问题
This is the function under test:
import * as firebase from 'firebase';
function signInWithGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithRedirect(provider);
}
firebase has below type definition:
declare namespace firebase.auth
and
function auth(app?: firebase.app.App): firebase.auth.Auth;
jest.mock('firebase', () => {
// Don't know how to mock, what should be returned?
})
I need mock firebase.auth.GoogleAuthProvider()
, firebase.auth()
and signInWithRedirect
methods of firebase.
But the firebase.auth
can be an object or a function. What should be returned in the factory
of jest.mock
?
Does jestjs support this kind of mock or spy? Thanks guys.
回答1:
Javascript functions are objects of type Function. And to every object you can assign properties so you can mock it as:
jest.mock('firebase', () => {
const auth = jest.fn();
auth.GoogleAuthProvider = jest.fn();
auth.Auth = jest.fn();
return { auth };
});
or you can use Jest's auto-mocking without factory function:
jest.mock('firebase');
and then mock the implementation
// based on your question (not tested)
firebase.auth.mockImplementation(() => new firebase.auth.Auth())
回答2:
From @Teneff's answer, I figure it out. The point is like @Teneff said, typescript namespace is some kind of a JS function after compiling and type erasure. After knowing this, of course, you can assign properties to JS function. Here is the completed working code example:
index.ts
:
import firebase from 'firebase';
export function signInWithgoogle() {
const provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithRedirect(provider);
}
For simple, I add @ts-ignore
comment in order to ignore the type check.
index.spec.ts
:
import { signInWithgoogle } from './';
import firebase from 'firebase';
jest.mock('firebase', () => {
const auth = jest.fn();
const mAuth = { signInWithRedirect: jest.fn() };
// @ts-ignore
auth.GoogleAuthProvider = jest.fn();
// @ts-ignore
auth.Auth = jest.fn(() => mAuth);
return { auth };
});
describe('signInWithgoogle', () => {
it('should mock firebase with typescript namespace', () => {
// @ts-ignore
firebase.auth.mockImplementation(() => new firebase.auth.Auth());
signInWithgoogle();
expect(firebase.auth.GoogleAuthProvider).toBeCalledTimes(1);
expect(firebase.auth).toBeCalledTimes(1);
expect(firebase.auth().signInWithRedirect).toBeCalledTimes(1);
});
});
Unit test result:
PASS src/mock-ts-namespace/index.spec.ts
signInWithgoogle
✓ should mock firebase with typescript namespace (7ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.964s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/mock-ts-namespace
来源:https://stackoverflow.com/questions/58873758/how-to-mock-a-module-with-typescript-namespace