From software-development
Jest testing patterns and conventions for TypeScript projects. This skill should be used when the project uses Jest as its test framework — detected via jest in package.json dependencies, jest.config.ts, jest.config.js, or a jest field in package.json. Loaded by the tester-agent when creating or modifying tests in a Jest project.
npx claudepluginhub bartekck/bartek-marketplace --plugin software-developmentThis skill uses the workspace's default tool permissions.
Detect Jest configuration in this order:
Provides Jest best practices for JavaScript/TypeScript tests: structure, mocking, async code, snapshots, React components with RTL, and matchers.
Configures Jest for JavaScript and TypeScript projects including setup files, module resolution, coverage thresholds, transform rules, and project organization for optimal testing.
Generates Jest unit tests for JavaScript/TypeScript modules and React components with mocking, coverage, spies, and snapshots. Use for test creation, missing coverage, or improper mocking.
Share bugs, ideas, or general feedback.
Detect Jest configuration in this order:
jest.config.ts or jest.config.js — standalone configpackage.json — jest fieldpackage.json — jest in dependenciesRead the config to understand: test file patterns, setup files, module name mapping, transform settings, test environment (jsdom for frontend, node for backend).
Jest globals are available without imports by default. If using @jest/globals:
import { describe, it, expect, jest, beforeEach, afterEach } from "@jest/globals";
Check the project's tsconfig.json for "types": ["jest"] and existing test files for the import convention.
const mockFn = jest.fn();
const mockFnTyped = jest.fn<(a: string, b: number) => boolean>();
// Return values
mockFn.mockReturnValue("value");
mockFn.mockResolvedValue({ id: "1" });
mockFn.mockRejectedValue(new Error("fail"));
// Implementation
mockFn.mockImplementation((a, b) => a + b);
// Auto-mock entire module
jest.mock("./userRepository");
// Manual mock with factory
jest.mock("./userRepository", () => ({
UserRepository: jest.fn().mockImplementation(() => ({
findById: jest.fn(),
save: jest.fn(),
})),
}));
Note: Jest hoists jest.mock() calls to the top of the file automatically. Factory functions cannot reference variables defined in the test file unless prefixed with mock:
// This works — variable name starts with "mock"
const mockFindById = jest.fn();
jest.mock("./userRepository", () => ({
UserRepository: jest.fn(() => ({ findById: mockFindById })),
}));
const spy = jest.spyOn(service, "process");
spy.mockResolvedValue(result);
// Verify calls
expect(spy).toHaveBeenCalledWith("arg1");
expect(spy).toHaveBeenCalledTimes(1);
beforeEach(() => {
jest.clearAllMocks(); // Clear call history and results
// or
jest.resetAllMocks(); // Clear + remove implementations
// or
jest.restoreAllMocks(); // Reset + restore originals (for spies)
});
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
it("should debounce", () => {
// Given
const callback = jest.fn();
const debounced = debounce(callback, 300);
// When
debounced();
jest.advanceTimersByTime(300);
// Then
expect(callback).toHaveBeenCalledTimes(1);
});
// Resolved values
it("should fetch user", async () => {
// Given
mockRepo.findById.mockResolvedValue({ id: "1", name: "John" });
// When
const result = await service.getUser("1");
// Then
expect(result).toEqual({ id: "1", name: "John" });
});
// Rejected / error paths
it("should throw on not found", async () => {
// Given
mockRepo.findById.mockResolvedValue(null);
// When / Then
await expect(service.getUser("999")).rejects.toThrow(NotFoundError);
});
Use sparingly — only for complex serializable outputs:
it("should render config", () => {
// Given
const input = { theme: "dark", locale: "en" };
// When
const config = generateConfig(input);
// Then
expect(config).toMatchInlineSnapshot(`
Object {
"theme": "dark",
"locale": "en",
"version": "1.0.0",
}
`);
});
Prefer toMatchInlineSnapshot over toMatchSnapshot for visibility.
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
it("should submit the form", async () => {
// Given
const onSubmit = jest.fn();
const user = userEvent.setup();
render(<LoginForm onSubmit={onSubmit} />);
// When
await user.type(screen.getByLabelText("Email"), "john@example.com");
await user.type(screen.getByLabelText("Password"), "secret123");
await user.click(screen.getByRole("button", { name: "Sign in" }));
// Then
expect(onSubmit).toHaveBeenCalledWith({
email: "john@example.com",
password: "secret123",
});
});
Use userEvent over fireEvent — it simulates real user behavior more accurately.
# Run specific test file
npx jest path/to/file.test.ts
# Run with pattern matching
npx jest --verbose -t "should create user"
# Run in watch mode (development)
npx jest --watch path/to/file.test.ts
# Run with coverage
npx jest --coverage
Jest requires a transform for TypeScript. Common setups:
transform: { "^.+\\.tsx?$": "ts-jest" } — uses the TypeScript compilertransform: { "^.+\\.tsx?$": ["@swc/jest"] } — faster, uses SWC@babel/preset-typescript — strips types only, no type checkingCheck the project's existing transform configuration before writing tests. Match the import style (ESM vs CJS) accordingly.
jest.mock() is hoisted above imports — factory variables must be prefixed with mockclearMocks: true in jest.config to auto-clear between testsjest.isolateModules(() => {}) for tests that need fresh module state__mocks__/ directory next to node_modules/ or next to the mocked file for automatic resolutionbeforeAll/beforeEach callbacks, this is shared within the describe block (rarely used with TypeScript)