Using Jest for Front-End Unit Testing and Coverage
The article explains how to set up Jest for front‑end unit testing, demonstrates basic test writing, async handling, hooks, snapshot and React component testing, shows coverage configuration and thresholds, compares Jest’s built‑in features to Mocha’s limitations, and offers tips on concurrency, mocking, and test‑driven development.
This article introduces how to use Jest for front‑end unit testing, how to collect test coverage, and compares Jest with Mocha.
What is Jest?
Jest is a delightful JavaScript testing framework focused on simplicity.
According to the official description, Jest is an out‑of‑the‑box testing framework that includes the Expect assertion API, mock utilities, snapshot testing, coverage collection, and other full‑stack testing features.
Why is Mocha not recommended?
No native parallel testing support.
Separate installation required for an assertion library.
Coverage collection must be installed separately.
Raw test reports have poor readability and need extra formatting.
No built‑in snapshot support; third‑party plugins are needed.
Using Mocha often requires installing many third‑party modules, which is cumbersome and error‑prone. By contrast, a single command
npm install -D jest installs Jest and enables quick test authoring.
Basic Jest Usage
Integrating Jest into a Project
Install Jest and its type definitions (useful for IDEs such as WebStorm):
npm install -D jest @types/jestCreate a jest.config.js file in the project root (refer to the official docs for configuration).
Add test scripts to package.json :
{
"scripts": {
"test": "jest",
"test-debug": "node --inspect-brk node_modules/jest/bin/jest.js --runInBand"
}
}Run tests with:
npm run jest
A Simple Test Example
Assume a file common/url.js exports two functions parse(url:string) and getParameter(url:string) . A Jest test could look like:
const url = require("./common/url.js");
describe("url.parse", () => {
test("parse a normal URL", () => {
const uri = url.parse("http://kg.qq.com/a/b.html?c=1&d=%2F");
expect(uri.protocol).toBe("http:");
expect(uri.hostname).toBe("kg.qq.com");
// ...
});
test("parse URL with hash", () => {/* ... */});
test("parse URL fragment", () => {/* ... */});
});
describe("url.getParameter", () => {
test("extract query param from URL", () => {
expect(url.getParameter("test", "?test=hash-test")).toBe("hash-test");
// ...
});
// additional test cases ...
});The describe() function groups related tests, while test() defines individual test cases.
url.parse supports: Parsing a normal URL. Parsing a URL with a hash. Parsing a URL fragment.
url.getParameter supports: Getting a query parameter from a specified URL. Getting a query parameter from the browser address. Handling empty parameters. Ensuring the value is decoded.
WebStorm’s test runner displays clear grouping:
Common Expect Assertions
Jest includes the built‑in Expect library. Some frequently used matchers:
expect(1).toBe(1); // passes
expect({}).toBe({}); // fails because objects are not the same referencetoStrictEqual performs deep structural comparison:
expect({}).toStrictEqual({}); // passes
expect({ person: { name: "shanelv" } }).toStrictEqual({ person: { name: "shanelv" } }); // passestoThrow verifies that a function throws an error:
function fetchUserInfo(uid) {
if (!uid) {
throw new Error("require uid!");
}
// ...
}
test('missing uid throws', () => {
expect(() => { fetchUserInfo(); }).toThrow();
});Note: The function must be wrapped in another function so Jest can catch the thrown error.
Asynchronous and Timeout Handling
Jest supports both callback‑based and Promise‑based async tests.
Callback example:
const fs = require("fs");
test("callback file read/write", (done) => {
fs.writeFileSync("./test.txt", "123456");
fs.readFile("./test.txt", (err, data) => {
expect(data.toString()).toBe("123456");
done();
});
});Promise/async‑await example:
const fs = require("fs");
const util = require("util");
const writeFile = util.promisify(fs.writeFile);
const readFile = util.promisify(fs.readFile);
test("promise file read/write", async () => {
await writeFile("./test.txt", "333");
let data = await readFile("./test.txt");
expect(data.toString()).toBe("333");
});Jest’s default async timeout is 5 seconds. It can be changed with jest.setTimeout :
test("timeout example", async () => {
jest.setTimeout(1000);
await sleep(2000); // will fail after 1 s
expect(1).toBe(1);
});Increasing the timeout to 3 seconds makes the test pass:
test("increase timeout", async () => {
jest.setTimeout(3000);
await sleep(2000);
expect(1).toBe(1);
});Hooks and Scopes
Repeated setup/teardown logic can be placed in hooks such as afterEach , beforeEach , beforeAll , and afterAll . Hooks apply only to the test suite (or nested suite) they are defined in.
global.platform = {};
function setGlobalPlatform(key, value) { global.platform[key] = value; }
describe("platform", () => {
afterEach(() => { global.platform = {}; console.log("reset platform!"); });
test("set iOS platform", () => {
setGlobalPlatform("ios", true);
expect(global.platform).toStrictEqual({ ios: true });
});
test("set web platform to undefined", () => {
setGlobalPlatform("web");
expect(global.platform).toStrictEqual({ web: global.undefined });
});
});Reasonable Use of Snapshots
Jest snapshots capture complex structures (React VDOM, file contents, HTML, AST, API responses) for later comparison. They are stored under __snapshots__ .
expect(generateAst("./test.jce")).toMatchSnapshot("AST of test.jce");Update snapshots with:
npm run jest -- --updateSnapshot
# or
npm run jest -- -uBe cautious: indiscriminate snapshot updates can hide real regressions.
Inline Snapshots
Inline snapshots embed the snapshot directly in the test file:
expect({ name: "shanelv" }).toMatchInlineSnapshot();
// after running Jest, the test becomes:
expect({ name: "shanelv" }).toMatchInlineSnapshot(`
Object {
"name": "shanelv",
}
`);Because --updateSnapshot also rewrites inline snapshots, it is recommended to generate an inline snapshot once, then replace it with a strict equality check ( toStrictEqual ).
When Not to Use Snapshots
Explicit functional tests should use direct assertions instead of snapshots, e.g., testing that setName changes the name property:
test("setName changes name", () => {
let person = new Person({ name: "lxj", job: "web" });
person.setName("shanelv");
expect(person.name).toBe("shanelv");
});Small data structures are better verified with toStrictEqual rather than snapshots.
Testing React Components with Jest
Install react-test-renderer to render components to plain JavaScript objects:
npm install -D react-test-rendererExample:
const renderer = require("react-test-renderer");
test("render React component", () => {
let renderInstance = renderer.create(
hello Jest
);
let nodeJson = renderInstance.toJSON();
expect(nodeJson.type).toBe("div");
expect(nodeJson.children[0]).toBe("hello Jest");
});When testing components that depend on Redux state, initialize the store and dispatch actions before rendering.
Test Coverage Reporting
Enable coverage collection in jest.config.js :
module.exports = {
collectCoverage: true,
};Running Jest will generate a coverage folder with an index.html report.
Targeted Coverage
To enforce 100 % coverage on specific files, list them in collectCoverageFrom and set thresholds:
let coverTestFiles = [
"library/client-side/cookie.js",
"library/client-side/url.js",
"library/h5-side/components/lazy.js",
];
module.exports = {
collectCoverage: true,
collectCoverageFrom: coverTestFiles,
coverageThreshold: coverTestFiles.reduce((obj, file) => {
obj[file] = { statements: 100, branches: 100 };
return obj;
}, {}),
};If any of these files fall below 100 % coverage, Jest will fail the test run.
Skipping Specific Lines
Use Istanbul comments to ignore particular branches:
/* istanbul ignore else */
if (isNaN(value)) {
// ...
} else {
// ...
}
/* istanbul ignore if */
if (isNaN(value)) {
// ...
}Jest Concurrency Considerations
Jest runs tests in parallel by default. For debugging with node‑inspect , add --runInBand to run tests sequentially:
{
"scripts": {
"test-debug": "node --inspect-brk node_modules/jest/bin/jest.js --runInBand"
}
}When tests share external resources (files, databases, etc.), ensure isolation, e.g., use distinct temporary file names for each test.
Other Jest Features
Mock functions – capture calls, define implementations.
Mock modules – automatic or custom mocks.
Unit Testing in Development
Writing unit tests first (test‑driven development) helps define expected behavior, reduces rework, and allows code reviews to focus on test coverage rather than code style.
Tencent Music Tech Team
Public account of Tencent Music's development team, focusing on technology sharing and communication.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.