Hone logo
Hone
Problems

Jest Branch Tracking: Building a Git-Aware Test Runner

In software development, understanding which tests are affected by code changes is crucial for efficient development and reliable releases. This challenge involves creating a custom Jest runner that intelligently tracks which tests to execute based on Git branch history. This will allow developers to run only the tests relevant to their current changes, saving time and improving focus.

Problem Description

Your task is to create a custom Jest runner in TypeScript that leverages Git to determine which tests to execute. When a developer runs tests with this custom runner, it should compare the current branch with a designated "base" branch (e.g., main or master). Only tests that have been modified or are located in files that have been modified since the common ancestor of the two branches should be executed.

Key Requirements:

  1. Branch Comparison: Implement logic to identify the common ancestor between the current branch and a specified base branch.
  2. File Change Detection: Based on the common ancestor, determine which files have been modified on the current branch.
  3. Test Selection: Identify Jest test files (.test.ts, .spec.ts, or similar patterns) that are either directly modified or are located in directories containing modified files.
  4. Custom Jest Runner: Create a Jest configuration that uses your custom runner.
  5. No Test Execution (Initial): For this challenge, the custom runner should identify and log the paths of the tests it would execute, rather than actually executing them. This simplifies the problem to focus on the branch tracking logic.

Expected Behavior:

When invoked with a specific base branch (e.g., main), the runner should output a list of test file paths that are deemed relevant for execution.

Edge Cases to Consider:

  • The repository is a fresh clone with no prior history.
  • The current branch is the same as the base branch.
  • The base branch does not exist.
  • The current branch has diverged significantly from the base branch.
  • Tests are located in nested directories, some of which contain modified files and others don't.

Examples

Example 1:

Assume the following Git history:

  • main: commit A (initial commit) -> commit B (add file1.ts, file2.ts)
  • feature-branch: commit B -> commit C (modify file1.ts, add file3.ts)

And the following Jest test files:

  • src/file1.test.ts
  • src/file2.test.ts
  • utils/file3.spec.ts

Input: Current branch: feature-branch Base branch: main

Output:

Tests to run:
- src/file1.test.ts
- utils/file3.spec.ts

Explanation: commit C modified file1.ts and added file3.ts. file2.ts was not modified on feature-branch. Therefore, src/file1.test.ts and utils/file3.spec.ts are selected. src/file2.test.ts is not.

Example 2:

Assume the following Git history:

  • main: commit X (add src/featureA/featureA.ts)
  • another-feature: commit X -> commit Y (modify src/featureA/featureA.ts, add src/featureA/helper.ts)

And the following Jest test files:

  • src/featureA/featureA.test.ts
  • src/featureB/featureB.test.ts

Input: Current branch: another-feature Base branch: main

Output:

Tests to run:
- src/featureA/featureA.test.ts

Explanation: commit Y modified src/featureA/featureA.ts and added src/featureA/helper.ts. src/featureA/featureA.test.ts is in the same directory as modified files, so it's selected. src/featureB/featureB.test.ts is not affected by any changes and is not selected.

Constraints

  • The solution must be implemented in TypeScript.
  • The solution must use a standard Git command-line interface (CLI) or a reliable Node.js Git library (e.g., simple-git).
  • The logic for determining changed files should be robust and correctly identify modifications between the common ancestor and the current branch tip.
  • The custom runner should be configurable to accept the base branch name as an argument or via environment variable.
  • The number of test files in a typical project could range from a few dozen to several thousand. The process of identifying changed files should be reasonably efficient.

Notes

  • You'll need to interact with Git to get commit history and file changes. Commands like git merge-base and git diff --name-status (or their equivalents in a library) will be very useful.
  • Consider how to map file changes to Jest test files. A simple heuristic is to include a test file if its parent directory or the file itself has been modified.
  • For this challenge, you are not required to execute the tests, only to identify and log them. This means you can focus on the Git interaction and filtering logic.
  • Think about how to integrate this custom runner with Jest. Jest allows specifying a runner in its configuration (jest.config.js).
  • How will you handle cases where the base branch doesn't exist or the current branch is behind the base branch?
Loading editor...
typescript