Reputation: 297
Currently trying to unit test components with hooks (useState and useEffects). As I have read, lifecycles can only be tested with a mount and not a shallow render.
Implementation code:
export function MainPageRouter({issuerDeals, match, dbLoadIssuerDeals}) {
console.log("MainPageRouter")
const [isLoading, setIsLoading] = useState(true);
const selectedIssuerId = match.params.id;
const issuerDeal = filterIssuerDealByIssuerId(issuerDeals,
selectedIssuerId);
useEffect(() => {
dbLoadIssuerDeals(selectedIssuerId)
.then(() => {
setIsLoading(false);
})
.catch(function (error) {
setIsLoading(false);
});
}, [selectedIssuerId]);
if (isLoading) {
return <MainPageLoading />
} else if(issuerDeal.length > 0) {
return <MappedDeal match={match}/>
} else {
return <MapDeal match={match}/>
}
}
const mapStateToProps = state => {
return {
deals: state.deals,
issuerDeals: state.issuerDeals
}
};
const mapDispatchToProps = {
dbLoadIssuerDeals
}
export default connect(mapStateToProps, mapDispatchToProps)(MainPageRouter);
However doing so results in this error:
Warning: An update to MainPageRouter inside a test was not wrapped in
act(...).
When testing, code that causes React state updates should be wrapped into
act(...):
act(() => {
/* fire events that update state */
});
Test:
it('Should render Mapped Deal', () => {
const dbLoadIssuerDeals = jest.fn(() => Promise.resolve({
payload:{ deals: { dealid: "1", sourceCode: "TEST" }, issuerId: "1" } }))
const props = createProps(issuerDeals, dbLoadIssuerDeals);
const mainPageRouter = mount(<MemoryRouter><MainPageRouter{...props} /></MemoryRouter>);
});
Is there a clean way to test that mainPageRouter would return back MappedDeal or MapDeal? I also understand that using mount is more towards integration tests.
Upvotes: 15
Views: 1076
Reputation: 468
The warning you're getting isn't caused by using hooks per see but because you have a side-effect that causes a state update.
Something is happening after your component's initial render: you're fetching data from your dbLoadIssuerDeals
service and updating the local state, resulting in a re-render. However, your test runs right after the first render, meaning it couldn't properly assert anything happening after the effect. You could basically only test that MainPageLoading
is displayed, but none of the other branching statements. React's act
testing API is warning you about that.
Running your code in act
guarantees the execution of state updates and enqueued side-effects. In other words, it lets you "wait" for changes resulting from state updates. You can read more about act
in React's official docs.
I recommend using React Testing Library instead of Enzyme or the test utilities of React DOM directly. It wraps updates and events in act
for you, allowing you to write more expressive tests without the boilerplate.
Upvotes: 1