当我使用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放大工作正常
import { Auth } from 'aws-amplify';
//...
const promise = Auth.signIn(username, password);
我不明白如何模拟对Cognito的API访问。 通常,我通过依赖注入为构造函数提供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();
});
});
是否有一种方法可以从规范文件中覆盖此导入?
答案 0 :(得分:1)
您可以这样:
// 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));
service.getProfile.subscribe((prof) => expect(prof).toEqual(userProfile));
});
答案 1 :(得分:0)
我设法摆脱了错误。
您需要在测试文件和以下解决方案中所需的类型中导入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实例的行为。
答案 2 :(得分:0)
而不是将其直接导入到服务或Effects类中,而是将其导入到模块中并进行注入。假设您有一个AuthService
服务类来处理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()
})
});
除了确认您的服务/组件正在调用期望的Auth函数外,该测试文件现在并没有做太多事情,但这应该可以帮助您。享受。