Testing
responsive-media/testing replaces window.matchMedia with a controllable viewport, so a test can change the width, flip a user preference and watch your components react — in Vitest or Jest with jsdom, which has no matchMedia of its own.
ts
import { createViewportMock } from 'responsive-media/testing'A viewport mock
createViewportMock(options?)
ViewportMock
Creates the mock. Nothing changes until you call install().
ts
import { beforeEach, afterEach, it, expect } from 'vitest'
import { createResponsiveState } from 'responsive-media'
import { createViewportMock } from 'responsive-media/testing'
const viewport = createViewportMock({ width: 1280, height: 800 })
beforeEach(() => viewport.install())
afterEach(() => viewport.uninstall())
it('follows the viewport', () => {
const state = createResponsiveState({
mobile: [{ type: 'max-width', value: 600 }],
desktop: [{ type: 'min-width', value: 601 }],
})
expect(state.getState()).toEqual({ mobile: false, desktop: true })
viewport.setViewport({ width: 500 })
expect(state.getState()).toEqual({ mobile: true, desktop: false })
})width,height—number· default:1280and800. The starting size.features—Record<string, string>· default: none. The starting values of user-preference features.
Methods
install()— puts the mock onwindow.matchMediaand setswindow.innerWidthandwindow.innerHeight.uninstall()— restoresmatchMediaand the window size, and returns the mock to its starting size and features, so one mock can be reused by every test.setViewport({ width?, height? })— changes the size, updateswindow.innerWidthandwindow.innerHeight, fireschangeon every query that flipped, and dispatches aresizeevent, sosubscribeViewportSize()anduseViewportSize()follow too.setFeature(name, value)— changes a user-preference feature, for examplesetFeature('prefers-color-scheme', 'dark'), and fireschangeon the queries that flipped.getViewport()— the current{ width, height }.
Supported queries
The mock evaluates the media queries a component is likely to use:
- Size —
width,heightandaspect-ratio, withmin-andmax-prefixes,orientation, and the range syntax:(width <= 850px),(600px <= width <= 900px). - Combinations —
and,,(or),not,only, and the media typesall,screenandprint(printis false unless you setsetFeature('media-type', 'print')). - User preferences —
prefers-color-scheme,prefers-reduced-motion,prefers-contrast,hover,any-hover,pointer,any-pointer,forced-colors,display-mode, with the defaults of a desktop browser (light, no preference,hover: hover,pointer: fine).
evaluateMediaQuery(query, size, features?)
boolean
The evaluator on its own, for a quick check of a query against a size.
ts
import { evaluateMediaQuery } from 'responsive-media/testing'
evaluateMediaQuery('(width <= 850px)', { width: 800, height: 600 }) // trueWhat it does not mock
ResizeObserver is not mocked, so container state needs your own stub — see the tests of the package for one.