Skip to content

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: 1280 and 800. The starting size.
  • features — Record<string, string> · default: none. The starting values of user-preference features.

Methods ​

  • install() — puts the mock on window.matchMedia and sets window.innerWidth and window.innerHeight.
  • uninstall() — restores matchMedia and 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, updates window.innerWidth and window.innerHeight, fires change on every query that flipped, and dispatches a resize event, so subscribeViewportSize() and useViewportSize() follow too.
  • setFeature(name, value) — changes a user-preference feature, for example setFeature('prefers-color-scheme', 'dark'), and fires change on 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, height and aspect-ratio, with min- and max- prefixes, orientation, and the range syntax: (width <= 850px), (600px <= width <= 900px).
  • Combinations — and, , (or), not, only, and the media types all, screen and print (print is false unless you set setFeature('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 }) // true

What it does not mock ​

ResizeObserver is not mocked, so container state needs your own stub — see the tests of the package for one.