Your tests have the following issues:
You should import SignOutButton component after replacing the Firebase.auth method with authMock. Otherwise, the Firebase.auth method is the original version rather than the mocked version. You can check using console.log(Firebase.auth).
You should return the same reference for the returned value of Firebase.auth method. Otherwise, the assertions will fail.
The complete unit test solution:
SignOutButton.tsx:
import React from 'react';
import Firebase from './firebase';
console.log(Firebase.auth);
console.log('should keep same reference to authObject:', Firebase.auth() === Firebase.auth());
const SignOutButton = () => (
<button type="button" onClick={() => Firebase.auth().signOut()}>
Sign Out
</button>
);
export default SignOutButton;
firebase.ts:
export default {
auth() {
console.log('auth real implementation');
return this;
},
async signOut() {
console.log('signOut real implementation');
},
};
setupTests.ts:
const authObjectMock = {
createUserAndRetrieveDataWithEmailAndPassword: jest.fn(() => Promise.resolve(true)),
sendPasswordResetEmail: jest.fn(() => Promise.resolve(true)),
signInAndRetrieveDataWithEmailAndPassword: jest.fn(() => Promise.resolve(true)),
fetchSignInMethodsForEmail: jest.fn(() => Promise.resolve(true)),
signOut: jest.fn(() => {
Promise.resolve(true);
}),
onAuthStateChanged: jest.fn(),
currentUser: {
sendEmailVerification: jest.fn(() => Promise.resolve(true)),
},
};
const authMock = jest.fn(() => authObjectMock);
export { authMock };
SignOutButton.test.tsx:
import React from 'react';
import { render, cleanup, fireEvent } from '@testing-library/react';
import Firebase from './firebase';
import { authMock } from './setupTests';
// @ts-ignore
Firebase.auth = authMock;
describe('<SignOutButton />', () => {
afterEach(cleanup);
it('calls Firebase signOut on click', async () => {
const SignOutButton = (await import('./SignOutButton')).default;
const { getByText } = render(<SignOutButton />);
const button = getByText('Sign Out');
fireEvent.click(button);
expect(Firebase.auth().signOut).toHaveBeenCalled();
});
});
unit test result with coverage report:
PASS src/stackoverflow/58562583/SignOutButton.test.tsx
<SignOutButton />
✓ calls Firebase signOut on click (76ms)
console.log src/stackoverflow/58562583/SignOutButton.tsx:382
{ [Function: mockConstructor]
_isMockFunction: true,
getMockImplementation: [Function],
mock: [Getter/Setter],
mockClear: [Function],
mockReset: [Function],
mockRestore: [Function],
mockReturnValueOnce: [Function],
mockResolvedValueOnce: [Function],
mockRejectedValueOnce: [Function],
mockReturnValue: [Function],
mockResolvedValue: [Function],
mockRejectedValue: [Function],
mockImplementationOnce: [Function],
mockImplementation: [Function],
mockReturnThis: [Function],
mockName: [Function],
getMockName: [Function] }
console.log src/stackoverflow/58562583/SignOutButton.tsx:386
should keep same reference to authObject: true
-------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-------------------|----------|----------|----------|----------|-------------------|
All files | 63.64 | 100 | 36.36 | 60 | |
SignOutButton.tsx | 100 | 100 | 100 | 100 | |
firebase.ts | 25 | 100 | 0 | 25 | 3,4,7 |
setupTests.ts | 50 | 100 | 28.57 | 44.44 | 2,3,4,5,11 |
-------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.943s