-1

I'm trying to test a custom hook, that fetches some token from the API. The ../api is my own module. Both files are in the same directory

// useTokenHook.tsx
import { getToken } from '../api';

const someVariable = useSelector();
useEffect(() => {
  const asyncWrapper = async () => {
    const token = await getToken()
    // do some stuff with token
  }
  asyncWrapper();
}, [someVariable]);

I'm trying to test it using jest and RTL

// useTokenHook.test.tsx
const getTokenMock = jest.fn();

jest.mock('../api', () => ({
  getToken: () => getTokenMock,
}));

describe('x', () => {
  it('should work', () => {
    renderHook(() => { useTokenHook(); },{ wrapper });

    expect(getTokenMock).toBeCalledTimes(1);
  });
});

I get the error:

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

Without the mock, I can see that the original getToken method gets called. I would assume the mock should also be called, but at least jest doesn't say so. I tried adding async to it() callback but the result is the same

AR2R
  • 166
  • 2
  • 16
  • 1
    Try to apply the approach suggested here https://stackoverflow.com/questions/55921228/jest-mock-function-that-is-imported-from-another-file – RAllen May 26 '23 at 22:42

2 Answers2

1

Try to use the following approach. Notice that there is no wrapper around getToken call. The code is obviously not tested but the concept should work.

// useTokenHook.tsx
import { getToken } from '../api';

const someVariable = useSelector();
useEffect(async () => {
    const token = await getToken()
    // do some stuff with token
}, [someVariable]);

And then the test:

// useTokenHook.test.tsx
import * as api from '../api';

jest.mock("../api");
api.getToken = jest.fn().mockImplementation(() => {
 return "the token";
});

describe('x', () => {
  it('should work', () => {
    renderHook(() => { useTokenHook(); },{ wrapper });

    expect(api.getToken).toBeCalledTimes(1);
  });
});
RAllen
  • 1,235
  • 1
  • 7
  • 10
  • 1
    This solution causes TS error `cannot assign to 'getAuthToken' because it is a read-only property`, but it pointed me in the right direction regarding the import statement. Thank you – AR2R May 27 '23 at 09:37
1

Based on RAllen answer I came up with the following:

// useTokenHook.test.tsx
import * as api from '../api';

jest.mock("../api");

describe('x', () => {
  it('should work', () => {
    const getTokenSpy = jest.spyOn(api, 'getToken')

    renderHook(() => { useTokenHook(); },{ wrapper });

    expect(getTokenSpy).toBeCalledTimes(1);
  });
});

Which solves my problem

AR2R
  • 166
  • 2
  • 16