Reputation: 10329
I'm using a library called react-firebase-hooks in a component of mine.
// Component.tsx
import React, {useEffect} from 'react';
import { Firebase } from '../firebase/firebase';
import { useAuthState } from 'react-firebase-hooks/auth';
export const Component = () => {
// Note that Firebase.getAuth is a static method of a class of mine for getting the firebase authentication object
const [user, loading ] = useAuthState(Firebase.getAuth());
if (!loading && !user) {
// ... stuff
}
return (
<div>
...stuff
</div>
);
};
I'm trying to mock out the useAuthState
call in one of my tests and I'm having a lot of trouble figuring out the optimal way to perform the mock. I've found a solution that works:
// Component.test.tsx
import {useAuthState} from 'react-firebase-hooks/auth'
jest.mock('react-firebase-hooks/auth', () => ({
useAuthState: jest.fn()
}));
However, the above mocking implementation makes it impossible to get IDE completion for the mock objects. For example, here's me trying to set up a mock return value:
test(`component correctly loads`, () => {
useAuthState.mockReturnValue([true, false])
// renderApp is a utility method of mine to render using react-testing-library
const { getByText } = renderApp();
// expect some stuff
});
What I'm finding is that I don't get autocomplete on useAuthState
.
Ideally how I'd like to declare the mock would be something closer to
const mockAuth = jest.fn();
jest.mock('react-firebase-hooks/auth', () => {
return jest.fn().mockImplementation(() => {
return {useAuthState: mockAuth}
})
});
which would then let me alter the mockAuth
object nicely through the tests I declare (and get autocomplete), eg:
test(`component correctly loads`, () => {
mockAuth.mockReturnValue([true, false])
// renderApp is a utility method of mine to render using react-testing-library which renders Component
const { getByText } = renderApp();
// expect some stuff
});
However, with the above implementation, I get the following error: (0 , _auth.useAuthState) is not a function or its return value is not iterable
in Component
.
I've also tried declaring the mock as
const mockAuth = jest.fn();
jest.mock('react-firebase-hooks/auth', () => ({
useAuthState: mockAuth
}));
but that gives me an error of ReferenceError: Cannot access 'mockAuth' before initialization
.
I've also tried
const mockAuth = jest.fn();
import {useAuthState} from 'react-firebase-hooks/auth'
jest.mock('react-firebase-hooks/auth', () => ({
useAuthState: mockAuth
}));
but that gives the same error.
Is there a way for me to declare a mock function "outside" of the mock declaration so that I can get autocomplete for it?
Upvotes: 0
Views: 1551
Reputation: 1887
If you use another file for the mock, you should be golden to change the implementation and still preserve the TypeScript Intellisense.
src/App.test.jsx
import App from "../App";
import { render } from "@testing-library/react";
import { useAuthState } from "../__mocks__/react-firebase-hooks/auth";
it("should be mocked", () => {
// Change the implementation of the mock
useAuthState.mockReturnValue([true, false]);
const { getByText } = render(<App />);
// Expect that the app file got the mocked value
expect(useAuthState).toBeCalledWith("my auth");
expect(getByText("true,false")).toBeTruthy();
});
src/__mocks__/react-firebase-hooks/auth.js
export const useAuthState = jest.fn();
src/App.js
import { useAuthState } from "react-firebase-hooks/auth";
export default function App() {
const test = useAuthState("my auth");
return <div>{test.toString()}</div>;
}
Upvotes: 1