i'm building a portfolio website, so i'm mocking some requests to show that i know how to handle it.
Here's my "request":
export const getTestimonials = async (): Promise<Testimonial[]> => {
// const response = await api.get("/testimonials");
const mockedResponse: MockedAxiosResponse = {
data: mockedTestimonials,
status: 200,
statusText: "OK",
headers: {},
config: {},
request: {},
};
return mockedResponse.data;
};
mockedTestimonials
is an array of objects.
export interface Testimonial {
user: string;
location: string;
testimonial: string;
}
export const mockedTestimonials: Testimonial[] = [
In my component of testimonials, i've made an example of how i would do if the requests was real:
const Testimonials = (): JSX.Element => {
useEffect(() => {
console.log("testimonials fetched");
// getTestimonials()
// .then(testimonials_ => {
// setTestimonials(testimonials_);
// })
// .catch(err => {
// console.error(err);
// });
}, []);
const [testimonials, setTestimonials] =
useState<Testimonial[]>(mockedTestimonials);
NOW THE PROBLEM
I was trying to write a test to it, so i've made a spy on useEffect:
test("Request made", async () => {
const spy = vi.spyOn(React, "useEffect");
await render(<Testimonials />);
expect(spy).toHaveBeenCalled();
});
This test apparently doesn't recognize that useEffect was called, but this test works:
test("Request made", async () => {
const spy = vi.spyOn(console, "log");
await render(<Testimonials />);
expect(spy).toHaveBeenCalledWith("testimonials fetched");
});
I'm trying to do the best automated test to this situation, since it's not real, i'm not testing the global fetch, the console.log is the best way i've found, but i think that is not good, i've searched for useEffect tests with vitest, but the examples are complex like real requests, custom hooks, so doesn't fit my need,can someone help how i could test if the useEffect was called, or some idea of a better test? Since then, thanks.
Tried spy and mock of vitest
Normally you do NOT test any methods from React directly, rather than treat a component as a black-box, where you pass some prop in, expect something out.
However, since you aren't rendering any data from the response, we will have to do it differently -- spyon getTestimonials
instead.
// assuming `getTestimonials` is stored in `./api.tx` file
import * Api from './api'
const getTestimonialsSpy = vi.spyOn(Api, 'getTestimonialsSpy')
afterEach(()=>{ vi.clearAllMocks()}) // reset mock counts
test("Request made", () => {
render(<Testimonials />);
expect(getTestimonialsSpy).toHaveBeenCalledTimes(1);
});
The other ways is to render all the Testimonials response to the component, add the data-testid
to the attribute of the children components, then do assertions with
// assume the children component has `data-testid="testimonial"` and has 3 items
expect(screen.getAllByTestId('testimonial')).toHaveLength(3)