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 results
import { 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 results
import { 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 }));
});
});