Since it can be useful to test different viewport sizes in jest, a few
window.matchMedia helpers have been included. The spyOnMatchMedia can be
used to change the viewport size for tests and expect different results. The
default behavior is to match the desktop min width.
A default matcher can be provided as well:
The following matchers have been provided out of the box which use the default media query breakpoints:
matchPhone - query.includes(DEFAULT_PHONE_MAX_WIDTH)matchTablet - query.includes(DEFAULT_TABLET_MIN_WIDTH)matchDesktop - query.includes(DEFAULT_DESKTOP_MIN_WIDTH)matchLargeDesktop - query.includes(DEFAULT_DESKTOP_LARGE_MIN_WIDTH)matchAnyDesktop - matchDesktop(query) || matchLargeDesktop(query)You can also create a custom matcher:
const customMatcher: MatchMediaMatcher = (query) => query.includes("20rem");
function Example() {
// the `customMatcher` would be called with `"screen and (min-width: 20rem)"`
const matches = useMediaQuery("screen and (min-width: 20rem)");
// implementation
}Use this util to make window.requestAnimationFrame happen immediately.
The ResizeObserverMock can be used to write tests that include the
useResizeObserver hook. Here is a small example:
import { useResizeObserver } from "@react-md/core/useResizeObserver";
import { useCallback, useState } from "react";
export function ExampleComponent() {
const [size, setSize] = useState({ height: 0, width: 0 });
const ref = useResizeObserver({
onUpdate: useCallback((entry) => {
setSize({
height: entry.contentRect.height,
width: entry.contentRect.width,
});
}, []),
});
return (
<>
<div data-testid="size">{JSON.stringify(size)}</div>
<div data-testid="resize-target" ref={ref} />
</>
);
}
This mock currently does nothing other than preventing errors while running tests,
but might be updated to have a similar API as the ResizeObserverMock to
improve testing.
import { matchPhone, render } from "@react-md/core/test-utils";
import { spyOnMatchMedia } from "@react-md/core/test-utils/jest-globals";
const matchMedia = spyOnMatchMedia();
render(<Test />);
// expect desktop results
matchMedia.changeViewport(matchPhone);
// expect phone resultsimport { matchPhone, render } from "@react-md/core/test-utils";
import { spyOnMatchMedia } from "@react-md/core/test-utils/jest-globals";
const matchMedia = spyOnMatchMedia(matchPhone);
render(<Test />);
// expect phone resultsimport { jest } from "@jest/globals";
import { testImmediateRaf } from "@react-md/core/test-utils/jest-globals";
afterEach(() => {
jest.restoreAllMocks();
});
describe("some test suite", () => {
it("should test something with requestAnimationFrame", () => {
const raf = testImmediateRaf();
// do some testing with requestAnimationFrame
// reset to original at the end of the test if not using `jest.restoreAllMocks()`
raf.mockRestore();
});
});import { afterEach, describe, expect, it, jest } from "@jest/globals";
import {
render,
screen,
setupResizeObserverMock,
} from "@react-md/core/test-utils";
import { cleanupResizeObserverAfterEach } from "@react-md/core/test-utils/jest-globals"
import { ExampleComponent } from "../ExampleComponent.jsx";
cleanupResizeObserverAfterEach();
describe("ExampleComponent", () => {
it("should do stuff", () => {
const observer = setupResizeObserverMock();
render(<ExampleComponent />);
const size = screen.getByTestId("size");
const resizeTarget = screen.getByTestId("resize-target");
// jsdom sets all element sizes to 0 by default
expect(size).toHaveTextContent(JSON.stringify({ height: 0, width: 0 }));
// you can trigger with a custom change
act(() => {
observer.resizeElement(resizeTarget, { height: 100, width: 100 });
});
expect(size).toHaveTextContent(JSON.stringify({ height: 100, width: 100 }));
// or you can mock the `getBoundingClientRect` result
jest.spyOn(resizeTarget, "getBoundingClientRect").mockReturnValue({
...document.body.getBoundingClientRect(),
height: 200,
width: 200,
});
act(() => {
observer.resizeElement(resizeTarget);
});
expect(size).toHaveTextContent(JSON.stringify({ height: 200, width: 200 }));
});
});