In your case, you could spy on React.useEffect and provide an alternative implementation. jest.spyOn(React, "useEffect").mockImplementation((f) => f())
so now you dont't have to care about the handling of useEffect anymore.
If you also want to test useEffect in a descent way you may extract the logic in a custom hook and use the testing library for hooks with the renderHooks function to test your use case.
I would test your Component like this:
import React from "react";
import { MyComponent } from "./Example";
import { render } from "@testing-library/react";
import { mocked } from "ts-jest/utils";
jest.mock("./api", () => ({
callApi: jest.fn(),
}));
import api from "./api";
const mockApi = mocked(api);
jest.spyOn(React, "useEffect").mockImplementation((f) => f());
describe("MyComponet", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should not call api when dontCallApi is set", async () => {
render(<MyComponent dontCallApi />);
expect(mockApi.callApi).toHaveBeenCalledTimes(0);
});
it("should call api when is not set", async () => {
render(<MyComponent />);
expect(mockApi.callApi).toHaveBeenCalledTimes(1);
});
});
Edit 03.07.2020
I recently found out that there is a possibility to query something like you wanted without mocking useEffect. You could simply use the async utilities of react testing library and get the following:
import React from "react";
import { MyComponent } from "./TestComponent";
import { render, waitFor } from "@testing-library/react";
import { api } from "./api";
const callApiSpy = jest.spyOn(api, "callApi");
beforeEach(() => {
callApiSpy.mockImplementation(() => Promise.resolve());
});
afterEach(() => {
callApiSpy.mockClear();
});
describe("MyComponet", () => {
afterEach(() => {
jest.clearAllMocks();
});
it("should not call api when dontCallApi is set", async () => {
render(<MyComponent dontCallApi />);
await waitFor(() => expect(callApiSpy).toHaveBeenCalledTimes(0));
});
it("should call api when is not set", async () => {
render(<MyComponent />);
await waitFor(() => expect(callApiSpy).toHaveBeenCalledTimes(1));
});
});
to get more information about this take a look at the async utilities docs