I am using React with Typescript and Jest for unit testing. I'm not using Enzyme.
I'm trying to understand the mocking capabilities with Jest and specifically to determine something wrong.
I've created a react app using the create-react-app with typescript, i.e.
npx create-react-app my-app --template typescript
My next step was to create the following inside the src directory.
// services/serviceResponse.ts
export interface ServiceResponse {
label: string;
id: string;
}
// services/myservice.ts
import { ServiceResponse } from "./serviceResponse";
const cannedServiceResponse: ServiceResponse[] = [
{
label: 'label1',
id: 'id1',
},
{
label: 'label2',
id: 'id2',
},
]
async function GetServiceData(): Promise<ServiceResponse[] | Error> {
return cannedServiceResponse;
}
export default {
GetServiceData,
};
// components/mycomponent.tsx
import React, { useState, useEffect } from 'react';
import myservice from '../services/myservice';
import { Row } from 'react-bootstrap';
import { ServiceResponse } from '../services/serviceResponse';
export const MyComponent = () => {
const [data, setData] = useState<ServiceResponse[] | undefined>();
useEffect(() => {
const fetchData = async () => {
const serviceData = await myservice.GetServiceData();
if (!(serviceData instanceof Error)) {
setData(serviceData);
}
};
fetchData();
}, []);
if (!data) {
return <></>;
}
return (
<>
<Row xs={1} md={4} className="col-lg-12">
</Row>
</>
);
};
Then I want to unit test the Component by mocking the data returned from the service method GetServiceData
. My code for the test component is
// components/mycomponents.test.tsx
import React from 'react';
import TestRenderer from 'react-test-renderer';
import { MyComponent } from './mycomponent';
import myservice from '../services/myservice';
import { Row } from 'react-bootstrap';
import { ServiceResponse } from '../services/serviceResponse';
const mockData: ServiceResponse[] = [
{ label: 'a', id: 'b'},
{ label: 'f', id: 'g'},
];
describe('mycomponent', () => {
it('MyComponent returns data', () => {
jest.spyOn(myservice, 'GetServiceData').mockImplementation(
() =>
new Promise<ServiceResponse[]>((resolve) => {
resolve(mockData);
})
);
const component = TestRenderer.create(<MyComponent />);
const componentInstance = component.root;
console.log(component.toJSON());
// TODO - Add an expect line here for assertion
});
});
The problem is that the jest.spyOn() doesn't mock the data. I tried using the following also
jest.mock('../services/myservice', () => ({
GetServiceData: jest.fn().mockReturnValue(() => Promise.resolve(mockData)),
}));
I understand there are ways to test with Enzyme as used here but I'm trying to understand mocking with Jest and what I'm doing wrong.
CodePudding user response:
jest.spyOn()
should work. You need to use the asynchronous version of act to apply resolved promises. You can refer to the official example testing-recipes.html#data-fetching
import React from 'react';
import { act, create } from 'react-test-renderer';
import { MyComponent } from './mycomponent';
import myservice from '../services/myservice';
import { ServiceResponse } from '../services/serviceResponse';
const mockData: ServiceResponse[] = [
{ label: 'a', id: 'b' },
{ label: 'f', id: 'g' },
];
describe('mycomponent', () => {
it('MyComponent returns data', async () => {
jest.spyOn(myservice, 'GetServiceData').mockResolvedValue(mockData);
let root;
await act(async () => {
root = create(<MyComponent />);
});
console.log(root.toJSON());
});
});
test result:
PASS examples/69293771/components/mycomponent.test.tsx (7.271 s)
mycomponent
✓ MyComponent returns data (25 ms)
console.log
{ type: 'div', props: {}, children: [ 'row' ] }
at examples/69293771/components/mycomponent.test.tsx:19:13
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 7.755 s, estimated 9 s