or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli-usage.mdconfiguration.mdindex.mdtest-discovery.mdtest-runner.mdtest-scheduling.md
tile.json

test-scheduling.mddocs/

0

# Test Scheduling

1

2

Jest's test scheduling system manages test execution coordination, multi-process scheduling, reporter management, and comprehensive result aggregation for optimal performance and reporting.

3

4

## Capabilities

5

6

### TestScheduler Class

7

8

The TestScheduler manages test execution scheduling and coordinates with reporters for comprehensive test result processing.

9

10

```typescript { .api }

11

/**

12

* Manages test execution scheduling and reporting

13

*/

14

class TestScheduler {

15

constructor(globalConfig: Config.GlobalConfig, context: TestSchedulerContext);

16

17

/**

18

* Adds a reporter to the dispatcher

19

* @param reporter - Reporter instance to add

20

*/

21

addReporter(reporter: Reporter): void;

22

23

/**

24

* Removes a reporter from the dispatcher

25

* @param reporterConstructor - Constructor of reporter to remove

26

*/

27

removeReporter(reporterConstructor: ReporterConstructor): void;

28

29

/**

30

* Schedules and executes the given tests

31

* @param tests - Array of test files to execute

32

* @param watcher - Test watcher for watch mode integration

33

* @returns Promise resolving to aggregated test results

34

*/

35

scheduleTests(tests: Array<Test>, watcher: TestWatcher): Promise<AggregatedResult>;

36

}

37

38

/**

39

* Factory function that creates a TestScheduler and sets up reporters

40

* @param globalConfig - Global Jest configuration

41

* @param context - Scheduler context including reporter and test runner contexts

42

* @returns Promise resolving to configured test scheduler

43

*/

44

function createTestScheduler(

45

globalConfig: Config.GlobalConfig,

46

context: TestSchedulerContext

47

): Promise<TestScheduler>;

48

49

type TestSchedulerContext = ReporterContext & TestRunnerContext;

50

51

type ReporterConstructor = new (

52

globalConfig: Config.GlobalConfig,

53

reporterConfig: Record<string, unknown>,

54

reporterContext: ReporterContext,

55

) => JestReporter;

56

```

57

58

**Usage Examples:**

59

60

```typescript

61

import { createTestScheduler, SearchSource } from "jest";

62

63

// Create and configure test scheduler

64

async function setupTestScheduler() {

65

const scheduler = await createTestScheduler(globalConfig, {

66

...reporterContext,

67

...testRunnerContext

68

});

69

70

// Add custom reporter

71

scheduler.addReporter(new CustomReporter(globalConfig, {}, reporterContext));

72

73

return scheduler;

74

}

75

76

// Execute tests with scheduler

77

async function executeTests(testFiles: Array<Test>) {

78

const scheduler = await setupTestScheduler();

79

80

const results = await scheduler.scheduleTests(

81

testFiles,

82

new TestWatcher({ isWatchMode: false })

83

);

84

85

return results;

86

}

87

```

88

89

### Test Execution Coordination

90

91

The TestScheduler coordinates test execution across multiple processes and manages the complete test lifecycle.

92

93

**Basic Test Scheduling:**

94

95

```typescript

96

import { createTestScheduler, SearchSource } from "jest";

97

98

async function coordinateTestExecution() {

99

// 1. Discover tests

100

const searchSource = new SearchSource(testContext);

101

const searchResult = await searchSource.getTestPaths(

102

globalConfig,

103

projectConfig

104

);

105

106

// 2. Create scheduler

107

const scheduler = await createTestScheduler(globalConfig, schedulerContext);

108

109

// 3. Schedule and execute tests

110

const results = await scheduler.scheduleTests(

111

searchResult.tests,

112

new TestWatcher({ isWatchMode: false })

113

);

114

115

console.log(`Executed ${results.numTotalTests} tests`);

116

console.log(`Passed: ${results.numPassedTests}`);

117

console.log(`Failed: ${results.numFailedTests}`);

118

119

return results;

120

}

121

```

122

123

### Reporter Management

124

125

Manage test result reporting through dynamic reporter configuration.

126

127

```typescript

128

import { createTestScheduler } from "jest";

129

130

// Custom reporter for specialized output

131

class CustomReporter {

132

constructor(

133

private globalConfig: Config.GlobalConfig,

134

private options: Record<string, unknown>,

135

private context: ReporterContext

136

) {}

137

138

onRunStart(results: AggregatedResult, options: ReporterOnStartOptions) {

139

console.log("Starting test run...");

140

}

141

142

onTestResult(test: Test, testResult: TestResult, results: AggregatedResult) {

143

if (testResult.testResults.some(result => result.status === "failed")) {

144

console.log(`❌ ${test.path}`);

145

} else {

146

console.log(`✅ ${test.path}`);

147

}

148

}

149

150

onRunComplete(contexts: Set<TestContext>, results: AggregatedResult) {

151

console.log(`Test run completed: ${results.success ? "PASSED" : "FAILED"}`);

152

}

153

}

154

155

// Configure scheduler with custom reporters

156

async function setupCustomReporting() {

157

const scheduler = await createTestScheduler(globalConfig, schedulerContext);

158

159

// Add multiple reporters

160

scheduler.addReporter(new CustomReporter(globalConfig, {}, reporterContext));

161

scheduler.addReporter(new JSONReporter(globalConfig, { outputFile: "results.json" }, reporterContext));

162

163

// Remove default reporter if needed

164

scheduler.removeReporter(DefaultReporter);

165

166

return scheduler;

167

}

168

```

169

170

### Multi-Process Coordination

171

172

Handle test execution across multiple worker processes for optimal performance.

173

174

```typescript

175

import { createTestScheduler } from "jest";

176

177

async function scheduleTestsWithWorkers(maxWorkers: number) {

178

const globalConfig = {

179

...baseGlobalConfig,

180

maxWorkers,

181

runInBand: maxWorkers === 1

182

};

183

184

const scheduler = await createTestScheduler(globalConfig, schedulerContext);

185

186

// Configure for multi-process execution

187

const results = await scheduler.scheduleTests(

188

testFiles,

189

new TestWatcher({

190

isWatchMode: false,

191

// Additional options for worker coordination

192

})

193

);

194

195

return results;

196

}

197

198

// Adaptive worker configuration

199

async function adaptiveTestScheduling(testCount: number) {

200

// Determine optimal worker count based on test count and system resources

201

const maxWorkers = Math.min(

202

Math.max(1, Math.floor(testCount / 10)), // At least 10 tests per worker

203

require("os").cpus().length, // Don't exceed CPU count

204

8 // Cap at 8 workers

205

);

206

207

return scheduleTestsWithWorkers(maxWorkers);

208

}

209

```

210

211

### Watch Mode Integration

212

213

Integrate with Jest's watch mode for automatic test re-execution.

214

215

```typescript

216

import { createTestScheduler } from "jest";

217

import { TestWatcher } from "jest-watcher";

218

219

async function scheduleTestsInWatchMode() {

220

const scheduler = await createTestScheduler(

221

{ ...globalConfig, watch: true },

222

schedulerContext

223

);

224

225

const watcher = new TestWatcher({ isWatchMode: true });

226

227

// Watch mode provides automatic re-scheduling

228

const results = await scheduler.scheduleTests(testFiles, watcher);

229

230

// In watch mode, this promise typically never resolves

231

// as Jest continues watching for file changes

232

return results;

233

}

234

235

// Custom watch mode logic

236

class CustomTestWatcher extends TestWatcher {

237

constructor(options: { isWatchMode: boolean }) {

238

super(options);

239

}

240

241

async onChange(changedFiles: Set<string>) {

242

console.log(`Files changed: ${Array.from(changedFiles).join(", ")}`);

243

244

// Custom logic for determining which tests to re-run

245

const searchSource = new SearchSource(testContext);

246

const relatedTests = await searchSource.findRelatedTests(changedFiles, false);

247

248

// Re-schedule only related tests

249

if (relatedTests.tests.length > 0) {

250

await this.scheduler.scheduleTests(relatedTests.tests, this);

251

}

252

}

253

}

254

```

255

256

### Result Aggregation and Processing

257

258

Process and aggregate test results for comprehensive reporting.

259

260

```typescript

261

import { createTestScheduler } from "jest";

262

263

interface TestExecutionMetrics {

264

totalDuration: number;

265

averageTestDuration: number;

266

slowestTests: Array<{ path: string; duration: number }>;

267

fastestTests: Array<{ path: string; duration: number }>;

268

failureRate: number;

269

coveragePercentage?: number;

270

}

271

272

async function executeWithMetrics(tests: Array<Test>): Promise<{

273

results: AggregatedResult;

274

metrics: TestExecutionMetrics;

275

}> {

276

const scheduler = await createTestScheduler(globalConfig, schedulerContext);

277

278

const startTime = Date.now();

279

const results = await scheduler.scheduleTests(

280

tests,

281

new TestWatcher({ isWatchMode: false })

282

);

283

const totalDuration = Date.now() - startTime;

284

285

// Calculate metrics

286

const testDurations = results.testResults

287

.flatMap(suite => suite.testResults)

288

.map(test => ({ path: test.title, duration: test.duration || 0 }))

289

.filter(test => test.duration > 0);

290

291

const averageTestDuration = testDurations.length > 0

292

? testDurations.reduce((sum, test) => sum + test.duration, 0) / testDurations.length

293

: 0;

294

295

const sortedByDuration = testDurations.sort((a, b) => b.duration - a.duration);

296

297

const metrics: TestExecutionMetrics = {

298

totalDuration,

299

averageTestDuration,

300

slowestTests: sortedByDuration.slice(0, 5),

301

fastestTests: sortedByDuration.slice(-5).reverse(),

302

failureRate: results.numTotalTests > 0

303

? results.numFailedTests / results.numTotalTests

304

: 0,

305

coveragePercentage: results.coverageMap

306

? calculateCoveragePercentage(results.coverageMap)

307

: undefined

308

};

309

310

return { results, metrics };

311

}

312

313

function calculateCoveragePercentage(coverageMap: any): number {

314

// Implementation would depend on coverage map structure

315

// This is a simplified example

316

const summary = coverageMap.getCoverageSummary?.();

317

return summary?.lines?.pct || 0;

318

}

319

```

320

321

### Error Handling and Recovery

322

323

Implement robust error handling for test scheduling failures.

324

325

```typescript

326

import { createTestScheduler } from "jest";

327

328

async function robustTestScheduling(tests: Array<Test>) {

329

let scheduler: TestScheduler;

330

331

try {

332

scheduler = await createTestScheduler(globalConfig, schedulerContext);

333

} catch (error) {

334

console.error("Failed to create test scheduler:", error);

335

throw new Error("Test scheduler initialization failed");

336

}

337

338

// Add error reporter

339

scheduler.addReporter(new ErrorTrackingReporter());

340

341

try {

342

const results = await scheduler.scheduleTests(

343

tests,

344

new TestWatcher({ isWatchMode: false })

345

);

346

347

// Check for critical failures

348

if (results.numRuntimeErrorTestSuites > 0) {

349

console.warn(`${results.numRuntimeErrorTestSuites} test suites had runtime errors`);

350

}

351

352

// Handle open handles

353

if (results.openHandles && results.openHandles.length > 0) {

354

console.warn(`${results.openHandles.length} open handles detected`);

355

356

// Optionally force exit

357

if (globalConfig.forceExit) {

358

process.exit(results.success ? 0 : 1);

359

}

360

}

361

362

return results;

363

364

} catch (error) {

365

console.error("Test execution failed:", error);

366

367

// Attempt recovery or cleanup

368

if (error.message.includes("worker")) {

369

console.log("Retrying with single worker...");

370

const fallbackConfig = { ...globalConfig, maxWorkers: 1, runInBand: true };

371

const fallbackScheduler = await createTestScheduler(fallbackConfig, schedulerContext);

372

return fallbackScheduler.scheduleTests(tests, new TestWatcher({ isWatchMode: false }));

373

}

374

375

throw error;

376

}

377

}

378

379

class ErrorTrackingReporter {

380

private errors: Array<{ test: string; error: any }> = [];

381

382

onTestResult(test: Test, testResult: TestResult) {

383

testResult.testResults.forEach(result => {

384

if (result.status === "failed") {

385

this.errors.push({

386

test: `${test.path} > ${result.title}`,

387

error: result.failureMessages

388

});

389

}

390

});

391

}

392

393

onRunComplete() {

394

if (this.errors.length > 0) {

395

console.log("\n=== Test Failures Summary ===");

396

this.errors.forEach(({ test, error }) => {

397

console.log(`\n❌ ${test}`);

398

console.log(error.join("\n"));

399

});

400

}

401

}

402

}

403

```

404

405

### Performance Optimization

406

407

Optimize test scheduling for different scenarios and constraints.

408

409

```typescript

410

import { createTestScheduler } from "jest";

411

412

interface SchedulingStrategy {

413

name: string;

414

configure: (config: Config.GlobalConfig) => Config.GlobalConfig;

415

}

416

417

const schedulingStrategies: Record<string, SchedulingStrategy> = {

418

fast: {

419

name: "Fast Execution",

420

configure: (config) => ({

421

...config,

422

maxWorkers: "100%",

423

cache: true,

424

bail: 1 // Stop on first failure

425

})

426

},

427

428

thorough: {

429

name: "Thorough Testing",

430

configure: (config) => ({

431

...config,

432

maxWorkers: "50%",

433

collectCoverage: true,

434

bail: false

435

})

436

},

437

438

debug: {

439

name: "Debug Mode",

440

configure: (config) => ({

441

...config,

442

maxWorkers: 1,

443

runInBand: true,

444

verbose: true,

445

detectOpenHandles: true

446

})

447

},

448

449

ci: {

450

name: "CI Optimized",

451

configure: (config) => ({

452

...config,

453

ci: true,

454

maxWorkers: "50%",

455

cache: false,

456

collectCoverage: true,

457

coverageReporters: ["text", "lcov"]

458

})

459

}

460

};

461

462

async function scheduleWithStrategy(

463

tests: Array<Test>,

464

strategyName: keyof typeof schedulingStrategies

465

) {

466

const strategy = schedulingStrategies[strategyName];

467

const optimizedConfig = strategy.configure(globalConfig);

468

469

console.log(`Using ${strategy.name} strategy`);

470

471

const scheduler = await createTestScheduler(optimizedConfig, schedulerContext);

472

return scheduler.scheduleTests(

473

tests,

474

new TestWatcher({ isWatchMode: false })

475

);

476

}

477

478

// Auto-select strategy based on environment

479

async function smartScheduling(tests: Array<Test>) {

480

const isCI = process.env.CI === "true";

481

const isDebug = process.env.DEBUG === "true";

482

const testCount = tests.length;

483

484

let strategy: keyof typeof schedulingStrategies;

485

486

if (isDebug) {

487

strategy = "debug";

488

} else if (isCI) {

489

strategy = "ci";

490

} else if (testCount < 10) {

491

strategy = "fast";

492

} else {

493

strategy = "thorough";

494

}

495

496

return scheduleWithStrategy(tests, strategy);

497

}

498

```

499

500

Jest's test scheduling system provides complete control over test execution coordination, enabling optimized performance, comprehensive reporting, and reliable test execution across different environments and use cases.