How to fix “Received number of calls: 0” when testing a class method?
- Main classes
class API {
someMethod() {
...
}
}
export default API;
class API {
someMethod() {
...
}
}
export default API;
class API { someMethod() { ... } } export default API;
import API from 'utils/API';
class Foo {
constructor() {
this.api = new API();
}
helloWorld() {
this.api.someMethod();
}
}
export default Foo;
import API from 'utils/API';
class Foo {
constructor() {
this.api = new API();
}
helloWorld() {
this.api.someMethod();
}
}
export default Foo;
import API from 'utils/API'; class Foo { constructor() { this.api = new API(); } helloWorld() { this.api.someMethod(); } } export default Foo;
- Failed test
describe( 'Foo', () => {
it ( 'should call someMethod', () => {
const foo = new Foo();
const api = new API();
jest.spyOn( api, 'someMethod' );
foo.helloWorld();
expect(api.someMethod).toHaveBeenCalledTimes(1);
});
});
describe( 'Foo', () => {
it ( 'should call someMethod', () => {
const foo = new Foo();
const api = new API();
jest.spyOn( api, 'someMethod' );
foo.helloWorld();
expect(api.someMethod).toHaveBeenCalledTimes(1);
});
});
describe( 'Foo', () => { it ( 'should call someMethod', () => { const foo = new Foo(); const api = new API(); jest.spyOn( api, 'someMethod' ); foo.helloWorld(); expect(api.someMethod).toHaveBeenCalledTimes(1); }); });
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
expect(jest.fn()).toHaveBeenCalledTimes(expected)
Expected number of calls: 1
Received number of calls: 0
expect(jest.fn()).toHaveBeenCalledTimes(expected) Expected number of calls: 1 Received number of calls: 0
- Correct test file
const mockSomeMethod = jest.fn(); // Make variables that start with the word mock
jest.mock( 'utils/API', () => { // Call jest.mock with module factory parameter
return jest.fn().mockImplementation(() => {
return {
someMethod: mockSomeMethod
};
});
});
describe( 'Foo', () => {
it ( 'should call greetWorld', () => {
const foo = new Foo();
const api = new API();
foo.helloWorld();
expect(api.greetWorld).toHaveBeenCalledTimes(1);
});
});
const mockSomeMethod = jest.fn(); // Make variables that start with the word mock
jest.mock( 'utils/API', () => { // Call jest.mock with module factory parameter
return jest.fn().mockImplementation(() => {
return {
someMethod: mockSomeMethod
};
});
});
describe( 'Foo', () => {
it ( 'should call greetWorld', () => {
const foo = new Foo();
const api = new API();
foo.helloWorld();
expect(api.greetWorld).toHaveBeenCalledTimes(1);
});
});
const mockSomeMethod = jest.fn(); // Make variables that start with the word mock jest.mock( 'utils/API', () => { // Call jest.mock with module factory parameter return jest.fn().mockImplementation(() => { return { someMethod: mockSomeMethod }; }); }); describe( 'Foo', () => { it ( 'should call greetWorld', () => { const foo = new Foo(); const api = new API(); foo.helloWorld(); expect(api.greetWorld).toHaveBeenCalledTimes(1); }); });
Ref: inner-functions-with-jest
How to mock a class to return a function instead of an object?
class API {
someMethod() {
...
}
}
export default API;
class API {
someMethod() {
...
}
}
export default API;
class API { someMethod() { ... } } export default API;
- If a class is mistakenly mocked as an “object” as opposed to a function, an object cannot be instantiated with a “new” operator.
This mock is incorrect because it returns an object:
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
// Returns an object
return {
someMethod: mockSomeMethod
};
})
// This will throw the error
const api = new API();
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
// Returns an object
return {
someMethod: mockSomeMethod
};
})
// This will throw the error
const api = new API();
import API from 'utils/API'; const mockSomeMethod = jest.fn() jest.mock('utils/API', () => { // Returns an object return { someMethod: mockSomeMethod }; }) // This will throw the error const api = new API();
- This mock is correct:
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
// Returns a function
return jest.fn().mockImplementation(() => ({
someMethod: mockSomeMethod
}));
})
// This will not throw an error anymore
const api = new API();
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
// Returns a function
return jest.fn().mockImplementation(() => ({
someMethod: mockSomeMethod
}));
})
// This will not throw an error anymore
const api = new API();
import API from 'utils/API'; const mockSomeMethod = jest.fn() jest.mock('utils/API', () => { // Returns a function return jest.fn().mockImplementation(() => ({ someMethod: mockSomeMethod })); }) // This will not throw an error anymore const api = new API();
How to mock a class which is exported as non-default?
The error you usually get for this case is “TypeError: _myClass.MyClass is not a constructor“
export class API {
someMethod() {
...
}
}
export class API {
someMethod() {
...
}
}
export class API { someMethod() { ... } }
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
return {
get API() {
return jest.fn().mockImplementation(() => ({
someMethod: mockSomeMethod
}));
}
}
})
const api = new API();
import API from 'utils/API';
const mockSomeMethod = jest.fn()
jest.mock('utils/API', () => {
return {
get API() {
return jest.fn().mockImplementation(() => ({
someMethod: mockSomeMethod
}));
}
}
})
const api = new API();
import API from 'utils/API'; const mockSomeMethod = jest.fn() jest.mock('utils/API', () => { return { get API() { return jest.fn().mockImplementation(() => ({ someMethod: mockSomeMethod })); } } }) const api = new API();
How to test async/ await?
export class API {
async fetchMethod() {
...
}
errroMethod() {
...
}
////////////////////////////////
////////////////////////////////
async someMethod() {
try {
await fetchMethod()
} catch(error) {
errorMethod()
}
}
}
export class API {
async fetchMethod() {
...
}
errroMethod() {
...
}
////////////////////////////////
////////////////////////////////
async someMethod() {
try {
await fetchMethod()
} catch(error) {
errorMethod()
}
}
}
export class API { async fetchMethod() { ... } errroMethod() { ... } //////////////////////////////// //////////////////////////////// async someMethod() { try { await fetchMethod() } catch(error) { errorMethod() } } }
import API from 'utils/API';
const api = new API();
const mockErrorMethod = jest.spyOn(api, 'errorMethod');
describe('API fecth works', () => {
jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.resolve());
it('calls fetchMethod, errorMethod is not called', async () => {
await api.someMethod;
expect(api.fetchMethod).toHaveBeenCalledTimes(1);
expect(mockErrorMethod).toHaveBeenCalledTimes(0);
});
})
describe('API fecth is down', () => {
jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.reject(error));
it('calls fetchMethod, errorMethod', async () => {
await api.someMethod;
expect(api.fetchMethod).toHaveBeenCalledTimes(1);
expect(mockErrorMethod).toHaveBeenCalledTimes(1);
});
})
import API from 'utils/API';
const api = new API();
const mockErrorMethod = jest.spyOn(api, 'errorMethod');
describe('API fecth works', () => {
jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.resolve());
it('calls fetchMethod, errorMethod is not called', async () => {
await api.someMethod;
expect(api.fetchMethod).toHaveBeenCalledTimes(1);
expect(mockErrorMethod).toHaveBeenCalledTimes(0);
});
})
describe('API fecth is down', () => {
jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.reject(error));
it('calls fetchMethod, errorMethod', async () => {
await api.someMethod;
expect(api.fetchMethod).toHaveBeenCalledTimes(1);
expect(mockErrorMethod).toHaveBeenCalledTimes(1);
});
})
import API from 'utils/API'; const api = new API(); const mockErrorMethod = jest.spyOn(api, 'errorMethod'); describe('API fecth works', () => { jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.resolve()); it('calls fetchMethod, errorMethod is not called', async () => { await api.someMethod; expect(api.fetchMethod).toHaveBeenCalledTimes(1); expect(mockErrorMethod).toHaveBeenCalledTimes(0); }); }) describe('API fecth is down', () => { jest.spyOn(api, 'fetchMethod').mockReturnValue(Promise.reject(error)); it('calls fetchMethod, errorMethod', async () => { await api.someMethod; expect(api.fetchMethod).toHaveBeenCalledTimes(1); expect(mockErrorMethod).toHaveBeenCalledTimes(1); }); })
How to test a component with a custom hook
// click-a-button.tsx
import {useClickAButton} from "./hooks/index";
export const ClickAButton = () => {
const { handleClick, total } = useClickAButton();
return <button onClick={handleClick}>{total}</button>;
}
// click-a-button.tsx
import {useClickAButton} from "./hooks/index";
export const ClickAButton = () => {
const { handleClick, total } = useClickAButton();
return <button onClick={handleClick}>{total}</button>;
}
// click-a-button.tsx import {useClickAButton} from "./hooks/index"; export const ClickAButton = () => { const { handleClick, total } = useClickAButton(); return <button onClick={handleClick}>{total}</button>; }
// hooks/use-click-a-button.tsx
import React, {useCallback, useState} from 'react';
export const useClickAButton = () => {
const [total, setTotal] = useState<number>(0);
const handleClick = useCallback(() => {
setTotal(total => total + 1);
}, []);
return {
handleClick,
total,
};
}
// hooks/use-click-a-button.tsx
import React, {useCallback, useState} from 'react';
export const useClickAButton = () => {
const [total, setTotal] = useState<number>(0);
const handleClick = useCallback(() => {
setTotal(total => total + 1);
}, []);
return {
handleClick,
total,
};
}
// hooks/use-click-a-button.tsx import React, {useCallback, useState} from 'react'; export const useClickAButton = () => { const [total, setTotal] = useState<number>(0); const handleClick = useCallback(() => { setTotal(total => total + 1); }, []); return { handleClick, total, }; }
// click-a-button.test.tsx
import * as React from 'react';
import {act} from "react-dom/test-utils";
import {render} from "@testing-library/react";
import {useClickAButton} from './hooks/index'
import {ClickAButton} from "./index";
jest.mock('./hooks') // This is important
const hooks = { useClickAButton }
const mockUseClickAButton = jest.spyOn(hooks, 'useClickAButton');
const mockHandleClick = jest.fn();
mockUseClickAButton.mockReturnValue({
handleClick: mockHandleClick,
total: 5,
});
test('it runs with a mocked customHook',() => {
const component = render(<ClickAButton />);
expect(component.container).toHaveTextContent('5');
act(() => {
component.container.click();
});
expect(mockHandleClick).toHaveBeenCalled();
})
// click-a-button.test.tsx
import * as React from 'react';
import {act} from "react-dom/test-utils";
import {render} from "@testing-library/react";
import {useClickAButton} from './hooks/index'
import {ClickAButton} from "./index";
jest.mock('./hooks') // This is important
const hooks = { useClickAButton }
const mockUseClickAButton = jest.spyOn(hooks, 'useClickAButton');
const mockHandleClick = jest.fn();
mockUseClickAButton.mockReturnValue({
handleClick: mockHandleClick,
total: 5,
});
test('it runs with a mocked customHook',() => {
const component = render(<ClickAButton />);
expect(component.container).toHaveTextContent('5');
act(() => {
component.container.click();
});
expect(mockHandleClick).toHaveBeenCalled();
})
// click-a-button.test.tsx import * as React from 'react'; import {act} from "react-dom/test-utils"; import {render} from "@testing-library/react"; import {useClickAButton} from './hooks/index' import {ClickAButton} from "./index"; jest.mock('./hooks') // This is important const hooks = { useClickAButton } const mockUseClickAButton = jest.spyOn(hooks, 'useClickAButton'); const mockHandleClick = jest.fn(); mockUseClickAButton.mockReturnValue({ handleClick: mockHandleClick, total: 5, }); test('it runs with a mocked customHook',() => { const component = render(<ClickAButton />); expect(component.container).toHaveTextContent('5'); act(() => { component.container.click(); }); expect(mockHandleClick).toHaveBeenCalled(); })
How to mock a hook?
// navigation.ts
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef();
...
// navigation.ts
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef();
...
// navigation.ts import { createNavigationContainerRef } from '@react-navigation/native'; export const navigationRef = createNavigationContainerRef(); ...
Error when running the test file
TypeError: (0 , _native.createNavigationContainerRef) is not a function
TypeError: (0 , _native.createNavigationContainerRef) is not a function
TypeError: (0 , _native.createNavigationContainerRef) is not a function
// Test file
const mockNavigation = jest.fn();
jest.mock('@react-navigation/native', () => ({
...jest.requireActual('@react-navigation/native'),
createNavigationContainerRef: () => {
return mockNavigation;
},
useNavigation: () => {
return mockNavigation;
}
}))
// Test file
const mockNavigation = jest.fn();
jest.mock('@react-navigation/native', () => ({
...jest.requireActual('@react-navigation/native'),
createNavigationContainerRef: () => {
return mockNavigation;
},
useNavigation: () => {
return mockNavigation;
}
}))
// Test file const mockNavigation = jest.fn(); jest.mock('@react-navigation/native', () => ({ ...jest.requireActual('@react-navigation/native'), createNavigationContainerRef: () => { return mockNavigation; }, useNavigation: () => { return mockNavigation; } }))
How to test a button press and fire an event?
// MyComponent.tsx
...
return
<MyButton
// Setup testID
testID={constants.testId.myButton}
// onPress action
onPress={() => navigateToSomewhere(link)}
/>
...
// MyComponent.tsx
...
return
<MyButton
// Setup testID
testID={constants.testId.myButton}
// onPress action
onPress={() => navigateToSomewhere(link)}
/>
...
// MyComponent.tsx ... return <MyButton // Setup testID testID={constants.testId.myButton} // onPress action onPress={() => navigateToSomewhere(link)} /> ...
// Test file
// Mock action
const mockAction = jest.spyOn(anObject, 'navigateToSomewhere').mockImplementation();
// Get button view by id
const { getByTestId } = render(<MyComponent />);
const button = getByTestId(constants.testId.myButton);
await waitFor(() => expect(button).toBeTruthy());
// Perform press action
fireEvent.press(button);
// Test result
expect(mockAction).toBeCalled();
// Test file
// Mock action
const mockAction = jest.spyOn(anObject, 'navigateToSomewhere').mockImplementation();
// Get button view by id
const { getByTestId } = render(<MyComponent />);
const button = getByTestId(constants.testId.myButton);
await waitFor(() => expect(button).toBeTruthy());
// Perform press action
fireEvent.press(button);
// Test result
expect(mockAction).toBeCalled();
// Test file // Mock action const mockAction = jest.spyOn(anObject, 'navigateToSomewhere').mockImplementation(); // Get button view by id const { getByTestId } = render(<MyComponent />); const button = getByTestId(constants.testId.myButton); await waitFor(() => expect(button).toBeTruthy()); // Perform press action fireEvent.press(button); // Test result expect(mockAction).toBeCalled();
How to test an API request using Axios?
// index.tsx
export const getUserProfile = async () => {
try {
const response = await axios.get(userProfileUrl)
return response.data;
} catch (error) {
throw error;
}
}
// index.tsx
export const getUserProfile = async () => {
try {
const response = await axios.get(userProfileUrl)
return response.data;
} catch (error) {
throw error;
}
}
// index.tsx export const getUserProfile = async () => { try { const response = await axios.get(userProfileUrl) return response.data; } catch (error) { throw error; } }
import axios from 'axios';
// Mock axios
jest.mock('axios');
const mockAxios = axios as jest.Mocked<typeof axios>;
describe('fetch user profile sucessfully', () => {
it('should return user profile', async () => {
// Mock return value
mockAxios.get.mockResolvedValue(mockData);
// Perform axios request
await getUserProfile();
// Result
expect(axios.get).toHaveBeenCalledWith(`${userProfileUrl}`)
})
})
import axios from 'axios';
// Mock axios
jest.mock('axios');
const mockAxios = axios as jest.Mocked<typeof axios>;
describe('fetch user profile sucessfully', () => {
it('should return user profile', async () => {
// Mock return value
mockAxios.get.mockResolvedValue(mockData);
// Perform axios request
await getUserProfile();
// Result
expect(axios.get).toHaveBeenCalledWith(`${userProfileUrl}`)
})
})
import axios from 'axios'; // Mock axios jest.mock('axios'); const mockAxios = axios as jest.Mocked<typeof axios>; describe('fetch user profile sucessfully', () => { it('should return user profile', async () => { // Mock return value mockAxios.get.mockResolvedValue(mockData); // Perform axios request await getUserProfile(); // Result expect(axios.get).toHaveBeenCalledWith(`${userProfileUrl}`) }) })
How to test if an element is displayed?
const { getByTestId, toJSON } = render(<MyComponent />);
// Snapshot
expect(toJSON()).toMatchSnapshot();
// Get element by Id
const button = getByTestId(testId.button.login);
expect(button).toBeTruthy();
const { getByTestId, toJSON } = render(<MyComponent />);
// Snapshot
expect(toJSON()).toMatchSnapshot();
// Get element by Id
const button = getByTestId(testId.button.login);
expect(button).toBeTruthy();
const { getByTestId, toJSON } = render(<MyComponent />); // Snapshot expect(toJSON()).toMatchSnapshot(); // Get element by Id const button = getByTestId(testId.button.login); expect(button).toBeTruthy();
Leave a Reply