This commit is contained in:
nuno maduro
2026-04-22 09:03:10 -07:00
parent 660b57b365
commit d9c18f9c02
4 changed files with 72 additions and 41 deletions

View File

@ -238,6 +238,44 @@ trait Testable
$this->__cachedPass = false;
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
$description = $method->description;
if ($this->dataName()) {
$description = str_contains((string) $description, ':dataset')
? str_replace(':dataset', str_replace('dataset ', '', $this->dataName()), (string) $description)
: $description.' with '.$this->dataName();
}
$description = htmlspecialchars(html_entity_decode((string) $description), ENT_NOQUOTES);
if ($method->repetitions > 1) {
$matches = [];
preg_match('/\((.*?)\)/', $description, $matches);
if (count($matches) > 1) {
if (str_contains($description, 'with '.$matches[0].' /')) {
$description = str_replace('with '.$matches[0].' /', '', $description);
} else {
$description = str_replace('with '.$matches[0], '', $description);
}
}
$description .= ' @ repetition '.($matches[1].' of '.$method->repetitions);
}
$this->__description = self::$__latestDescription = $description;
self::$__latestAssignees = $method->assignees;
self::$__latestNotes = $method->notes;
self::$__latestIssues = $method->issues;
self::$__latestPrs = $method->prs;
// TIA replay short-circuit. Runs AFTER dataset/description/
// assignee metadata is populated so output and filtering still
// see the correct test name + tags on a cache hit, but BEFORE
// `parent::setUp()` and `beforeEach` so we skip the user's
// fixture setup (which is the whole point of replay — avoid
// paying for work whose outcome we already know).
/** @var Tia $tia */
$tia = Container::getInstance()->get(Tia::class);
$cached = $tia->getCachedResult(self::$__filename, $this::class.'::'.$this->name());
@ -275,38 +313,6 @@ trait Testable
throw new AssertionFailedError($cached->message() ?: 'Cached failure');
}
$method = TestSuite::getInstance()->tests->get(self::$__filename)->getMethod($this->name());
$description = $method->description;
if ($this->dataName()) {
$description = str_contains((string) $description, ':dataset')
? str_replace(':dataset', str_replace('dataset ', '', $this->dataName()), (string) $description)
: $description.' with '.$this->dataName();
}
$description = htmlspecialchars(html_entity_decode((string) $description), ENT_NOQUOTES);
if ($method->repetitions > 1) {
$matches = [];
preg_match('/\((.*?)\)/', $description, $matches);
if (count($matches) > 1) {
if (str_contains($description, 'with '.$matches[0].' /')) {
$description = str_replace('with '.$matches[0].' /', '', $description);
} else {
$description = str_replace('with '.$matches[0], '', $description);
}
}
$description .= ' @ repetition '.($matches[1].' of '.$method->repetitions);
}
$this->__description = self::$__latestDescription = $description;
self::$__latestAssignees = $method->assignees;
self::$__latestNotes = $method->notes;
self::$__latestIssues = $method->issues;
self::$__latestPrs = $method->prs;
parent::setUp();
$beforeEach = TestSuite::getInstance()->beforeEach->get(self::$__filename)[1];

View File

@ -72,7 +72,13 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
private const string OPTION = '--tia';
private const string REBUILD_OPTION = '--tia-rebuild';
/**
* Discards any existing graph and re-records from scratch. Meant to
* be combined with `--tia`; the flag is shared with the rest of Pest
* (no `tia-` prefix) so a single `--tia --fresh` reads naturally as
* "TIA, fresh start".
*/
private const string FRESH_OPTION = '--fresh';
/**
* Bypasses `BaselineSync`'s post-failure cooldown. After a failed
@ -331,15 +337,22 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
$replayingGlobal = $isWorker && (string) Parallel::getGlobal(self::REPLAYING_GLOBAL) === '1';
$enabled = $this->hasArgument(self::OPTION, $arguments);
$forceRebuild = $this->hasArgument(self::REBUILD_OPTION, $arguments);
$freshRequested = $this->hasArgument(self::FRESH_OPTION, $arguments);
$this->forceRefetch = $this->hasArgument(self::REFETCH_OPTION, $arguments);
if (! $enabled && ! $forceRebuild && ! $this->forceRefetch && ! $recordingGlobal && ! $replayingGlobal) {
// `--fresh` only takes effect alongside `--tia` (or from a
// worker that's already in TIA mode). Without `--tia`, Pest
// users could be passing `--fresh` to an unrelated plugin —
// silently ignore it here and let whatever else consumes it
// handle it. The flag isn't popped in that branch.
$forceRebuild = $freshRequested && ($enabled || $recordingGlobal || $replayingGlobal);
if (! $enabled && ! $this->forceRefetch && ! $recordingGlobal && ! $replayingGlobal) {
return $arguments;
}
$arguments = $this->popArgument(self::OPTION, $arguments);
$arguments = $this->popArgument(self::REBUILD_OPTION, $arguments);
$arguments = $this->popArgument(self::FRESH_OPTION, $arguments);
$arguments = $this->popArgument(self::REFETCH_OPTION, $arguments);
// When `--coverage` is active, piggyback on PHPUnit's CodeCoverage
@ -1141,6 +1154,18 @@ final class Tia implements AddsOutput, HandlesArguments, Terminable
private function registerRecap(): void
{
DefaultPrinter::addRecap(function (): string {
// Parallel mode: worker replays live in other processes and
// flushed their counters to disk on terminate. Collision's
// `writeRecap` fires inside `ExecutionFinished`, which is
// strictly before `addOutput` — so we must merge right here
// or the fragment below would read 0 and the suffix would
// silently disappear on `--tia --parallel`. The merge is
// idempotent: partial keys are deleted on read, so the
// later `addOutput` call becomes a no-op.
if (Parallel::isEnabled() && ! Parallel::isWorker()) {
$this->mergeWorkerReplayPartials();
}
$fragments = [];
if ($this->executedCount > 0) {

View File

@ -21,7 +21,7 @@ use Pest\Plugins\Tia\Storage;
*
* The guard engages only when ALL of these hold:
* 1. `--tia` is present in argv.
* 2. No `--tia-rebuild` flag (forced record always drives the coverage
* 2. No `--fresh` flag (forced record always drives the coverage
* driver; dropping Xdebug would break the recording).
* 3. No `--coverage*` flag (coverage runs need the driver regardless).
* 4. A valid graph already exists on disk AND its structural fingerprint
@ -117,7 +117,7 @@ final class XdebugGuard
return false;
}
if ($value === '--tia-rebuild') {
if ($value === '--fresh') {
return false;
}

View File

@ -5,18 +5,18 @@ declare(strict_types=1);
use Pest\TestsTia\Support\Sandbox;
/*
* `--tia-rebuild` short-circuits whatever graph is on disk and records
* `--tia --fresh` short-circuits whatever graph is on disk and records
* from scratch. Used when the user knows the cache is wrong.
*/
test('--tia-rebuild forces record mode even with a valid graph', function () {
test('--tia --fresh forces record mode even with a valid graph', function () {
tiaScenario(function (Sandbox $sandbox) {
$sandbox->pest(['--tia']);
expect($sandbox->hasGraph())->toBeTrue();
$graphBefore = $sandbox->graph();
$process = $sandbox->pest(['--tia', '--tia-rebuild']);
$process = $sandbox->pest(['--tia', '--fresh']);
expect($process->isSuccessful())->toBeTrue(tiaOutput($process));
expect(tiaOutput($process))->toContain('recording dependency graph');