Тестирование
responsive-media/testing заменяет window.matchMedia управляемым вьюпортом, так что тест может менять ширину, переключать пользовательское предпочтение и смотреть, как реагируют ваши компоненты — в Vitest или Jest с jsdom, у которого собственного matchMedia нет.
ts
import { createViewportMock } from 'responsive-media/testing'Мок вьюпорта
createViewportMock(options?)
ViewportMock
Создаёт мок. Пока вы не вызовете 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('следует за вьюпортом', () => {
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· по умолчанию:1280и800. Начальный размер.features—Record<string, string>· по умолчанию: нет. Начальные значения пользовательских предпочтений.
Методы
install()— ставит мок наwindow.matchMediaи задаётwindow.innerWidthиwindow.innerHeight.uninstall()— восстанавливаетmatchMediaи размер окна и возвращает мок к начальному размеру и признакам, так что один мок можно использовать во всех тестах.setViewport({ width?, height? })— меняет размер, обновляетwindow.innerWidthиwindow.innerHeight, вызываетchangeу каждого запроса, который переключился, и отправляет событиеresize, поэтомуsubscribeViewportSize()иuseViewportSize()тоже следуют за размером.setFeature(name, value)— меняет пользовательское предпочтение, напримерsetFeature('prefers-color-scheme', 'dark'), и вызываетchangeу запросов, которые переключились.getViewport()— текущий{ width, height }.
Поддерживаемые запросы
Мок вычисляет media query, которые компонент скорее всего использует:
- Размер —
width,heightиaspect-ratioс префиксамиmin-иmax-,orientationи синтаксис диапазонов:(width <= 850px),(600px <= width <= 900px). - Комбинации —
and,,(или),not,onlyи типыall,screenиprint(printложен, пока вы не задалиsetFeature('media-type', 'print')). - Пользовательские предпочтения —
prefers-color-scheme,prefers-reduced-motion,prefers-contrast,hover,any-hover,pointer,any-pointer,forced-colors,display-modeсо значениями десктопного браузера по умолчанию (светлая тема, без предпочтений,hover: hover,pointer: fine).
evaluateMediaQuery(query, size, features?)
boolean
Сам вычислитель — для быстрой проверки запроса на размере.
ts
import { evaluateMediaQuery } from 'responsive-media/testing'
evaluateMediaQuery('(width <= 850px)', { width: 800, height: 600 }) // trueЧто он не мокает
ResizeObserver не мокается, поэтому состоянию контейнера нужна ваша собственная заглушка — пример есть в тестах самого пакета.