š„ React Testing: Mocking Browser APIs and modules
July 26, 2025
1 min
jsdom is a JavaScript implementation of the browser environment that runs in Node.js.
It provides:
document, window, and DOM APIsIt allows you to test UI logic without launching a real browser, making tests:
Here are some APIs that are either missing or partially implemented:
| API | Why Itās a Problem in jsdom |
|---|---|
navigator.geolocation | Not implemented |
window.matchMedia | Not implemented |
window.resizeTo | Not implemented |
HTMLCanvasElement | Limited / missing |
IntersectionObserver | Not implemented |
ResizeObserver | Not implemented |
| Media APIs | No video/audio rendering |
When your component depends on these, tests will fail ā unless you mock them.
matchMediaLetās say you have a hook that uses media queries:
const isMobile = window.matchMedia('(max-width: 768px)').matches
In jsdom, this throws:
ā
TypeError: window.matchMedia is not a function
matchMediabeforeAll(() => {window.matchMedia = jest.fn().mockImplementation(query => ({matches: query.includes('768'),media: query,onchange: null,addListener: jest.fn(),removeListener: jest.fn(),addEventListener: jest.fn(),removeEventListener: jest.fn(),dispatchEvent: jest.fn(),}))})
Now your tests can safely use media queries.
navigator.geolocation.getCurrentPosition(...)
jsdom ā doesnāt support this either.
import { render, screen } from '@testing-library/react'import userEvent from '@testing-library/user-event'import Location from './Location'describe('Location component', () => {beforeEach(() => {const mockGeolocation = {getCurrentPosition: jest.fn(success =>success({coords: { latitude: 10, longitude: 20 },})),}Object.defineProperty(navigator, 'geolocation', {value: mockGeolocation,configurable: true,})})test('displays user location after clicking button', async () => {render(<Location />)await userEvent.click(screen.getByRole('button', { name: /get location/i }))expect(screen.getByText(/lat: 10/i)).toBeInTheDocument()expect(screen.getByText(/lng: 20/i)).toBeInTheDocument()})test('shows error when permission is denied', async () => {navigator.geolocation.getCurrentPosition = jest.fn((_, error) =>error({ message: 'Permission denied' }))render(<Location />)await userEvent.click(screen.getByRole('button', { name: /get location/i }))expect(screen.getByRole('alert')).toHaveTextContent(/permission denied/i)})})