#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")
});