Home
React
Testing: JSDOM Mocks
Daniel Nguyen
Daniel Nguyen
August 04, 2025
1 min

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 document
  • DOM element creation and manipulation
  • Basic event handling
  • Many standard HTML and DOM interfaces

This allows you to test React components without launching a real browser.

1. What Doesn’t jsdom Fully Support?

jsdom is not a complete browser engine. Some browser APIs are missing or have limited behavior.

APICommon limitation
navigator.geolocationBrowser geolocation is not implemented
window.matchMediaMay be unavailable without a mock
window.resizeToDoes not perform real browser resizing
CanvasLimited support without additional packages
IntersectionObserverRequires a mock in common setups
ResizeObserverRequires a mock in common setups
Audio and videoNo 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.

2. Example: Mock matchMedia

Suppose 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.

3. Example: Mock Geolocation

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.

4. When Should You Use jsdom vs. a Real Browser?

  • jsdom + React Testing Library: Component rendering, user interactions, state updates, and error handling.
  • Playwright or Cypress: Actual browser behavior, layout, responsive rendering, scrolling, media queries, and end-to-end workflows.

Tags

#ReactTesting

Share

Daniel Nguyen

Daniel Nguyen

Frontend Developer

Frontend developer specializing in React, Next.js, and JavaScript. Writing practical guides on modern web development at Dev98.

Expertise

React
Next.js
JavaScript
TypeScript
Python

Social Media

githublinkedinyoutubewebsite

Related Posts

React Testing
Testing: MSW
August 03, 2025
1 min
Dev98

Dev98

React · Next.js · Web development