如何在 Angular 中模拟 AWS Amplify 库?
How to mock AWS Amplify library in Angular?
当我 运行 使用 Karma 进行测试套件时,我收到一个似乎来自 AWS Amplify 的错误。
AuthEffects
login
√ should not dispatch any action
√ should call setItem on LocalStorageService
Chrome 78.0.3904 (Windows 10.0.0) ERROR
An error was thrown in afterAll
Uncaught TypeError: Cannot read property 'clientMetadata' of undefined thrown
据我推测,这个错误是从上次启动的测试中抛出的:AuthEffects
在我的 AuthEffects 中,我必须这样做才能使 AWS amplify 正常工作
import { Auth } from 'aws-amplify';
//...
const promise = Auth.signIn(username, password);
我不明白如何模拟 API 对 Cognito 的访问。
通常,我通过依赖注入为构造函数提供 Mock 服务,以避免真正连接到 API。这里是直接在组件中导入的。
规格文件:
describe('login', () => {
it('should not dispatch any action', () => {
const actions = new Actions(EMPTY);
const effect = new AuthEffects(
//...
);
const metadata = getEffectsMetadata(effect);
expect(metadata.login).toEqual({ dispatch: false });
});
it('should call setItem on LocalStorageService', () => {
const loginAction = new ActionAuthLogin('test', 'Test1234!');
const source = cold('a', { a: loginAction });
const actions = new Actions(source);
const effect = new AuthEffects(
//...
);
effect.login.subscribe(() => {
expect(localStorageService.setItem).toHaveBeenCalledWith(AUTH_KEY, {
isAuthenticated: true
});
});
});
afterAll(() => {
TestBed.resetTestingModule();
});
});
有没有办法从规范文件中覆盖此导入?
我设法摆脱了错误。
您需要在测试文件中导入 Auth 以及以下解决方案中需要的类型。
import { Auth } from 'aws-amplify';
import { ClientMetaData, SignInOpts } from '@aws-amplify/auth/src/types/Auth';
现在重新定义Auth的signIn方法即可解决问题:
describe('AuthEffects', () => {
//...
Auth.signIn = (
usernameOrSignInOpts: string | SignInOpts,
pw?: string,
clientMetadata: ClientMetaData = this._config.clientMetadata
) => of({}).toPromise();
//...
您需要按照方法的签名来覆盖它。
public signIn(
usernameOrSignInOpts: string | SignInOpts,
pw?: string,
clientMetadata: ClientMetaData = this._config.clientMetadata
): Promise<CognitoUser | any>
我不知道这是否是执行它的最佳(更清洁)解决方案,但我设法消除了错误并控制了 Auth 实例的行为。
与其将其直接导入您的服务或效果 class,不如将其导入您的模块并注入。假设您有一个 AuthService
服务 class 处理 AWS Amplify 的 Auth。
在你对应的模块中:
import Auth, { AuthClass } from '@aws-amplify/auth';
...
providers: [
AuthService,
{ provide: AuthClass, useValue: Auth }
]
在您的组件或服务中,像任何其他依赖项一样简单地注入它:
constructor(
private auth: AuthClass
) {
auth.signIn('abc', 'def')
}
最后,在您的规范文件中模拟它并使用间谍:
describe('AuthService', () => {
let service: AuthService;
let authSpy: jasmine.SpyObj<AuthClass>
let authSpyObj = {
signIn: () => new Promise<any>(() => true),
signOut: () => new Promise<any>(() => true),
signUp: () => new Promise<any>(() => true),
confirmSignUp: () => new Promise<any>(() => true),
resendSignUp: () => new Promise<any>(() => true),
}
beforeEach(() => {
const spyAuth = jasmine.createSpyObj('auth', authSpyObj);
TestBed.configureTestingModule({
providers: [
AuthService,
{ provide: AuthClass, useValue: spyAuth },
]
})
service = TestBed.inject(AuthService)
authSpy = TestBed.inject(AuthClass) as jasmine.SpyObj<AuthClass>
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should have called signIn', () => {
service.signIn('a@b.c', '12345678')
expect(authSpy.signIn).toHaveBeenCalled()
})
});
除了确认您的 service/component 正在调用 expect Auth 函数外,该测试文件现在没有做太多事情,但这应该让您离开地面。享受吧。
你可以这样做:
// service with Auth
import { Injectable } from '@angular/core';
import Auth, { CognitoUser } from '@aws-amplify/auth';
...
private getProfile(): void {
return from(Auth.currentUserInfo());
}
// service.spec.ts
it('should set user and user profile', async () => {
const userProfile = { profile: 'userProfile' } as any;
Auth.currentUserInfo = jasmine.createSpy().and.callFake(() => Promise.resolve(userProfile));
const resp = await service.getProfile.toPromise();
expect(resp).toEqual(userProfile)
});
当我 运行 使用 Karma 进行测试套件时,我收到一个似乎来自 AWS Amplify 的错误。
AuthEffects
login
√ should not dispatch any action
√ should call setItem on LocalStorageService
Chrome 78.0.3904 (Windows 10.0.0) ERROR
An error was thrown in afterAll
Uncaught TypeError: Cannot read property 'clientMetadata' of undefined thrown
据我推测,这个错误是从上次启动的测试中抛出的:AuthEffects
在我的 AuthEffects 中,我必须这样做才能使 AWS amplify 正常工作
import { Auth } from 'aws-amplify';
//...
const promise = Auth.signIn(username, password);
我不明白如何模拟 API 对 Cognito 的访问。 通常,我通过依赖注入为构造函数提供 Mock 服务,以避免真正连接到 API。这里是直接在组件中导入的。
规格文件:
describe('login', () => {
it('should not dispatch any action', () => {
const actions = new Actions(EMPTY);
const effect = new AuthEffects(
//...
);
const metadata = getEffectsMetadata(effect);
expect(metadata.login).toEqual({ dispatch: false });
});
it('should call setItem on LocalStorageService', () => {
const loginAction = new ActionAuthLogin('test', 'Test1234!');
const source = cold('a', { a: loginAction });
const actions = new Actions(source);
const effect = new AuthEffects(
//...
);
effect.login.subscribe(() => {
expect(localStorageService.setItem).toHaveBeenCalledWith(AUTH_KEY, {
isAuthenticated: true
});
});
});
afterAll(() => {
TestBed.resetTestingModule();
});
});
有没有办法从规范文件中覆盖此导入?
我设法摆脱了错误。
您需要在测试文件中导入 Auth 以及以下解决方案中需要的类型。
import { Auth } from 'aws-amplify';
import { ClientMetaData, SignInOpts } from '@aws-amplify/auth/src/types/Auth';
现在重新定义Auth的signIn方法即可解决问题:
describe('AuthEffects', () => {
//...
Auth.signIn = (
usernameOrSignInOpts: string | SignInOpts,
pw?: string,
clientMetadata: ClientMetaData = this._config.clientMetadata
) => of({}).toPromise();
//...
您需要按照方法的签名来覆盖它。
public signIn(
usernameOrSignInOpts: string | SignInOpts,
pw?: string,
clientMetadata: ClientMetaData = this._config.clientMetadata
): Promise<CognitoUser | any>
我不知道这是否是执行它的最佳(更清洁)解决方案,但我设法消除了错误并控制了 Auth 实例的行为。
与其将其直接导入您的服务或效果 class,不如将其导入您的模块并注入。假设您有一个 AuthService
服务 class 处理 AWS Amplify 的 Auth。
在你对应的模块中:
import Auth, { AuthClass } from '@aws-amplify/auth';
...
providers: [
AuthService,
{ provide: AuthClass, useValue: Auth }
]
在您的组件或服务中,像任何其他依赖项一样简单地注入它:
constructor(
private auth: AuthClass
) {
auth.signIn('abc', 'def')
}
最后,在您的规范文件中模拟它并使用间谍:
describe('AuthService', () => {
let service: AuthService;
let authSpy: jasmine.SpyObj<AuthClass>
let authSpyObj = {
signIn: () => new Promise<any>(() => true),
signOut: () => new Promise<any>(() => true),
signUp: () => new Promise<any>(() => true),
confirmSignUp: () => new Promise<any>(() => true),
resendSignUp: () => new Promise<any>(() => true),
}
beforeEach(() => {
const spyAuth = jasmine.createSpyObj('auth', authSpyObj);
TestBed.configureTestingModule({
providers: [
AuthService,
{ provide: AuthClass, useValue: spyAuth },
]
})
service = TestBed.inject(AuthService)
authSpy = TestBed.inject(AuthClass) as jasmine.SpyObj<AuthClass>
});
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should have called signIn', () => {
service.signIn('a@b.c', '12345678')
expect(authSpy.signIn).toHaveBeenCalled()
})
});
除了确认您的 service/component 正在调用 expect Auth 函数外,该测试文件现在没有做太多事情,但这应该让您离开地面。享受吧。
你可以这样做:
// service with Auth
import { Injectable } from '@angular/core';
import Auth, { CognitoUser } from '@aws-amplify/auth';
...
private getProfile(): void {
return from(Auth.currentUserInfo());
}
// service.spec.ts
it('should set user and user profile', async () => {
const userProfile = { profile: 'userProfile' } as any;
Auth.currentUserInfo = jasmine.createSpy().and.callFake(() => Promise.resolve(userProfile));
const resp = await service.getProfile.toPromise();
expect(resp).toEqual(userProfile)
});