Automating Unit Tests with Jest for Seamless CI Integration
In modern software development, ensuring code quality and stability is paramount. Continuous Integration (CI) plays a vital role by automatically testing code changes. This challenge focuses on setting up Jest, a popular JavaScript testing framework, for seamless integration into a CI environment, ensuring that all unit tests pass before code is merged.
Problem Description
Your task is to configure a TypeScript project to run its Jest unit tests automatically when changes are pushed to a repository. This involves setting up Jest, writing a few basic tests, and ensuring that these tests execute successfully in a simulated CI environment. The goal is to demonstrate a robust testing setup that can be easily integrated into any CI pipeline (e.g., GitHub Actions, GitLab CI, Jenkins).
Key Requirements:
- Project Setup: Initialize a new TypeScript project with Jest and the necessary dependencies.
- Unit Tests: Write a simple function and create at least two unit tests for it using Jest.
- Jest Configuration: Configure Jest to work effectively with TypeScript (e.g., using
ts-jest). - CI Script: Create a script in
package.jsonthat runs Jest. - Verification: Ensure the script successfully passes when all tests are green and fails when any test fails.
Expected Behavior:
- When the
testscript is executed, Jest should find and run all tests. - If all tests pass, the script should exit with a success code (0).
- If any test fails, the script should exit with a non-zero error code, indicating a failure.
- The output should clearly indicate which tests passed and failed.
Edge Cases to Consider:
- Tests that involve asynchronous operations.
- Tests that might produce different outputs based on subtle variations (ensure assertions are precise).
Examples
Example 1:
Input:
A TypeScript file src/math.ts with the following content:
export function add(a: number, b: number): number {
return a + b;
}
Jest Test File (src/math.test.ts):
import { add } from './math';
describe('add', () => {
test('should return the sum of two positive numbers', () => {
expect(add(2, 3)).toBe(5);
});
test('should return the sum of a positive and a negative number', () => {
expect(add(5, -2)).toBe(3);
});
});
package.json script:
"scripts": {
"test": "jest"
}
Execution:
Running npm run test or yarn test.
Output:
PASS src/math.test.ts
add
✓ should return the sum of two positive numbers (2ms)
✓ should return the sum of a positive and a negative number (1ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.XXXs
Explanation:
The add function is tested with two distinct scenarios. Both tests pass, and Jest reports a successful execution.
Example 2:
Input:
The same src/math.ts as in Example 1, but with a modified test file src/math.test.ts:
import { add } from './math';
describe('add', () => {
test('should return the sum of two positive numbers', () => {
expect(add(2, 3)).toBe(5);
});
test('should return the sum of a positive and a negative number', () => {
expect(add(5, -2)).toBe(3); // This assertion is incorrect
});
test('should handle zero correctly', () => {
expect(add(0, 7)).toBe(7);
});
});
Execution:
Running npm run test or yarn test.
Output:
FAIL src/math.test.ts
add
✓ should return the sum of two positive numbers (2ms)
✕ should return the sum of a positive and a negative number (1ms)
✓ should handle zero correctly (1ms)
● add › should return the sum of a positive and a negative number
expect(received).toBe(expected) // deep equality
Expected: 3
Received: 7
10 | test('should return the sum of a positive and a negative number', () => {
11 | expect(add(5, -2)).toBe(3); // This assertion is incorrect
12 | });
13 |
at src/math.test.ts:11:26
Test Suites: 1 failed, 1 total
Tests: 1 failed, 2 passed, 3 total
Snapshots: 0 total
Time: 0.XXXs
Explanation:
The second test for the add function has an incorrect assertion (expect(add(5, -2)).toBe(3) where add(5, -2) actually returns 3, but the test is written as expect(add(5, -2)).toBe(3) expecting 3 and receiving 3, this example needs to be corrected. Let's assume the incorrect assertion was expect(add(5, -2)).toBe(7).
Correction to Example 2 explanation:
The second test for the add function has an incorrect assertion (expect(add(5, -2)).toBe(7)). The actual result of add(5, -2) is 3, but the test expects 7. Jest detects this mismatch, marks the test as failed, and the overall script exits with a non-zero code.
Constraints
- Node.js Version: Use Node.js version 16 or later.
- Dependencies: Only install essential development dependencies (Jest,
ts-jest,@types/jest, TypeScript). - Project Size: The project should be minimal, focusing solely on the testing setup.
- CI Environment: The solution should be runnable in a standard CI environment without requiring special configurations beyond executing the
testscript.
Notes
- Consider how to handle different types of tests (synchronous, asynchronous).
- Think about how Jest's configuration file (
jest.config.jsorjest.config.ts) can be used to customize behavior for CI. - This challenge is designed to be a foundational step. In real-world CI, you'd typically integrate this into a CI pipeline definition file (e.g.,
.github/workflows/main.yml). For this challenge, simply ensure thenpm run test(oryarn test) command behaves as expected.