Reputation: 1738
I'm testing the component Checkout
which has two axios.get
calls inside its useEffect
, like so:
useEffect(() => {
let isMounted = true;
if (isMounted) {
axios
.get("/cart/get-total") // 1st call
.then((res) => {
setCartTotal(res.data)
);
})
.catch((err) => {
console.error(err);
axios
.get("/cart/get-subtotal") // 2nd call
.then((res) => {
setUpfrontPayPalPayment(res.data); // 7% comission
})
.catch((err) => {
console.error(err);
});
}
return () => (isMounted = false);
}, []);
The first call is mocked using axiosMock
from __mocks__/axios.js
method:
axios.js
export default {
post: jest.fn().mockResolvedValue({ data: {} }),
get: jest.fn().mockResolvedValue({ data: {} }),
// getAgain: jest.fn().mockResolvedValue({ data: {} }), // nope
};
However, I don't know how to mock the second call which is also a
get
call.
Checkout.test.js
jest.unmock("axios"); // unmock from previous test
import axiosMock from "../__mocks__/axios";
// faked props
const userInfo = {
userName: "paco",
userPhone: "1234567890",
};
const loggedIn = true;
describe("Checkout Component", () => {
axiosMock.get.mockResolvedValueOnce({ data: 1600 });
// axiosMock.get.mockResolvedValueOnce({ data: 120 }); // tried this for the second
// axiosMock.getAgain.mockResolvedValueOnce({ data: 120 }); // also this
it("renders", async () => {
await act(async () => {
render(
<HashRouter>
<Checkout userInfo={userInfo} loggedIn={loggedIn} />
</HashRouter>
);
screen.debug();
});
});
});
The Checkout.js component if you want to dive in deeper:
import axios from "axios";
import React, { useEffect, useState, useRef, useContext } from "react";
const Checkout = (props) => {
// several useStates
const context = useContext(Context);
// this method gets fired onSubmit
const handleTransferSubmit = () => {
// two axios.post consecutive calls that should not affect at
// all since they are fired onSubmit
};
// get user info and cart total-subtotal
useEffect(() => {
let isMounted = true;
// if phone info available set it
props.userInfo["userPhone"] &&
setPhone(parseInt(props.userInfo["userPhone"]));
if (isMounted) {
axios
.get("/cart/get-total")
.then((res) => {
setCartTotal(
res.data
);
})
.catch((err) => {
console.error(err);
context.notifyToaster('error', 'Tenemos problemas con el servidor. Intenta más tarde');
});
axios
.get("/cart/get-subtotal")
.then((res) => {
setUpfrontPayPalPayment(res.data); // 7% comission
})
.catch((err) => {
console.error(err);
context.notifyToaster(
"error",
"Tenemos problemas con el servidor. Intenta más tarde"
);
});
}
return () => (isMounted = false);
}, []);
// form validations
useEffect(() => {
let isMounted = true;
return () => (isMounted = false);
}, [
orderName,
phone,
CP,
streetName,
addressNumber,
deliveryDay,
deliverySchedule,
addressDetails,
paymentMode,
]);
return (
<div className="container">
{!loader ? (
props.loggedIn && cartTotal > 1500 ? (
<div style={{ marginBottom: "6rem" }}>
<Form>
{/* all the form info */}
<Button
className="mb-5"
variant="primary"
type="submit"
disabled={buttonIsActive ? false : true}
onClick={handleTransferSubmit}
>
Generar orden
</Button>
</Form>
</div>
) : (
<div>{/* if user is not logged in he can't see the form */}</div>
)
) : (
<CustomLoader />
)}
</div>
);
};
export default withRouter(Checkout);
Can't get to see the updated component.
If I screen.debug()
I notice that cartTotal
which is set in the axios
mocked response is not yet set when the render
happens, causing that the condition for rendering the - Form
- component cartTotal > 1500
is false
.
Thanks again buddies!
Upvotes: 1
Views: 4451
Reputation: 1738
As per @jonrsharpe comments and Jest docs
- https://jestjs.io/docs/mock-function-api#mockfnmockresolvedvalueoncevalue - I could mock two consecutive axios calls by chaining mockResolvedValueOnce
. I was using them sepparated at the beginning.
Before
axiosMock.get.mockResolvedValueOnce({ data: 1600 });
axiosMock.get.mockResolvedValueOnce({ data: 120});
After
axiosMock.get
.mockResolvedValueOnce({ data: 1600 })
.mockResolvedValueOnce({ data: 120 })
Upvotes: 1