Files
bun.sh/docs/test/examples/concurrent-test-glob.md
robobun e58a4a7282 feat: add concurrent-test-glob option to bunfig.toml for selective concurrent test execution (#22898)
## Summary

Adds a new `concurrentTestGlob` configuration option to bunfig.toml that
allows test files matching a glob pattern to automatically run with
concurrent test execution enabled. This provides granular control over
which tests run concurrently without modifying test files or using the
global `--concurrent` flag.

## Problem

Currently, enabling concurrent test execution in Bun requires either:
1. Using the `--concurrent` flag (affects ALL tests)
2. Manually adding `test.concurrent()` to individual test functions
(requires modifying test files)

This creates challenges for:
- Large codebases wanting to gradually migrate to concurrent testing
- Projects with mixed test types (unit tests that need isolation vs
integration tests that can run in parallel)
- CI/CD pipelines that want to optimize test execution without code
changes

## Solution

This PR introduces a `concurrentTestGlob` option in bunfig.toml that
automatically enables concurrent execution for test files matching a
specified glob pattern:

```toml
[test]
concurrentTestGlob = "**/concurrent-*.test.ts"
```

### Key Features
-  Non-breaking: Completely opt-in via configuration
-  Flexible: Use glob patterns to target specific test files or
directories
-  Override-friendly: `--concurrent` flag still forces all tests to run
concurrently
-  Zero code changes: No need to modify existing test files

## Implementation Details

### Code Changes
1. Added `concurrent_test_glob` field to `TestOptions` struct
(`src/cli.zig`)
2. Added parsing for `concurrentTestGlob` from bunfig.toml
(`src/bunfig.zig`)
3. Added `concurrent_test_glob` field to `TestRunner`
(`src/bun.js/test/jest.zig`)
4. Implemented `shouldFileRunConcurrently()` method that checks file
paths against the glob pattern
5. Updated test execution logic to apply concurrent mode based on glob
matching (`src/bun.js/test/ScopeFunctions.zig`)

### How It Works
- When a test file is loaded, its path is checked against the configured
glob pattern
- If it matches, all tests in that file run concurrently (as if
`--concurrent` was passed)
- Files not matching the pattern run sequentially as normal
- The `--concurrent` CLI flag overrides this behavior when specified

## Usage Examples

### Basic Usage
```toml
# bunfig.toml
[test]
concurrentTestGlob = "**/integration/*.test.ts"
```

### Multiple Patterns
```toml
[test]
concurrentTestGlob = [
  "**/integration/*.test.ts",
  "**/e2e/*.test.ts", 
  "**/concurrent-*.test.ts"
]
```

### Migration Strategy
Teams can gradually migrate to concurrent testing:
1. Start with integration tests: `"**/integration/*.test.ts"`
2. Add stable unit tests: `"**/fast-*.test.ts"`
3. Eventually migrate most tests except those requiring isolation

## Testing

Added comprehensive test coverage in
`test/cli/test/concurrent-test-glob.test.ts`:
-  Tests matching glob patterns run concurrently (verified via
execution order logging)
-  Tests not matching patterns run sequentially (verified via shared
state and execution order)
-  `--concurrent` flag properly overrides the glob setting
- Tests use file system logging to deterministically verify concurrent
vs sequential execution

## Documentation

Complete documentation added:
- `docs/runtime/bunfig.md` - Configuration reference
- `docs/test/configuration.md` - Test configuration details
- `docs/test/examples/concurrent-test-glob.md` - Comprehensive example
with migration guide

## Performance Considerations

- Glob matching happens once per test file during loading
- Uses Bun's existing `glob.match()` implementation
- Minimal overhead: simple string pattern matching
- Future optimization: Could cache match results per file path

## Breaking Changes

None. This is a fully backward-compatible, opt-in feature.

## Checklist

- [x] Implementation complete and building
- [x] Tests passing
- [x] Documentation updated
- [x] No breaking changes
- [x] Follows existing code patterns

## Related Issues

This addresses common requests for more granular control over concurrent
test execution, particularly for large codebases migrating from other
test runners.

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2025-09-23 23:01:15 -07:00

3.5 KiB

Concurrent Test Glob Example

This example demonstrates how to use the concurrentTestGlob option to selectively run tests concurrently based on file naming patterns.

Project Structure

my-project/
├── bunfig.toml
├── tests/
│   ├── unit/
│   │   ├── math.test.ts          # Sequential
│   │   └── utils.test.ts         # Sequential
│   └── integration/
│       ├── concurrent-api.test.ts     # Concurrent
│       └── concurrent-database.test.ts # Concurrent

Configuration

bunfig.toml

[test]
# Run all test files with "concurrent-" prefix concurrently
concurrentTestGlob = "**/concurrent-*.test.ts"

Test Files

Unit Test (Sequential)

tests/unit/math.test.ts

import { test, expect } from "bun:test";

// These tests run sequentially by default
// Good for tests that share state or have specific ordering requirements
let sharedState = 0;

test("addition", () => {
  sharedState = 5 + 3;
  expect(sharedState).toBe(8);
});

test("uses previous state", () => {
  // This test depends on the previous test's state
  expect(sharedState).toBe(8);
});

Integration Test (Concurrent)

tests/integration/concurrent-api.test.ts

import { test, expect } from "bun:test";

// These tests automatically run concurrently due to filename matching the glob pattern.
// Using test() is equivalent to test.concurrent() when the file matches concurrentTestGlob.
// Each test is independent and can run in parallel.

test("fetch user data", async () => {
  const response = await fetch("/api/user/1");
  expect(response.ok).toBe(true);
});

test("fetch posts", async () => {
  const response = await fetch("/api/posts");
  expect(response.ok).toBe(true);
});

test("fetch comments", async () => {
  const response = await fetch("/api/comments");
  expect(response.ok).toBe(true);
});

Running Tests

# Run all tests - concurrent-*.test.ts files will run concurrently
bun test

# Override: Force ALL tests to run concurrently
# Note: This overrides bunfig.toml and runs all tests concurrently, regardless of glob
bun test --concurrent

# Run only unit tests (sequential)
bun test tests/unit

# Run only integration tests (concurrent due to glob pattern)
bun test tests/integration

Benefits

  1. Gradual Migration: Migrate to concurrent tests file by file by renaming them
  2. Clear Organization: File naming convention indicates execution mode
  3. Performance: Integration tests run faster in parallel
  4. Safety: Unit tests remain sequential where needed
  5. Flexibility: Easy to change execution mode by renaming files

Migration Strategy

To migrate existing tests to concurrent execution:

  1. Start with independent integration tests
  2. Rename files to match the glob pattern: mv api.test.ts concurrent-api.test.ts
  3. Verify tests still pass
  4. Monitor for race conditions or shared state issues
  5. Continue migrating stable tests incrementally

Tips

  • Use descriptive prefixes: concurrent-, parallel-, async-
  • Keep related sequential tests together
  • Document why certain tests must remain sequential
  • Use test.concurrent() for fine-grained control in sequential files (In files matched by concurrentTestGlob, plain test() already runs concurrently)
  • Consider separate globs for different test types:
[test]
# Multiple patterns for different test categories
concurrentTestGlob = [
  "**/integration/*.test.ts",
  "**/e2e/*.test.ts",
  "**/concurrent-*.test.ts"
]