Some links for reference:
https://www.atlassian.com/continuous-delivery/software-testing/types-of-software-testing
What is Jest?
Installation
npm install --save-dev jest
yarn add --dev jest
Basic Test
Create a test file (e.g., sum.test.js
):
// sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
// sum.test.js
const sum = require("./sum");
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe(3);
});
Running Tests
npm test
or
yarn test
toBe(value)
- Checks for exact equality.toEqual(value)
- Checks for deep equality.Mocking
const mockFn = jest.fn();
mockFn("arg1");
expect(mockFn).toHaveBeenCalledWith("arg1");
Setup and Teardown
Use beforeEach
, afterEach
, beforeAll
, afterAll
to run code before/after tests:
beforeEach(() => {
// Code to run before each test
});
afterEach(() => {
// Code to run after each test
});
Asynchronous Testing
done
callback or async/await
for async code:
test("async test", async () => {
const data = await fetchData();
expect(data).toBe("expectedData");
});
Snapshot Testing
Capture a snapshot of a component’s output and compare it to future snapshots:
import renderer from "react-test-renderer";
import MyComponent from "./MyComponent";
test("renders correctly", () => {
const tree = renderer.create(<MyComponent />).toJSON();
expect(tree).toMatchSnapshot();
});
Coverage Reporting
npm test -- --coverage
or
yarn test --coverage
Custom Matchers
Extend Jest with custom matchers to assert more complex conditions:
expect.extend({
toBeEven(received) {
const pass = received % 2 === 0;
if (pass) {
return {
message: () => `${received} is even`,
pass: true,
};
}
return {
message: () => `${received} is not even`,
pass: false,
};
},
});
test("number is even", () => {
expect(4).toBeEven();
});
Test Hooks
Use beforeEach
, afterEach
, beforeAll
, afterAll
for setup/teardown of tests. They can be asynchronous:
beforeAll(async () => {
await setupDatabase();
});
afterAll(async () => {
await cleanupDatabase();
});
Parameterized Tests
test.each
for running the same test with different data:
test.each([
[1, 2, 3],
[4, 5, 9],
])("sum of %i and %i is %i", (a, b, expected) => {
expect(sum(a, b)).toBe(expected);
});
Manual Mocks
__mocks__
directory to manually mock modules:
// __mocks__/module.js
module.exports = {
myFunction: jest.fn(() => "mocked value"),
};
Test Isolation
Additional Jest concepts not covered in the notes:
Testing React Components
Use @testing-library/react
to render and interact with components:
npm install --save-dev @testing-library/react
import { render, screen } from "@testing-library/react";
import MyComponent from "./MyComponent";
test("renders component", () => {
render(<MyComponent />);
expect(screen.getByText("Hello, World!")).toBeInTheDocument();
});
Mocking Modules
Mock entire modules to control their behavior in tests:
jest.mock("axios");
import axios from "axios";
axios.get.mockResolvedValue({ data: "mocked data" });
test("fetches data", async () => {
const data = await fetchData();
expect(data).toBe("mocked data");
});
Timers and Time Mocks
Control timers in tests with jest.useFakeTimers()
:
jest.useFakeTimers();
test("delays execution", () => {
const callback = jest.fn();
setTimeout(callback, 1000);
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
});
Spies
jest.spyOn
to spy on functions without completely mocking them:
const myFunction = jest.spyOn(obj, "method");
obj.method();
expect(myFunction).toHaveBeenCalled();
Parallel and Sequential Test Execution
--runInBand
:
npm test -- --runInBand
Mocking Implementations
const mockFn = jest.fn().mockImplementation(() => "mocked return");
expect(mockFn()).toBe("mocked return");
ES Modules and Jest
"type": "module"
in package.json
and adjusting Jest settings:
{
"jest": {
"transform": {}
}
}
Handling Errors in Tests
Use toThrow
to test if a function throws an error:
function throwError() {
throw new Error("Test error");
}
test("throws an error", () => {
expect(() => throwError()).toThrow("Test error");
});
Testing with Enzyme (Legacy)
If you’re working with older React projects, you might encounter Enzyme. Install and use it for component testing:
npm install --save-dev enzyme enzyme-adapter-react-16
import { shallow } from "enzyme";
import MyComponent from "./MyComponent";
test("renders without crashing", () => {
shallow(<MyComponent />);
});
Environment Variables
Use process.env
to test code that relies on environment variables:
process.env.API_URL = "http://mockapi.com";
test("uses API URL", () => {
expect(getApiUrl()).toBe("http://mockapi.com");
});
Running Only Specific Tests
Use .only
to run a single test or group of tests:
test.only("this is the only test that will run", () => {
// Test code here
});
describe.only("only this group will run", () => {
// Grouped test cases here
});
Skipping Tests
Use .skip
to skip specific tests or groups of tests:
test.skip("this test will be skipped", () => {
// Test code here
});
describe.skip("this group of tests will be skipped", () => {
// Grouped test cases here
});
Debugging Tests
test.only
with console.log
statements or debugger
to isolate and debug tests.Custom Test Environment
module.exports = {
testEnvironment: "node",
};
Watch Mode
npm test -- --watch
Test Retry
test.retry(3)("test with retry", () => {
// Test code here
});