I am working with a navbar.offcanvas element for responsive navigation menus. I just ran my tests, which pass when I comment out the navbar.offcanvas element. I am using React-Bootstrap, Jest, and testing-library/react.
When I leave the element in and run tests, I get the following:
TypeError: targetWindow.matchMedia is not a function
56 | test("Try to render element", () => {
57 | // Arrange
> 58 | render(<TodoList />);
| ^
I am not sure why this occurs.
Here is the Navbar.Offcanvas
<Navbar.Offcanvas
id={`offcanvasNavbar-expand-md`}
aria-labelledby={`offcanvasNavbarLabel-expand-md`}
placement="start"
>
<Offcanvas.Header closeButton>
<Offcanvas.Title id={`offcanvasNavbarLabel-expand-md`}>
Navigation
</Offcanvas.Title>
</Offcanvas.Header>
<Offcanvas.Body>
<Nav>
{pages.map((page) => {
return (
<Nav.Item key={page.path}>
<Nav.Link
href={page.path}
eventKey={page.path}
onSelect={(k) => setKey(k)}
className="layout-nav-link"
>
{page.name}
</Nav.Link>
</Nav.Item>
);
})}
</Nav>
</Offcanvas.Body>
</Navbar.Offcanvas>
Here are the tests
test("Renders TodoList", () => {
render(<TodoList />);
const todoList = screen.getByText("Todo List");
expect(todoList).toHaveTextContent("Todo List");
});
test("Type into TodoList input box", () => {
// Arrange
render(<TodoList />);
const todoListInput = screen.getByLabelText("TodoId");
console.log(todoListInput);
// Act
fireEvent.change(todoListInput, {
target: { value: "Run" },
});
// Assert
expect(todoListInput.value).toBe("Run");
// Act
fireEvent.change(todoListInput, {
target: { value: "" },
});
// Assert
expect(todoListInput.value).toBe("");
});
If you need any additional information, please let me know. Thanks!
Note: I am still new to using Jest so this may not be the recommended way of fixing the issue. This is the only workaround I could come up with considering my limited knowledge.
I ended up adding the following to my arrange sections in each test that was causing issues:
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
So it will look like:
test("Renders TodoList", () => {
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(), // deprecated
removeListener: jest.fn(), // deprecated
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
render(<TodoList />);
const todoList = screen.getByText("Todo List");
expect(todoList).toHaveTextContent("Todo List");
});
Essentially, I had a method from React Bootstrap that uses matchMedia somewhere but since JSDOM does not implement it (Jest uses JSDOM) I need to mock it. Now my tests are happy... for now. Hope this helps.
Reference: https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom