如何在Angular中模拟AWS Amplify库?

时间:2019-12-06 14:41:30

标签: angular typescript unit-testing mocking aws-amplify

当我使用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();
    });
  });

是否有一种方法可以从规范文件中覆盖此导入?

3 个答案:

答案 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函数外,该测试文件现在并没有做太多事情,但这应该可以帮助您。享受。