Reputation: 644
I am trying to test my method in a context provider. I have one branch in the method to be covered and that's what I am strangling with. The specific branch is only entered when a specific condition occurs: if (offset !== 0 && total !== 0 && offset >= total)
See my Class component below:
class JourneyProvider extends Component<
{
children: ReactNode;
},
JourneyContextData
> {
constructor(props: { children: ReactNode }) {
super(props);
this.state = {
...defaultValues,
};
}
getContextValue = (): JourneyContextData => {
const { products, total, limit, offset, loading, disabled, setProducts } =
this.state;
return {
products,
total,
limit,
offset,
loading,
disabled,
setProducts,
};
};
setProducts = async (): Promise<void> => {
const { limit, offset, total, products } = this.state;
if (total === 0 || offset < total) {
const gqlRequest = new GQLRequest(query);
this.setLoading(true);
try {
await gqlRequest.post().then(({ products: { edges, totalCount } }) => {
const newOffset = offset + limit;
this.setState({
products,
total: totalCount,
offset: newOffset,
});
this.setLoading(false);
// Disable button if there are no more products
if (offset !== 0 && total !== 0 && offset >= total) {
// never gets in here when testing.
this.setDisabled(true);
}
});
} catch (e) {
this.setLoading(false);
}
}
};
}
This is my test:
it("setProducts is successful and disable button", async () => {
const wrapper = shallow(
<JourneyProvider>
<div>test</div>
</JourneyProvider>
) as any;
const result = {
products: {
edges: [
{
node: {
id: "1",
name: "test-name",
},
},
],
totalCount: 1,
},
};
mockedClient.post.mockResolvedValueOnce(result);
jest
.spyOn(ProductsQuery, "getProductsQuery")
.mockResolvedValueOnce(new Query("test", true) as never);
const setLoadingSpy = jest.spyOn(wrapper.instance(), "setLoading");
const setDisabledSpy = jest.spyOn(wrapper.instance(), "setDisabled");
wrapper.state().limit = result.products.totalCount;
console.log(wrapper.state().offset); //this returns 0
await wrapper.instance().setProducts();
console.log(wrapper.state().offset); //this returns 0
expect(setLoadingSpy).toHaveBeenCalledWith(true); // this passes
expect(setLoadingSpy).toHaveBeenCalledWith(false); // this passes
expect(setDisabledSpy).toHaveBeenCalledWith(true); // this fails
});
Upvotes: 0
Views: 332
Reputation: 20775
You should change the logic in the code where you're making the comparison because you're using a stale state, keep in mind that a call to setState
doesn't change the state immediately. Compare the new values you set to the state instead of the old state values
if (newOffset !== 0 && totalCount !== 0 && newOffset >= totalCount) {
or put that code inside the setState callback to guarantee you're using updated values
...
const newOffset = offset + limit;
this.setState({
products,
total: totalCount,
offset: newOffset,
}, () => {
this.setLoading(false);
if (offset !== 0 && total !== 0 && offset >= total) {
this.setDisabled(true);
}
});
...
Upvotes: 1