jsdom is a JavaScript implementation of many web standards that provides a browser-like DOM environment inside Node.js.
It supports APIs such as:
window and documentThis allows you to test React components without launching a real browser.
jsdom is not a complete browser engine. Some browser APIs are missing or have limited behavior.
| API | Common limitation |
|---|---|
navigator.geolocation | Browser geolocation is not implemented |
window.matchMedia | May be unavailable without a mock |
window.resizeTo | Does not perform real browser resizing |
| Canvas | Limited support without additional packages |
IntersectionObserver | Requires a mock in common setups |
ResizeObserver | Requires a mock in common setups |
| Audio and video | No real media playback or rendering |
When a component depends on these APIs, mock them or use a real-browser testing tool when actual browser behavior matters.
matchMediaSuppose a component uses a media query:
const isMobile = window.matchMedia("(max-width: 768px)").matches;
If matchMedia is unavailable, the test fails with:
TypeError: window.matchMedia is not a function
For Jest, you can provide a mock:
beforeAll(() => {Object.defineProperty(window, "matchMedia", {writable: true,value: jest.fn().mockImplementation(query => ({matches: false,media: query,onchange: null,addListener: jest.fn(),removeListener: jest.fn(),addEventListener: jest.fn(),removeEventListener: jest.fn(),dispatchEvent: jest.fn(),})),});});
This supplies the expected API shape. Set matches to true or false in individual tests to verify different responsive behaviors.
Note: This mock does not simulate viewport changes or automatically notify listeners.
Consider a component that retrieves the user’s location when a button is clicked.
import { useState } from "react";export default function Location() {const [location, setLocation] = useState(null);const [error, setError] = useState("");function getLocation() {navigator.geolocation.getCurrentPosition(position => {setLocation({lat: position.coords.latitude,lng: position.coords.longitude,});},error => {setError(error.message);});}return (<div><button onClick={getLocation}>Get location</button>{location && (<p>Lat: {location.lat}, Lng: {location.lng}</p>)}{error && <p role="alert">{error}</p>}</div>);}
Since jsdom doesn’t provide real geolocation, mock the API in your tests.
Test successful location retrieval
import { beforeEach, expect, jest, test } from "@jest/globals";import { render, screen } from "@testing-library/react";import userEvent from "@testing-library/user-event";import Location from "./Location";const mockGetCurrentPosition = jest.fn();beforeEach(() => {mockGetCurrentPosition.mockReset();Object.defineProperty(navigator, "geolocation", {configurable: true,value: {getCurrentPosition: mockGetCurrentPosition,},});});test("displays the user's location", async () => {mockGetCurrentPosition.mockImplementation(success => {success({coords: {latitude: 10,longitude: 20,},});});const user = userEvent.setup();render(<Location />);await user.click(screen.getByRole("button", { name: /get location/i }));expect(screen.getByText(/lat: 10/i)).toBeInTheDocument();expect(screen.getByText(/lng: 20/i)).toBeInTheDocument();});
Test permission denial
test("displays an error when location access is denied", async () => {mockGetCurrentPosition.mockImplementation((success, error) => {error({code: 1,message: "Permission denied",});});const user = userEvent.setup();render(<Location />);await user.click(screen.getByRole("button", { name: /get location/i }));expect(screen.getByRole("alert")).toHaveTextContent(/permission denied/i);});
These tests verify how the component responds to success and failure without requiring actual device permissions or GPS access.