I'm writing some jest-enzyme tests for a simple React app using Typescript and the new React hooks.
However, I can't seem to properly simulate the api call being made inside the useEffect
hook.
useEffect
makes the api call and updates the useState
state "data" with "setData".
The object "data" is then mapped into a table to its corresponding table cells.
This seems like it should be easy to tackle with a mocked api response and an enzyme mount, but I keep getting errors telling me to use act()
for component updates.
I tried using act()
many ways but to no avail. I've tried replacing axios
with fetch and using enzyme shallow and the react-test-library's render, but nothing seems to work.
The component:
import axios from 'axios'
import React, { useEffect, useState } from 'react';
interface ISUB {
id: number;
mediaType: {
digital: boolean;
print: boolean;
};
monthlyPayment: {
digital: boolean;
print: boolean;
};
singleIssue: {
digital: boolean;
print: boolean;
};
subscription: {
digital: boolean;
print: boolean;
};
title: string;
}
interface IDATA extends Array<ISUB> {}
const initData: IDATA = [];
const SalesPlanTable = () => {
const [data, setData] = useState(initData);
useEffect(() => {
axios
.get(`/path/to/api`)
.then(res => {
setData(res.data.results);
})
.catch(error => console.log(error));
}, []);
const renderTableRows = () => {
return data.map((i: ISUB, k: number) => (
<tr key={k}>
<td>{i.id}</td>
<td>
{i.title}
</td>
<td>
{i.subscription.print}
{i.mediaType.digital}
</td>
<td>
{i.monthlyPayment.print}
{i.monthlyPayment.digital}
</td>
<td>
{i.singleIssue.print}
{i.singleIssue.digital}
</td>
<td>
<button>Submit</button>
</td>
</tr>
));
};
return (
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>MediaType</th>
<th>MonthlyPayment</th>
<th>SingleIssue</th>
<th/>
</tr>
</thead>
<tbody'>{renderTableRows()}</tbody>
</table>
);
};
export default SalesPlanTable;
The test:
const response = {
data: {
results: [
{
id: 249,
mediaType: {
digital: true,
print: true
},
monthlyPayment: {
digital: true,
print: true
},
singleIssue: {
digital: true,
print: true
},
subscription: {
digital: true,
print: true
},
title: 'ELLE'
}
]
}
};
//after describe
it('should render a proper table data', () => {
const mock = new MockAdapter(axios);
mock.onGet('/path/to/api').reply(200, response.data);
act(() => {
component = mount(<SalesPlanTable />);
})
console.log(component.debug())
});
I expect it to log the html of the table with the table body section rendered, I tried some async and different ways to mock axios
but I keep either getting just the table headers or the message: An update to SalesPlanTable
inside a test was not wrapped in act(...).
I looked for many hours for a resolution but can't find anything that works so I decided to muster up some courage and ask here.
so I decided to muster up some courage and ask here
...we're not THAT scary, are we? :) (great question, btw) – Murmurous