How to test the function in function component by jest - javascript

I am trying to test the function in React component.
My simple component.
const TestFunction = (props) =>{
const testFunc = () => {
console.log("test");
return "test";
};
return (<div>test</div>)
}
export default TestFunction
and test script is like this below
import renderer from 'react-test-renderer';
import TestFunction from './TestFunction';
import {render, fireEvent, waitFor, screen} from '#testing-library/react'
import '#testing-library/jest-dom'
it('check the TestFunction', async() => {
render(<TestFunction/>)
expect(testFunc()).toBe("test");
});
However it shows error like this.
How can I test the function in function component?
$npm run dev
ReferenceError: testFunc is not defined
14 |
> 15 | expect(testFunc()).toBe("test");
| ^

If you want to assert the value during the rendering of the TestFunction component, you need to call the testFunc function inside the TestFunction component

Related

use jest mockImplementation to mock customized hook in typescript

I have one component that that use one customized hook and I need to write some test and make sure I mock the hook. How can I mock the customized hook to have unit test for my component like the code of hook does not even exist?
import "./styles.css";
import useAPICall from "#src/hooks/useAPICall ";
export default function App() {
const { onAPICall } = useAPICall(123);
const handleOnClick = useCallback(() => {
onAPICall();
});
return (
<div className="App">
<button onClick={handleOnClick}>Click</button>
</div>
);
}
///test.tsx all I know is this. but I am not sure how I can use mockImplementation that does not return anything
jest.mock('#src/hooks/useAPICall', () => ({
onAPICall: () => jest.fn(),
}));
You can do it in three simple steps:
Import the module which you want to mock
Then mock the module
Provide the return value of the mocked module.
import React from 'react';
import { render } from '#testing-library/react';
import userEvent from '#testing-library/user-event';
import App from './App';
import useAPICall from "#src/hooks/useAPICall "; // 1st step
jest.mock('#src/hooks/useAPICall'); //2nd step
test('can call useAPICall hook', () => {
useAPICall.mockReturnValue({ onAPICall: jest.fn() }); // 3rd step
const { getByRole } = render(<NewApp />);
userEvent.click(getByRole('button'));
expect(useAPICall).toBeCalled();
});

Mock a function called in a React component with jest

I have a React component which calls an external API. I'm try to unit test this component, but I didn't understand how I can mock the function with jest and "fake" the result.
Component:
import { getWeather } from '../../service/WeatherService'
import {useState, useEffect} from 'react'
export default function Weather() {
...
useEffect(() => {
getWeather().then((res) => { // function which calls the external API
...
}
See https://stackoverflow.com/a/43090261/5798347
You can mock the function like below, which will change the implementation of this function that will be used when you run your tests:
jest.mock('../../service/WeatherService', () => ({
getWeather: jest.fn() /* Insert Mock Implementation here */
}))

Mocking simple internal function using Jest for use in rendered React component

I have a simple React application with the following App.js, App.test.js, and utils.js files:
App.js
import React from 'react';
import { randomNameGenerator } from './utils.js';
import './App.css';
function App() {
return (
<div>
{randomNameGenerator()}
</div>
);
}
export default App;
App.test.js
import React from 'react';
import { render } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect'
import App from './App';
it('allows Jest method mocking', () => {
const { getByText } = render(<App />);
expect(getByText("Craig")).toBeInTheDocument()
});
utils.js
export function randomNameGenerator() {
return Math.floor((Math.random() * 2) + 1) == 1 ? 'Steve' : 'Bill';
}
This is a simple example, but what I'm trying to accomplish is a Jest mock of the randomNameGenerator() function to only return "Craig" for that specific Jest test.
I've followed a wide variety of tutorials/guides, but can't find anything that works - the closest (by "feel") that I've gotten was this (in App.test.js), which had no effect:
jest.doMock('./utils', () => {
const originalUtils = jest.requireActual('./utils');
return {
__esModule: true,
...originalUtils,
randomNameGenerator: jest.fn(() => {
console.log('## Returning mocked typing duration!');
return 'Craig';
}),
};
})
The way it fails is expected:
Unable to find an element with the text: Craig. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.
<body>
<div>
<div>
Steve
</div>
</div>
</body>
6 | it('allows Jest method mocking', () => {
7 | const { getByText } = render(<App />);
> 8 | expect(getByText("Craig")).toBeInTheDocument()
| ^
9 | });
You can mock the module by calling jest.mock, and then import it, then inside your tests you call mockImplementation to setup the right return value.
import React from 'react';
import { render } from '#testing-library/react';
import '#testing-library/jest-dom/extend-expect'
import App from './App';
import { randomNameGenerator } from "./utils";
jest.mock('./utils.js', () => ({
randomNameGenerator: jest.fn()
}));
describe('test', () => {
it('allows Jest method mocking 1', () => {
randomNameGenerator.mockImplementation(() => "Craig");
const { getByText } = render(<App />);
expect(getByText("Craig")).toBeInTheDocument()
});
it('allows Jest method mocking 2', () => {
randomNameGenerator.mockImplementation(() => "Not Craig");
const { getByText } = render(<App />);
expect(getByText("Not Craig")).toBeInTheDocument()
});
});

Mocking out React.Suspense Whilst Leaving the Rest of React Intact

I'm trying to write a Jest unit test for a component that uses React.Suspense.
Simplified versions of my component modules under test:
MyComponent.js
import React from 'react';
export default () => <h1>Tadaa!!!</h1>;
MySuspendedComponent.js
import React, { Suspense } from 'react';
import MyComponent from './MyComponent';
export default () => (
<Suspense fallback={<div>Loading…</div>}>
<MyComponent />
</Suspense>
);
Naïvely, in my first attempt, I wrote a unit test that uses Enzyme to mount the suspended component:
MySuspendedComponent.test.js
import React from 'react';
import { mount } from 'enzyme';
import MySuspendedComponent from './MySuspendedComponent';
test('the suspended component renders correctly', () => {
const wrapper = mount(<MySuspendedComponent />);
expect(wrapper.html()).toMatchSnapshot();
});
This causes the test to crash with the error message:
Error: Enzyme Internal Error: unknown node with tag 13
Searching for the error message on the web, I found that this is most likely caused by Enzyme not being ready to render Suspense (yet).
If I use shallow instead of mount, the error message changes to:
Invariant Violation: ReactDOMServer does not yet support Suspense
My next attempt was to mock out Suspense with a dummy pass-through component, like this:
MySuspendedComponent.test.js
import React from 'react';
import { mount } from 'enzyme';
import MySuspendedComponent from './MySuspendedComponent';
jest.mock('react', () => {
const react = require.requireActual('react');
return () => ({
...react,
Suspense({ children }) {
return children;
}
});
});
test('the suspended component renders correctly', () => {
const wrapper = mount(<MySuspendedComponent />);
expect(wrapper.html()).toMatchSnapshot();
});
The idea is to have a mock implementation of the React module that contains all the actual code from the React library, with only Suspense being replaced by a mock function.
I've used this pattern with requireActual, as described in the Jest documentation, successfully in other unit tests when mocking other modules than React, but with React, it does not work.
The error I get now is:
TypeError: (($_$w(...) , react) || ($$w(...) , _load_react(...))).default.createElement is not a function
…which, I assume, is caused by the original implementation of React not being available after my mocking trick.
How can I mock out Suspense while leaving the rest of the React library intact?
Or is there another, better way to test suspended components?
The solution is not to use object spreading to export the original React module, but simply overwriting the Suspense property, like this:
MySuspendedComponent.test.js
import React from 'react';
import { mount } from 'enzyme';
import MySuspendedComponent from './MySuspendedComponent';
jest.mock('react', () => {
const React = jest.requireActual('react');
React.Suspense = ({ children }) => children;
return React;
});
test('the suspended component renders correctly', () => {
const wrapper = mount(<MySuspendedComponent />);
expect(wrapper.html()).toMatchSnapshot();
});
This creates the following snapshot, as expected:
MySuspendedComponent.test.js.snap
exports[`the suspended component renders correctly 1`] = `"<h1>Tadaa!!!</h1>"`;
I needed to test my lazy component using Enzyme. Following approach worked for me to test on component loading completion:
const myComponent = React.lazy(() =>
import('#material-ui/icons')
.then(module => ({
default: module.KeyboardArrowRight
})
)
);
Test Code ->
//mock actual component inside suspense
jest.mock("#material-ui/icons", () => {
return {
KeyboardArrowRight: () => "KeyboardArrowRight",
}
});
const lazyComponent = mount(<Suspense fallback={<div>Loading...</div>}>
{<myComponent>}
</Suspense>);
const componentToTestLoaded = await componentToTest.type._result; // to get actual component in suspense
expect(componentToTestLoaded.text())`.toEqual("KeyboardArrowRight");
This is hacky but working well for Enzyme library.

React-Native Jest test function is called in componentDidMount

I'm trying to test if a function is called in the componentDidMount hook of my component.
I use React-Native and Jest to test my component.
The component looks like this:
const tracker = new GoogleAnalyticsTracker('UA-79731-33');
class MyComponent extends Component {
componentDidMount() {
tracker.trackScreenView(this.props.title);
}
}
So I'm mocking the GoogleAnalyticsTracker, it looks okay. Although I'm not sure how I can test that it has been called in the componentDidMount hook.
This is my test, which doesn't work:
import 'react-native';
import React from 'react';
import renderer from 'react-test-renderer';
import { GoogleAnalyticsTracker } from 'react-native-google-analytics-bridge';
import MyComponent from '../';
jest.mock('react-native-google-analytics-bridge');
const tracker = new GoogleAnalyticsTracker('ABC-123');
describe('MyComponent', () => {
it('renders', () => {
const tree = renderer.create(
<MyComponent />,
).toJSON();
expect(tree).toMatchSnapshot();
expect(tracker.trackScreenView).toBeCalled();
});
});
The toBeCalled() returns false.
How can I test that my function has been called in the componentDidMount?
Thanks
The react test rendered only calls the render method of a component and returns the output, it does not really start the component and so all the life cycle methods are not called. You should switch to the enzyme renderer which supports the full start of components using enzyme.mount

Categories