Reputation: 105
I'm writing tests using Jest for a custom DataTable component. I'm also using React Testing Library.
The component loads an iframe when a row is clicked. I'm attempting to mock the function that loads the iframe and I'm getting an error message when running the test that uses the mock. For context, the goal of mocking this function is preventing the test from loading the actual iframe.
The full error message is: Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
My understanding is that this error message usually happens when you're incorrectly importing a module. However, I don't believe this is my case because the component is being imported and used in other tests and it works fine in those tests. It's only the component with the mocked function that produces this error.
How would I mock this function? The function is loadIframe(id)
and it's in a class component. The code for the component and the test code is below.
Stripped down version of the component with the function I want to mock:
class MyDataTable extends React.Component {
...
// I want to mock this function
loadIframe(id = "") {
this.setState({iframe: `/path/to/iframe/${id}`})
}
...
render() {
return (
...
{this.state.iframe !== "" &&
<iframe src={this.state.iframe}/>
}
...
)
);
}
export default MyDataTable;
Code for the tests:
import "@testing-library/jest-dom";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import axios from "axios";
import MyDataTable from "../../components/DataTable/MyDataTable";
jest.mock("axios");
jest.mock("../../components/DataTable/MyDataTable", () => ({
...jest.requireActual("../../components/DataTable/MyDataTable"),
loadIframe: jest.fn((id) => {
// this mocked implementation will need to do something, but I've removed it from this example
})
}));
describe("My tests", () => {
it("should load iframe on row click", async () => {
const data = [
["row 1, col 1", "row 1, col 2"],
["row 2, col 1", "row 2, col 2"]
];
// Need to make a mock POST request to get data so a row can be clicked
axios.post.mockResolvedValue({ data });
// The error is thrown when render() is called here
render(<MyDataTable id="test_id"/>);
await waitFor(() => expect(axios.post).toHaveBeenCalled());
userEvent.click(screen.getAllByRole("gridcell")[0]);
expect(screen.getByTitle("iframe")).toBeInTheDocument();
});
});
Upvotes: 1
Views: 1427
Reputation: 86
IMO, This case is unnecessary to test logic on function loadIframe
. You just query selector that you wanna test and expect src
attribute should be a value according to state change from function loadIframe
.
jest.mock("axios");
describe("My tests", () => {
it("should load iframe on row click", async () => {
const data = [
["row 1, col 1", "row 1, col 2"],
["row 2, col 1", "row 2, col 2"]
];
// Need to make a mock POST request to get data so a row can be clicked
axios.post.mockResolvedValue({ data });
// The error is thrown when render() is called here
const {container} = render(<MyDataTable id="test_id"/>);
await waitFor(() => expect(axios.post).toHaveBeenCalled());
userEvent.click(screen.getAllByRole("gridcell")[0]);
const iFrame = container.querySelector('iframe')
// this step is expect `src` attribute in iFrame element should be according to state change inside function `loadiFrame`
expect(iFrame).toHaveAttribute('src','/path/to/iframe/1')
});
});
Upvotes: 1