Test the dispatch function with jest - reactjs

How can I test the return dispatch from mapDispatchToProps?
export const mapDispatchToProps = (dispatch) => {
return {
sidebarSettings: () => {
dispatch(showSettings)
},
setFilterText: (value) => {
dispatch(setFilterText(value))
},
setExportCount: () => {
dispatch(setExportCount())
}
}
}
Have this but not working...
describe('mapDispatchToProps', () => {
test('should retrun a dispatch of sidebar settings, filter text and of export count', () => {
const wrapper = shallow(<mapDispatchToProps />)
expect(wrapper.find('dispatch')).toHaveLength(3)
})
})

Here is the solution, mapDispatchToProps function just a javascript function. You don't need to test it using Shallow render with enzyme.
const ACTION_TYPES = {
SHOW_SETTINGS: 'SHOW_SETTINGS',
SET_FILTER_TEXT: 'SET_FILTER_TEXT',
SET_EXPORT_COUNT: 'SET_EXPORT_COUNT'
};
export const showSettings = { type: ACTION_TYPES.SHOW_SETTINGS };
export const setFilterText = value => ({ type: ACTION_TYPES.SET_FILTER_TEXT, payload: { value } });
export const setExportCount = () => ({ type: ACTION_TYPES.SET_EXPORT_COUNT });
export const mapDispatchToProps = dispatch => {
return {
sidebarSettings: () => {
dispatch(showSettings);
},
setFilterText: value => {
dispatch(setFilterText(value));
},
setExportCount: () => {
dispatch(setExportCount());
}
};
};
Unit test:
import { mapDispatchToProps, showSettings, setFilterText, setExportCount } from './';
const dispatch = jest.fn();
describe('mapDispatchToProps', () => {
it('t1', () => {
const actualValue = mapDispatchToProps(dispatch);
expect(Object.keys(actualValue)).toEqual(['sidebarSettings', 'setFilterText', 'setExportCount']);
actualValue.sidebarSettings();
expect(dispatch).toBeCalledWith(showSettings);
actualValue.setFilterText('name');
expect(dispatch).toBeCalledWith(setFilterText('name'));
actualValue.setExportCount();
expect(dispatch).toBeCalledWith(setExportCount());
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/57802233/index.spec.ts
mapDispatchToProps
✓ t1 (11ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.201s

mapDispatchToProps isn't a React component so you can't render it. If you really want to test that it returns the defined functions, which doesn't make much sense imo, you can just check if the object has the defined props:
describe('mapDispatchToProps', () => {
test('should retrun a dispatch of sidebar settings, filter text and of export count', () => {
expect(Object.keys(mapDispatchToProps())).toHaveLength(3)
})
})

mapDispatchToProps is not React component you don't need enzyme to test this.
one of way testing is you can pass mocked dispatch and call all the function and check if mocked dispatch is called that many times.
describe('mapDispatchToProps', () => {
const dispatch = jest.fn();
const props = mapDispatchToProps(dispatch);
props.setExportCount();
props.setFilterText();
props.sidebarSettings();
expect(dispatch).toHaveBeenCalledTimes(3);
})

Related

How to unit test a React functional component using hooks useEffect,useDispatch and useSelector and Redux?

I am trying to test a functional component which is below :
export const MyFunctionalComponent=()=>{
const {id, otherid} = useSelector((state) => state.user);
const accounts = useSelector((state) => state.Selection.accounts);
const dispatch = useDispatch();
useEffect(() => {
if (!accounts) {
dispatch(getDetails(id, otherid));
}
}, []);
const handleOnClick = (Id) => {
dispatch(saveId(Id));
};
if (!accounts) {
return <CircularLoader />;
}
if (!accounts.length) {
return (
<AccessUnavailablePanel
/>
);
}
if (accounts.length === 1) {
return <Redirect to={`${accounts[0].id}`} />;
}
return (
<MyList
accounts={accounts}
handleOnClick={handleOnClick}
/>
);
};
i am new to JEST , how can i correctly mock useSelector, useDispatch and useEffect ?
i am trying to test as follows :
jest.mock('react-redux', () => ({
...jest.requireActual('react-redux'),
useSelector: jest.fn(),
useDispatch: jest.fn()
}));
describe('<MyFunctionalComponent/>', () => {
const useEffect=jest.spyOn(React, "useEffect").mockImplementation(() => {})
const useSelectorMock = reactRedux.useSelector;
const useDispatchMock = reactRedux.useDispatch;
const user = {
id: '32sdfsdfr-fjdfdk33-4434sdfs',
otherid: '73587hdfjg-dfghd94-jgdj'
};
const store = mockStore({
user:user,
Selection: {
Id: '',
accounts: null
}
});
let wrapper;
const setup = () => {
const {result} = renderHook(() => MyFunctionalComponent(), {
wrapper: ({children}) => (
<Provider store={store}>{children}</Provider>
)
});
return result;
};
describe('Rendering accounts available', () => {
beforeEach(() => {
useDispatchMock.mockImplementation(() => () => {});
useSelectorMock.mockImplementation((selector) =>
selector(mockStore)
);
});
afterEach(() => {
jest.clearAllMocks();
useSelectorMock.mockClear();
useDispatchMock.mockClear();
});
it('should render the accounts if more than 1 account available', () => {
useSelectorMock.mockReturnValue(user);
const mockdata = {
accounts: [
{
id: '637ghgh',
},
{
id: '10a190abd',
}
]
};
const getDetails = jest.spyOn(
SelectionActions,
'getDetails'
);
useSelectorMock.mockReturnValue(mocdata);
useDispatchMock.mockReturnValue(
getDetails(user.id, user.otherid)
);
wrapper = setup();
store.dispatch(getDetails(user.id, user.otherid))
sleep(500);
const actions=store.getActions();
console.debug(actions[0])
expect(getDetails).toHaveBeenCalledWith(user.id, user.otherid);
expect(actions[0].type).toEqual('GET_DETAILS')
expect(wrapper.current).toMatchSnapshot();
});
});
But my snapshot seems to return AccessUnavialable, and the payload is undefined. How can I modify my tests to correctly return the mocked data as payload and get the correct snapshot?
It can be tested by mocking libraries such as react-redux, but it is not recommended. It pays too much attention to implementation details. A better way is to use the mock store to provide only mock data instead of mock implementation details. Use the original, unmocked useSelector and useEffect hooks, which are closer to the real function of the code, rather than the implementation details of the mock.
In addition, creating mock objects and their implementation are also very cumbersome steps. You should also pay attention to cleaning up mock objects to avoid being used by other test cases, resulting in test failures.
Use redux-mock-store to create a mock store with the mocked state.
Each test case provides different mock data to drive component rendering, and finally, assert whether the component rendering is correct.
For simplicity, just to demonstrate this test method, I replaced your component with a simple component, the principle is the same.
E.g.
index.tsx:
import { useSelector, useDispatch } from 'react-redux';
import { useEffect } from 'react';
import React from 'react';
const getDetails = (id, otherId) => ({ type: 'GET_DETAILS' });
export const MyFunctionalComponent = () => {
const { id, otherid } = useSelector((state: any) => state.user);
const accounts = useSelector((state: any) => state.Selection.accounts);
const dispatch = useDispatch();
useEffect(() => {
if (!accounts) {
dispatch(getDetails(id, otherid));
}
}, []);
if (!accounts) {
return <div>CircularLoader</div>;
}
if (!accounts.length) {
return <div>AccessUnavailablePanel</div>;
}
if (accounts.length === 1) {
return <div>Redirect</div>;
}
return <div>MyList</div>;
};
index.test.tsx:
import { MyFunctionalComponent } from './';
import createMockStore from 'redux-mock-store';
import { screen, render } from '#testing-library/react';
import { Provider } from 'react-redux';
import React from 'react';
const mockStore = createMockStore([]);
describe('69013562', () => {
test('should render AccessUnavailablePanel', () => {
const state = {
user: { id: '1', otherid: '2' },
Selection: { accounts: [] },
};
const store = mockStore(state);
render(<MyFunctionalComponent />, {
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
});
expect(screen.getAllByText('AccessUnavailablePanel')).toBeTruthy();
expect(store.getActions()).toEqual([]);
});
test('should render CircularLoader and dispatch get details action', () => {
const state = {
user: { id: '1', otherid: '2' },
Selection: {},
};
const store = mockStore(state);
render(<MyFunctionalComponent />, {
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
});
expect(screen.getAllByText('CircularLoader')).toBeTruthy();
expect(store.getActions()).toEqual([{ type: 'GET_DETAILS' }]);
});
test('should render Redirect', () => {
const state = {
user: { id: '1', otherid: '2' },
Selection: { accounts: [1] },
};
const store = mockStore(state);
render(<MyFunctionalComponent />, {
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
});
expect(screen.getAllByText('Redirect')).toBeTruthy();
expect(store.getActions()).toEqual([]);
});
test('should render MyList', () => {
const state = {
user: { id: '1', otherid: '2' },
Selection: { accounts: [1, 2, 3] },
};
const store = mockStore(state);
render(<MyFunctionalComponent />, {
wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
});
expect(screen.getAllByText('MyList')).toBeTruthy();
expect(store.getActions()).toEqual([]);
});
});
test result:
PASS examples/69013562/index.test.tsx (10.158 s)
69013562
✓ should render AccessUnavailablePanel (28 ms)
✓ should render CircularLoader and dispatch get details action (3 ms)
✓ should render Redirect (2 ms)
✓ should render MyList (2 ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.tsx | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 11.014 s
There is no single answer to the test strategy, adjust according to the specific situation.

How to set state in test when using enzyme and jest?

To start I'm conditionally rendering a component that's reliant on the useState hook being set as a result of useEffect hook. Here's a code sample:
function Component() {
const [response, setResponse] = useState();
const [fail, setFail] = useState();
/**
* #function getModels - fetch data to populate the models
* */
const fetchStuff = async () => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((data) => {
const storage = [data];
setResponse(storage);
setFail(false);
})
.catch((err) => {
setResponse(err);
setFail(true);
});
};
useEffect(() => {
fetchStuff();
}, []);
if (fail === true) {
return (
<p>
ERROR:
{fail}
</p>
);
}
if (fail === false) {
return (
<p>
Success:
{response}
</p>
);
}
return <p>Loading Screen</p>;
}
My current point of contention is that I'm unable to call setResponse or setFail and update the state of fail or response. I believe that I need to use mount as opposed to shallow rendering? Also, I understand that testing philosophies would argue against conducting a test in this fashion. However, I am seeking an a solution that enables updating the state. Any advice would be greatly appreciated.
You can mock fetch API call to and its resolved value. Then, you can assert what exactly the component renders. We should use whenStable function to make sure the mocked API calls are completed.
Component.jsx:
import React, { useState, useEffect } from 'react';
export function Component() {
const [response, setResponse] = useState();
const [fail, setFail] = useState();
/**
* #function getModels - fetch data to populate the models
* */
const fetchStuff = async () => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((data) => {
const storage = [data];
setResponse(storage);
setFail(false);
})
.catch((err) => {
setResponse(err);
setFail(true);
});
};
useEffect(() => {
fetchStuff();
}, []);
if (fail === true) {
return (
<p>
ERROR:
{fail}
</p>
);
}
if (fail === false) {
return (
<p>
Success:
{response}
</p>
);
}
return <p>Loading Screen</p>;
}
Component.test.jsx:
import React from 'react';
import { Component } from './Component';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
const whenStable = async () => {
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
};
describe('65243384', () => {
let fetch;
beforeEach(() => {
fetch = global.fetch;
});
afterEach(() => {
global.fetch = fetch;
});
it('should success', async () => {
global.fetch = jest.fn().mockResolvedValueOnce('mocked success data');
const wrapper = mount(<Component></Component>);
expect(wrapper.find('p').text()).toBe('Loading Screen');
await whenStable();
expect(wrapper.find('p').text()).toBe('Success:mocked success data');
expect(global.fetch).toBeCalledWith('https://jsonplaceholder.typicode.com/todos/1');
});
it('should fail', async () => {
const mErr = new Error('network');
global.fetch = jest.fn().mockRejectedValueOnce(mErr);
const wrapper = mount(<Component></Component>);
expect(wrapper.find('p').text()).toBe('Loading Screen');
await whenStable();
expect(wrapper.find('p').text()).toBe('ERROR:');
expect(global.fetch).toBeCalledWith('https://jsonplaceholder.typicode.com/todos/1');
});
});
unit test result:
PASS examples/65243384/Component.test.jsx
65243384
✓ should success (44 ms)
✓ should fail (5 ms)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
Component.jsx | 100 | 100 | 100 | 100 |
---------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 5.121 s
source code: https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/65243384

How to write test case for url push in useEffect react hook?

import { logout } from '../../actions/user.actions';
const Logout = () => {
useEffect(() => {
Router.push('/any');
}, []);
};
Test File
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.resetAllMocks(); // clear all the mocks.
});
it('Should check the route', () => {
const wrapper = mount(<Logout />);
expect(wrapper.find('LoadingMessage')).toBeTruthy();
expect(useDispatch).toBeCalledTimes(1);
const mDispatch = useDispatch();
expect(mDispatch).toBeCalledWith({ type: 'USER_LOGOUT' });
expect(Router.push).toBeCalledWith('/');expect(mDispatch).toBeCalledWith({ type: 'USER_LOGOUT' });
expect(mDispatch).toBeCalledWith('/');
})
})
This is my sample of code that I have written, I want to write a test case for this. So I can test the Router push is happening or not?
Wanting some idea or help.
Thanks in advance.
Below unit test solution mocks useDispatch hook and next/router module without using a mock redux store. Using the mocked redux store and check the state of store after dispatching an action is closer to integration testing.
E.g.
index.jsx:
import React, { useEffect } from 'react';
import Router from 'next/router';
import { useDispatch } from 'react-redux';
import { logout } from './user.actions';
import { LoadingMessage } from './LoadingMessage';
export const Logout = () => {
const dispatch = useDispatch();
const props = {
active: true,
withOverlay: false,
small: false,
};
useEffect(() => {
dispatch(logout());
Router.push('/');
}, []);
return (
<div>
<LoadingMessage {...props}>
<div>Logging out, please wait...</div>
</LoadingMessage>
</div>
);
};
user.actions.ts:
export function logout() {
return {
type: 'LOGOUT',
};
}
LoadingMessage.jsx
export const LoadingMessage = ({ children }) => <div>{children}</div>;
index.test.jsx:
import { Logout } from './';
import { useDispatch } from 'react-redux';
import { mount } from 'enzyme';
import Router from 'next/router';
jest.mock('next/router', () => ({ push: jest.fn() }), { virtual: true });
jest.mock('react-redux', () => {
const originalReactRedux = jest.requireActual('react-redux');
const mDispatch = jest.fn();
const mUseDispatch = jest.fn(() => mDispatch);
return {
...originalReactRedux,
useDispatch: mUseDispatch,
};
});
describe('61928263', () => {
afterEach(() => {
jest.clearAllMocks();
});
afterAll(() => {
jest.resetAllMocks();
});
it('should pass without using mock store', () => {
const wrapper = mount(<Logout></Logout>);
expect(wrapper.find('LoadingMessage')).toBeTruthy();
expect(useDispatch).toBeCalledTimes(1);
const mDispatch = useDispatch(); // get the mocked dispatch function
expect(mDispatch).toBeCalledWith({ type: 'LOGOUT' });
expect(Router.push).toBeCalledWith('/');
});
});
The outcome for the test:
PASS stackoverflow/61928263/index.test.jsx (8.62s)
61928263
✓ should pass without using mock store (37ms)
--------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
LoadingMessage.jsx | 100 | 100 | 100 | 100 |
index.jsx | 100 | 100 | 100 | 100 |
user.actions.ts | 100 | 100 | 100 | 100 |
--------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 9.601s

test restapi inside useeffect in jest

I'm new to Jest and I'm writing test case for the below function,
useEffect(() => {
fetch("http://ip-api.com/json")
.then(res => res.json())
.then(data => {
cntCode = `country_code=${data.countryCode}`;
country = `country=${data.country}`;
});
});
I tried few ways to cover using but I'm not able to figure out how to cover this function. Can someone help me in writing the testcase for this please?
Here is the unit test solution:
index.tsx:
import React, { useEffect, useState } from 'react';
export const MyComponent = () => {
const [cntCode, setCntCode] = useState('');
const [country, setCountry] = useState('');
useEffect(() => {
fetch('http://ip-api.com/json')
.then((res) => res.json())
.then((data) => {
setCntCode(data.countryCode);
setCountry(data.country);
});
}, [cntCode, country]);
return (
<div>
country: {country}, cntCode: {cntCode}
</div>
);
};
index.test.ts:
import { MyComponent } from './';
import React from 'react';
import { mount } from 'enzyme';
import { act } from 'react-dom/test-utils';
describe('MyComponent', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
const mResponse = jest.fn().mockResolvedValue({ countryCode: 123, country: 'US' });
(global as any).fetch = jest.fn(() => {
return Promise.resolve({ json: mResponse });
});
const wrapper = mount(<MyComponent></MyComponent>);
expect(wrapper.exists()).toBeTruthy();
expect(wrapper.text()).toBe('country: , cntCode: ');
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
expect(wrapper.text()).toBe('country: US, cntCode: 123');
expect((global as any).fetch).toBeCalledWith('http://ip-api.com/json');
});
});
Unit test result with 100% coverage:
PASS src/stackoverflow/59368499/index.test.tsx (9.629s)
MyComponent
✓ should pass (73ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.tsx | 100 | 100 | 100 | 100 | |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.64s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59368499

How to test basic example of async function in useEffect

I have a simple component, it fetches async list of posts.
export const Posts = () => {
const [list, dispatch] = useReducer(listReducer, []);
useEffect(() => {
fetchList(dispatch);
}, []);
return (
<ul>
{list.map((el) => (
<li key={el.id}>{el.title}</li>
))}
</ul>
);
};
In other file i keep the logic:
export const fetchList = async (dispatch) => {
try {
const result = await api.get('/list/') /* AXIOS */
dispatch({ type: LIST_SUCCES, payload: result.data.list })
} catch (error) {
dispatch({ type: LIST_FAILURE })
}
}
export const listReducer = (state, action) => {
switch (action.type) {
case LIST_SUCCES:
return action.payload
case LIST_FAILURE:
return []
default:
throw new Error()
}
}
I've tried multiple libraries but i'm just unable to write a test. How can i write Posts.test.js to check if post are fetched and displayed, i'm triggering async fetchList after first mount of the component (so it is not componentDidMount), and after data are fetched i dispatch action from that async function and update the list.
Here is the unit test solution:
index.tsx:
import React, { useReducer, useEffect } from 'react';
import { listReducer, fetchList } from './reducer';
export const Posts = () => {
const [list, dispatch] = useReducer(listReducer, []);
useEffect(() => {
fetchList(dispatch);
}, []);
return (
<ul>
{list.map((el) => (
<li key={el.id}>{el.title}</li>
))}
</ul>
);
};
reducer.ts:
import axios from 'axios';
const LIST_SUCCES = 'LIST_SUCCES';
const LIST_FAILURE = 'LIST_FAILURE';
export const fetchList = async (dispatch) => {
try {
const result = await axios.get('/list/'); /* AXIOS */
dispatch({ type: LIST_SUCCES, payload: result.data.list });
} catch (error) {
dispatch({ type: LIST_FAILURE });
}
};
export const listReducer = (state, action) => {
switch (action.type) {
case LIST_SUCCES:
return action.payload;
case LIST_FAILURE:
return [];
default:
throw new Error();
}
};
index.spec.tsx:
import React from 'react';
import { Posts } from './';
import { mount } from 'enzyme';
import axios from 'axios';
import { act } from 'react-dom/test-utils';
describe('Posts', () => {
afterAll(() => {
jest.restoreAllMocks();
});
it('should render list correctly', async () => {
const mResponse = { data: { list: [{ id: 1, title: 'jest' }] } };
jest.spyOn(axios, 'get').mockResolvedValueOnce(mResponse);
const wrapper = mount(<Posts></Posts>);
expect(wrapper.find('ul').children()).toHaveLength(0);
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('ul').children()).toHaveLength(1);
expect(wrapper).toMatchInlineSnapshot(`
<Component>
<ul>
<li
key="1"
>
jest
</li>
</ul>
</Component>
`);
});
it('should render empty list when request list data failed', async () => {
const mError = new Error('Internal server error');
jest.spyOn(axios, 'get').mockRejectedValueOnce(mError);
const wrapper = mount(<Posts></Posts>);
expect(wrapper.find('ul').children()).toHaveLength(0);
await act(async () => {
await new Promise((resolve) => setTimeout(resolve, 0));
});
wrapper.update();
expect(wrapper.find('ul').children()).toHaveLength(0);
expect(wrapper).toMatchInlineSnapshot(`
<Component>
<ul />
</Component>
`);
});
});
Unit test result with coverage report:
PASS src/stackoverflow/59197574/index.spec.tsx (12.494s)
Posts
✓ should render list correctly (105ms)
✓ should render empty list when request list data failed (37ms)
› 1 snapshot written.
------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files | 95.83 | 66.67 | 100 | 95 | |
index.tsx | 100 | 100 | 100 | 100 | |
reducer.ts | 92.86 | 66.67 | 100 | 91.67 | 21 |
------------|----------|----------|----------|----------|-------------------|
Snapshot Summary
› 1 snapshot written from 1 test suite.
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 1 written, 1 passed, 2 total
Time: 14.409s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59197574

Resources