Jest издевается, не регистрируясь как вызываемый в expect().toBeCalled() при вызове Mocks

#javascript #jestjs #mocking

#javascript #jestjs #издевательство

Вопрос:

Для рассматриваемых тестов я издевался над некоторыми обратными вызовами и передавал их функции, которую я тестирую. Я добавил консоль.войдите в издевательства, просто чтобы попытаться отладить происходящее. Эти консоли.журналы распечатываются в журнале тестирования, поэтому создается впечатление, что издевательские обратные вызовы на самом деле вызываются правильно во время теста (см. Вывод теста ниже), но когда я выполняю ожидание (mockedFunction).toBeCalled() это утверждение завершается ошибкой. Я не могу понять, почему это не удается, поскольку издевательские обратные вызовы выходят на консоль при запуске теста. Вот мой код:

это код, который я пытаюсь протестировать.

 import IAccount from './IAccount';
import IAccountManager from './IAccountManager';
import firebase from '../firebase/Firebase';
import { stringHasASymbol } from '../../common/Utility';

export class FirebaseAccountManager implements IAccountManager {

  register(newAccount: IAccount, successCallback: (response: any) => any, errorCallback: (error: any) => any): void {
    console.log("called: FirebaseAccountManager:register()");
    firebase.register(newAccount.email, newAccount.password, newAccount.firstName   " "   newAccount.lastName)
      .then(response => {
        console.log("GOT HERE 1", response)
        successCallback(true);
      })
      .catch(error => {
        console.log("GOT HERE 2", error)
        errorCallback({ code: this.convertRegisterErrorCode(error.code), message: error.message })
      });
  }

  private convertRegisterErrorCode(code: string): string {
    if (code === 'auth/email-already-in-use') {
      return 'email-already-in-use';
    }

    return 'unsupported-error-type: firebase error code = '   stringHasASymbol;
  }
}
  

Вот мой тест:

 import { FirebaseAccountManager } from './FirebaseAccountManager';
import IAccount from './IAccount';

jest.mock('firebase/app', () => (
  {
    auth: jest.fn().mockReturnThis(),
    initializeApp: jest.fn(),
    createUserWithEmailAndPassword: jest.fn()
      .mockResolvedValueOnce(true)
      .mockRejectedValueOnce({
        code: 'invalid-email'
      })
  }
));

const mockSuccessCallback = jest.fn((response: any) => {
  console.log("MOCK SUCCESS CALLBACK CALLED", response);
  return 'Success!';
});
const mockErrorCallback = jest.fn((error: any) => {
  console.log("MOCK ERROR CALLBACK CALLED", error);
  return { code: 'invalid-email', message: 'this email is already in use' }
});

afterEach(() => {
  jest.clearAllMocks();
});

describe('test', () => {
  test('Successful Registration', () => {
    console.log("START Successful Registration")
    const newAccount: IAccount = { firstName: 'asdf', lastName: 'asdf', email: 'asdf@adf.com', password: 'qwer', phoneNumber: '', workStatus: '', city: '', postalCode: '', country: '' }

    const fam = new FirebaseAccountManager();
    fam.register(newAccount, mockSuccessCallback, mockErrorCallback);
    console.log(mockSuccessCallback.mock.calls.length)
    expect(mockSuccessCallback).toBeCalled();
    expect(mockErrorCallback).not.toBeCalled();
    console.log("DONE Successful Registration")
  });

  test('Failed Registration', () => {
    console.log("START Failed Registration")
    const newAccount: IAccount = { firstName: 'asdf', lastName: 'asdf', email: 'asdf@adf.com', password: 'qwer', phoneNumber: '', workStatus: '', city: '', postalCode: '', country: '' }

    const fam = new FirebaseAccountManager();
    fam.register(newAccount, mockSuccessCallback, mockErrorCallback);
    expect(mockSuccessCallback).not.toBeCalled();
    expect(mockErrorCallback).toBeCalled();
    console.log("DONE Failed Registration")
  });

});
  

оба завершаются неудачей, даже если вызываются обратные вызовы. Вот результат теста:

  FAIL  src/middleware/Account/FirebaseAccountManager.test.ts
  test
    ✕ Successful Registration (7ms)
    ✕ Failed Registration (3ms)

  ● test › Successful Registration

    expect(jest.fn()).toBeCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      35 |     fam.register(newAccount, mockSuccessCallback, mockErrorCallback);
      36 |     console.log(mockSuccessCallback.mock.calls.length)
    > 37 |     expect(mockSuccessCallback).toBeCalled();
         |                                 ^
      38 |     expect(mockErrorCallback).not.toBeCalled();
      39 |     console.log("DONE Successful Registration")
      40 |   });

      at Object.<anonymous> (src/middleware/Account/FirebaseAccountManager.test.ts:37:33)

  ● test › Failed Registration

    expect(jest.fn()).toBeCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

      47 |     fam.register(newAccount, mockSuccessCallback, mockErrorCallback);
      48 |     expect(mockSuccessCallback).not.toBeCalled();
    > 49 |     expect(mockErrorCallback).toBeCalled();
         |                               ^
      50 |     console.log("DONE Failed Registration")
      51 |   });
      52 | 

      at Object.<anonymous> (src/middleware/Account/FirebaseAccountManager.test.ts:49:31)

  console.log src/middleware/Account/FirebaseAccountManager.test.ts:31
    START Successful Registration

  console.log src/middleware/Account/FirebaseAccountManager.ts:8
    called: FirebaseAccountManager:register()

  console.log src/middleware/Account/FirebaseAccountManager.test.ts:36
    0

  console.log src/middleware/Account/FirebaseAccountManager.ts:11
    GOT HERE 1 true

  console.log src/middleware/Account/FirebaseAccountManager.test.ts:17
    MOCK SUCCESS CALLBACK CALLED true

  console.log src/middleware/Account/FirebaseAccountManager.test.ts:43
    START Failed Registration

  console.log src/middleware/Account/FirebaseAccountManager.ts:8
    called: FirebaseAccountManager:register()

  console.log src/middleware/Account/FirebaseAccountManager.ts:15
    GOT HERE 2 { code: 'invalid-email' }

  console.log src/middleware/Account/FirebaseAccountManager.test.ts:21
    MOCK ERROR CALLBACK CALLED {
      code: 'unsupported-error-type: firebase error code = invalid-email',
      message: undefined
    }

Test Suites: 1 failed, 1 total
Tests:       2 failed, 2 total
Snapshots:   0 total
Time:        0.967s, estimated 1s
Ran all test suites matching /Fire/i.

Watch Usage: Press w to show more.

  

Скриншот результатов теста

Ответ №1:

Я решил это. Проблема заключалась в том, что функция register в FirebaseAccountManager обрабатывала обещание, но не была асинхронной. Как только я добавил асинхронность в функцию и ожидал ее в тесте, тесты прошли. Я думаю, что тест утверждал, что обратный вызов был вызван до того, как обещание разрешило или отклонило его. Обновленные примеры кода следующим образом:

   async register(newAccount: IAccount, successCallback: (response: any) => any, errorCallback: (error: any) => any): Promise<any> {
    console.log("called: FirebaseAccountManager:register()");
    await firebase.register(newAccount.email, newAccount.password, newAccount.firstName   " "   newAccount.lastName)
      .then(response => {
        console.log("GOT HERE 1", response)
        successCallback(true);
      })
      .catch(error => {
        console.log("GOT HERE 2", error)
        errorCallback({ code: this.convertRegisterErrorCode(error.code), message: error.message })
      });
  }
  

И вот измененные тесты, которые теперь проходят.

   test('Successful Registration', async () => {
    console.log("START Successful Registration")
    const newAccount: IAccount = { firstName: 'asdf', lastName: 'asdf', email: 'asdf@adf.com', password: 'qwer', phoneNumber: '', workStatus: '', city: '', postalCode: '', country: '' }

    const fam = new FirebaseAccountManager();
    await fam.register(newAccount, mockSuccessCallback, mockErrorCallback);
    expect(mockSuccessCallback).toBeCalled();
    expect(mockErrorCallback).not.toBeCalled();
    console.log("DONE Successful Registration")
  });

  test('Failed Registration', async () => {
    console.log("START Failed Registration")
    const newAccount: IAccount = { firstName: 'asdf', lastName: 'asdf', email: 'asdf@adf.com', password: 'qwer', phoneNumber: '', workStatus: '', city: '', postalCode: '', country: '' }

    const fam = new FirebaseAccountManager();
    await fam.register(newAccount, mockSuccessCallback, mockErrorCallback);
    expect(mockSuccessCallback).not.toBeCalled();
    expect(mockErrorCallback).toBeCalled();
    console.log("DONE Failed Registration")
  });