Hone logo
Hone
Problems

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:

  1. Project Setup: Initialize a new TypeScript project with Jest and the necessary dependencies.
  2. Unit Tests: Write a simple function and create at least two unit tests for it using Jest.
  3. Jest Configuration: Configure Jest to work effectively with TypeScript (e.g., using ts-jest).
  4. CI Script: Create a script in package.json that runs Jest.
  5. Verification: Ensure the script successfully passes when all tests are green and fails when any test fails.

Expected Behavior:

  • When the test script 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 test script.

Notes

  • Consider how to handle different types of tests (synchronous, asynchronous).
  • Think about how Jest's configuration file (jest.config.js or jest.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 the npm run test (or yarn test) command behaves as expected.
Loading editor...
typescript