diff --git a/tests/Features/Tia/DefaultBranchReplay.php b/tests/Features/Tia/DefaultBranchReplay.php index e6c5efb4..4a3b6d3d 100644 --- a/tests/Features/Tia/DefaultBranchReplay.php +++ b/tests/Features/Tia/DefaultBranchReplay.php @@ -78,6 +78,38 @@ test('replays on a branch whose name contains slashes', function (): void { ->and($project->branchKeys())->toContain('feature/x/y'); })->skipOnWindows(); +test('replays again once back on the default branch', function (): void { + $project = Project::make('master'); + $project->seed('master'); + + $project->git()->switchTo('feature-x', new: true); + $project->pest('--tia'); + + $project->git()->switchTo('master'); + + $project->snapshot(); + $result = $project->pest('--tia'); + $delta = $project->delta(); + + expect($result->replayed())->toBe(Project::TOTAL_TESTS, $result->describe()) + ->and($result->uncached())->toBe(0, $result->describe()) + ->and($delta->writtenCount())->toBe(0, $delta->summary()) + ->and($delta->isResultsOnly())->toBeTrue($delta->summary()); +})->skipOnWindows(); + +test('replays on a new branch when tia is enabled by configuration', function (): void { + $project = Project::make('master', overlay: 'always-enabled'); + $project->seed('master'); + + $project->git()->switchTo('feature-x', new: true); + + $result = $project->pest(); + + expect($result->replayed())->toBe(Project::TOTAL_TESTS, $result->describe()) + ->and($result->uncached())->toBe(0, $result->describe()) + ->and($project->branchKeys())->toBe(['master', 'feature-x']); +})->skipOnWindows(); + test('replays inside a worktree on a new branch', function (): void { $project = Project::make('master'); $worktree = $project->worktree('feature-worktree'); diff --git a/tests/Features/Tia/DefaultBranchResolution.php b/tests/Features/Tia/DefaultBranchResolution.php index 7a17aa8a..b30485b2 100644 --- a/tests/Features/Tia/DefaultBranchResolution.php +++ b/tests/Features/Tia/DefaultBranchResolution.php @@ -34,6 +34,22 @@ test('a declared default branch that does not exist degrades to a full run', fun ->and($project->branchKeys())->toBe(['master', 'feature-x']); })->skipOnWindows(); +test('a renamed default branch replays and writes under its new name', function (): void { + $project = Project::make('master'); + $project->seed('master'); + + $project->git()->rename('master', 'main'); + + $result = $project->pest('--tia'); + $delta = $project->delta(); + + expect($result->replayed())->toBe(Project::TOTAL_TESTS, $result->describe()) + ->and($result->uncached())->toBe(0, $result->describe()) + ->and($project->branchKeys())->toBe(['master', 'main']) + ->and($delta->baselineUntouched('master'))->toBeTrue($delta->summary()) + ->and($delta->writtenCount())->toBe(0, $delta->summary()); +})->skipOnWindows(); + test('the CI provider names the default branch where the checkout cannot', function (): void { $project = Project::make('master'); $project->git()->unsetOriginHead(); diff --git a/tests/Features/Tia/DefaultBranchWriteTier.php b/tests/Features/Tia/DefaultBranchWriteTier.php index 28f56020..dee41d6b 100644 --- a/tests/Features/Tia/DefaultBranchWriteTier.php +++ b/tests/Features/Tia/DefaultBranchWriteTier.php @@ -75,6 +75,40 @@ test('filtered mode finds nothing to do on a clean green feature branch', functi ->and($delta->isHardSuppressed())->toBeTrue($delta->summary()); })->skipOnWindows(); +test('filtered mode falls back to a full replay when a cached failure cannot be located', function (): void { + $project = Project::make('master'); + + $project->seed('master', failing: ['adds two numbers']); + + $project->mutateGraph(function (array $graph): array { + $testId = Project::testId('tests/Unit/CalculatorTest.php', 'adds two numbers'); + + $graph['baselines']['master']['results'][$testId]['file'] = 'tests/Unit/DeletedTest.php'; + + return $graph; + }); + + $project->git()->switchTo('feature-x', new: true); + + $result = $project->pest('--tia', '--filtered'); + + expect($result->output)->toContain('Some cached tests due a re-run could not be located on disk.') + ->and($result->output)->toContain('Running the full suite with replay instead of a filtered run.') + ->and($result->output)->not->toContain('No affected tests found'); +})->skipOnWindows(); + +test('filtered mode finds nothing to do on the default branch itself', function (): void { + $project = Project::make('master'); + $project->seed('master'); + + $result = $project->pest('--tia', '--filtered'); + $delta = $project->delta(); + + expect($result->output)->toContain('No affected tests found') + ->and($result->exitCode)->toBe(0, $result->describe()) + ->and($delta->isHardSuppressed())->toBeTrue($delta->summary()); +})->skipOnWindows(); + test('a detached HEAD replays without minting a branch key', function (): void { $project = Project::make('master'); $project->seed('master'); diff --git a/tests/Fixtures/Tia/Project.php b/tests/Fixtures/Tia/Project.php index 04b5ff3b..e5d80bc2 100644 --- a/tests/Fixtures/Tia/Project.php +++ b/tests/Fixtures/Tia/Project.php @@ -243,24 +243,34 @@ final class Project } public function sentinel(): void + { + $this->mutateGraph(function (array $graph): array { + foreach ($graph['baselines'] ?? [] as $branch => $baseline) { + foreach (array_keys($baseline['results'] ?? []) as $testId) { + $graph['baselines'][$branch]['results'][$testId]['time'] = 9.999; + + if ((int) ($baseline['results'][$testId]['assertions'] ?? 0) > 0) { + $graph['baselines'][$branch]['results'][$testId]['assertions'] = 42; + } + } + } + + return $graph; + }); + } + + /** + * @param callable(array): array $callback + */ + public function mutateGraph(callable $callback): void { $graph = $this->graph(); if ($graph === null) { - throw new RuntimeException('There is no graph to sentinel.'); + throw new RuntimeException('There is no graph to mutate.'); } - foreach ($graph['baselines'] ?? [] as $branch => $baseline) { - foreach (array_keys($baseline['results'] ?? []) as $testId) { - $graph['baselines'][$branch]['results'][$testId]['time'] = 9.999; - - if ((int) ($baseline['results'][$testId]['assertions'] ?? 0) > 0) { - $graph['baselines'][$branch]['results'][$testId]['assertions'] = 42; - } - } - } - - $this->state()->write(Tia::KEY_GRAPH, (string) json_encode($graph, JSON_UNESCAPED_SLASHES)); + $this->state()->write(Tia::KEY_GRAPH, (string) json_encode($callback($graph), JSON_UNESCAPED_SLASHES)); $this->snapshot(); } diff --git a/tests/Fixtures/Tia/overlays/always-enabled/tests/Pest.php b/tests/Fixtures/Tia/overlays/always-enabled/tests/Pest.php new file mode 100644 index 00000000..7fc02891 --- /dev/null +++ b/tests/Fixtures/Tia/overlays/always-enabled/tests/Pest.php @@ -0,0 +1,8 @@ +tia()->always();