Simple server-side compatible substitution for window.matchMedia() based on media-query-fns.
mock-match-media is a ponyfill for window.matchMedia but for Node.
This mock is fully compliant with the spec (see doc on MDN or Other features).
We currently requires at least Node v20.19.0 to be able to require(ESM)
It's also coded in TypeScript.
const { matchMedia, setMedia } = require("mock-match-media");
// Define current media
setMedia({
width: 50,
type: "screen",
orientation: "landscape",
prefersColorScheme: "light",
});
matchMedia("(min-width: 250px)").matches;
// > false
matchMedia("(width > 40px)").matches;
// > true
// Only redefine what changed
setMedia({
width: 500,
});
matchMedia("(width > 250px)").matches;
// > truemock-match-media also supports even listeners:
const { matchMedia, setMedia } = require("mock-match-media");
setMedia({
width: 50,
});
const listener = (event) => console.log(event.matches);
const matcher = matchMedia("(min-width: 250px)");
matcher.addEventListener("change", listener);
// And also the deprecated version
// matchMedia("(min-width: 250px)").addListener(event => console.log(event.matches));
setMedia({
width: 100,
});
// outputs nothing because `matches` hasn't changed
setMedia({
width: 1000,
});
// outputs `true`
matcher.removeEventListener("change", listener);
setMedia({
width: 100,
});
// outputs nothing because the listener is removedmock-match-media provides 3 cleanup functions:
const { cleanupListeners, cleanupMedia, cleanup } = require("mock-match-media");cleanupListeners clears all listeners called via matchMedia().addListener() or matchMedia().addEventListener() (to avoid calling in side effects).
cleanupMedia resets the state of the window set via setMedia().
cleanup at the same time clears all listeners (like cleanupListeners), and clears the state of the window (like cleanupMedia).
If you don't want to change your code or to setup mocks with your testing library, you can do:
require("mock-match-media/polyfill");And then global variables matchMedia and MediaQueryListEvent will be set.
And thus, you won't have to import those (you'll still have to import setMedia, and the cleanup functions).
This library covers most of the aspects of matchMedia. In addition to the API presented above, it also supports:
const { matchMedia } = require("mock-match-media");
const mql = matchMedia("(min-width: 250px)");
mql.addEventListener("change", listener, { once: true }); // the listener will be removed after 1 received eventLike every other EventTarget, you can .dispatchEvent(event) to manually dispatch event (it’s not that useful to be honest, but as it’s in the spec, we implemented it).
const { matchMedia, MediaQueryListEvent } = require("mock-match-media");
const mql = matchMedia("(min-width: 250px)");
mql.dispatchEvent(new MediaQueryListEvent("change", { matches: false, media: "(custom-non-valid)" }));
// Works also with a regular event but it’s not recommended:
mql.dispatchEvent(new Event("change"));Like on any HTML element, you can attach a .onchange legacy event handler:
const { matchMedia } = require("mock-match-media");
const mql = matchMedia("(min-width: 250px)");
mql.onchange = listener;We follow how browsers implemented interactions like:
const { matchMedia } = require("mock-match-media");
const mql = matchMedia("(min-width: 250px)");
mql.onchange = listener;
mql.addListener(listener);
mql.addEventListener("change", listener);
mql.addEventListener("change", listener, { once: true });And all of those are tested.
We also ship 2 versions of this library:
- one in CJS
- one in ESM
This is also true for the polyfills, but the setup-jest file is only available in CJS (Jest doesn't work that well with ESM).
In jest.setup.js, you only need to import mock-match-media/jest-setup (or mock-match-media/jest-setup.cjs depending on your config). It'll:
- install the polyfill (for
matchMediaandMediaQueryListEvent) - add a call to
cleanupinafterAllto auto-cleanup your env in after eachtest/it.
You can set import jest-setup in setupFiles or in setupFilesAfterEnv in your jest config.
And then you can use setMedia in your tests.
You can find an example here that includes Jest, react testing library and react-scripts.
You can find an example here for how to use mock-match-media with NextJS.