diff --git a/bin/pest b/bin/pest index 0dcde19c..a6f87492 100755 --- a/bin/pest +++ b/bin/pest @@ -3,8 +3,10 @@ declare(strict_types=1); +use Pest\Contracts\Restarter; use Pest\Kernel; use Pest\Panic; +use Pest\Support\Container; use Pest\TestCaseFilters\GitDirtyTestCaseFilter; use Pest\TestCaseMethodFilters\AssigneeTestCaseFilter; use Pest\TestCaseMethodFilters\IssueTestCaseFilter; @@ -193,17 +195,11 @@ use Symfony\Component\Console\Output\ConsoleOutput; try { $kernel = Kernel::boot($testSuite, $input, $output); - // Restarters re-exec the PHP process when conditions warrant it - // (XdebugRestarter drops Xdebug on TIA replay; PcovRestarter pins - // `pcov.directory` to the project root). Runs here, after - // Kernel::boot has loaded `tests/Pest.php` (so - // `pest()->tia()->always()` is visible) and before any plugin's - // `handleArguments` runs (so a re-exec replays cleanly). - $container = \Pest\Support\Container::getInstance(); + $container = Container::getInstance(); foreach (Kernel::RESTARTERS as $restarterClass) { $restarter = $container->get($restarterClass); - assert($restarter instanceof \Pest\Contracts\Restarter); + assert($restarter instanceof Restarter); $restarter->maybeRestart($rootPath, $originalArguments); } diff --git a/src/Exceptions/BaselineFetchFailed.php b/src/Exceptions/BaselineFetchFailed.php index 204b6836..12b7caf9 100644 --- a/src/Exceptions/BaselineFetchFailed.php +++ b/src/Exceptions/BaselineFetchFailed.php @@ -12,13 +12,6 @@ use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Output\OutputInterface; /** - * Raised when fetching the team-shared TIA baseline hits an error - * that's actionable rather than transient — missing `gh`, broken - * auth, scope/perms misconfiguration, or a CI publish that produced - * an unreadable artifact. Silently falling through to a full record - * would paper over the bug and waste minutes; better to stop, tell - * the user what to fix, and offer the `--fresh` escape hatch. - * * @internal */ final class BaselineFetchFailed extends RuntimeException implements ExceptionInterface, Panicable, RenderlessEditor, RenderlessTrace diff --git a/src/Plugins/Tia.php b/src/Plugins/Tia.php index 09f147b5..061d8e0c 100644 --- a/src/Plugins/Tia.php +++ b/src/Plugins/Tia.php @@ -31,11 +31,6 @@ use Symfony\Component\Process\Process; use Throwable; /** - * Test Impact Analysis plugin — record/replay, parallel-aware. - * - * Must be registered before `Parallel` — Parallel exits on `--parallel`, - * so later plugins never execute. - * * @internal */ final class Tia implements AddsOutput, HandlesArguments, Terminable diff --git a/src/Plugins/Tia/AutoloadEdges.php b/src/Plugins/Tia/AutoloadEdges.php index 0ecf9719..de9a3293 100644 --- a/src/Plugins/Tia/AutoloadEdges.php +++ b/src/Plugins/Tia/AutoloadEdges.php @@ -5,12 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia; /** - * Captures PHP files that were included while a test was running. - * - * Coverage drivers miss declaration-only files (classes, enums, interfaces, - * traits) and files loaded before the coverage window opens. Diffing - * `get_included_files()` gives TIA an explicit edge for those autoloaded files. - * * @internal */ final readonly class AutoloadEdges diff --git a/src/Plugins/Tia/BaselineSync.php b/src/Plugins/Tia/BaselineSync.php index 2cfa7665..c8cc6d60 100644 --- a/src/Plugins/Tia/BaselineSync.php +++ b/src/Plugins/Tia/BaselineSync.php @@ -13,13 +13,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; /** - * Downloads a team-shared TIA baseline from GitHub workflow artifacts so new contributors and - * fresh CI workspaces start in replay mode. Artifacts are used instead of releases because they - * produce no tag (no push cascade), support tunable retention, and can only be published by CI. - * - * Fingerprint validation happens in `Tia::handleParent` after the blobs land; a mismatched - * environment falls through to the normal record path. - * * @internal */ final readonly class BaselineSync diff --git a/src/Plugins/Tia/BladeEdges.php b/src/Plugins/Tia/BladeEdges.php index 8a7465b5..1a5681bb 100644 --- a/src/Plugins/Tia/BladeEdges.php +++ b/src/Plugins/Tia/BladeEdges.php @@ -5,27 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia; /** - * Laravel-only collaborator: during record mode, attributes every - * rendered Blade view to the currently-running test. - * - * Why this exists: the coverage driver only sees compiled view files - * under `storage/framework/views/.php`, not the `.blade.php` - * source. Without a dedicated hook TIA has no edges for blade files, - * so it leans on the Laravel WatchDefault's broad "any .blade.php - * change → every feature test" fallback. Safe but noisy — editing a - * single partial re-runs the whole suite. - * - * With this armed at record time, each test's edge set grows to - * include the precise `.blade.php` files it rendered (directly or - * through `@include`, layouts, components, Livewire, Inertia root - * views — anything that goes through Laravel's view factory fires - * `View::composer('*')`). Replay then invalidates exactly the tests - * that rendered the changed template. - * - * Implementation note: everything Laravel-touching goes through - * string class names, `class_exists`, and `method_exists` so Pest - * core doesn't pull `illuminate/container` into its `require`. - * * @internal */ final class BladeEdges diff --git a/src/Plugins/Tia/Bootstrapper.php b/src/Plugins/Tia/Bootstrapper.php index 78c1b961..5825e5dd 100644 --- a/src/Plugins/Tia/Bootstrapper.php +++ b/src/Plugins/Tia/Bootstrapper.php @@ -10,17 +10,6 @@ use Pest\Support\Container; use Pest\TestSuite; /** - * Plugin-level container registrations for TIA. Runs as part of Kernel's - * bootstrapper chain so Tia's own service graph is set up without Kernel - * having to know about any of its internals. - * - * Most Tia services (`Recorder`, `CoverageCollector`, `WatchPatterns`, - * `ResultCollector`, `BaselineSync`) are auto-buildable — Pest's container - * resolves them lazily via constructor reflection. The only service that - * requires an explicit binding is the `State` contract, because the - * filesystem implementation needs a root-directory string that reflection - * can't infer. - * * @internal */ final readonly class Bootstrapper implements BootstrapperContract diff --git a/src/Plugins/Tia/ChangedFiles.php b/src/Plugins/Tia/ChangedFiles.php index fd7fdb8a..ee81bd0b 100644 --- a/src/Plugins/Tia/ChangedFiles.php +++ b/src/Plugins/Tia/ChangedFiles.php @@ -7,19 +7,6 @@ namespace Pest\Plugins\Tia; use Symfony\Component\Process\Process; /** - * Detects files that changed between the last recorded TIA run and the - * current working tree. - * - * Strategy: - * 1. If we have a `recordedAtSha`, `git diff ..HEAD` captures committed - * changes on top of the recording point. - * 2. `git status --short` captures unstaged + staged + untracked changes on - * top of that. - * - * We return relative paths to the project root. Deletions are included so the - * caller can decide whether to invalidate: a deleted source file may still - * appear in the graph and should mark its dependents as affected. - * * @internal */ final readonly class ChangedFiles diff --git a/src/Plugins/Tia/Configuration.php b/src/Plugins/Tia/Configuration.php index 20920f9f..d7e5165b 100644 --- a/src/Plugins/Tia/Configuration.php +++ b/src/Plugins/Tia/Configuration.php @@ -7,19 +7,6 @@ namespace Pest\Plugins\Tia; use Pest\Support\Container; /** - * User-facing TIA configuration, returned by `pest()->tia()`. - * - * Usage in `tests/Pest.php`: - * - * pest()->tia()->watch([ - * 'resources/js/**\/*.tsx' => 'tests/Browser', - * 'public/build/**\/*' => 'tests/Browser', - * ]); - * - * Patterns are merged with the built-in defaults (config, routes, views, - * frontend assets, migrations). Duplicate glob keys overwrite the default - * mapping so users can redirect a pattern to a narrower directory. - * * @internal */ final class Configuration diff --git a/src/Plugins/Tia/ContentHash.php b/src/Plugins/Tia/ContentHash.php index 368b1209..79b718b6 100644 --- a/src/Plugins/Tia/ContentHash.php +++ b/src/Plugins/Tia/ContentHash.php @@ -5,24 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia; /** - * Per-file hashing that ignores changes which can't alter behaviour — - * comments and whitespace for PHP, `{{-- … --}}` comments and whitespace - * runs for Blade templates. Every other file type falls back to a plain - * xxh128 of the raw bytes. - * - * Why it matters: TIA's file diff signals drive which tests re-run. A - * one-line comment tweak on a migration is a behavioural no-op, but the - * raw-bytes hash still differs, so every test that talks to the DB would - * currently re-execute. Normalising to the parsed-token / compiled-shape - * keeps the drift signal honest: edits that can't change runtime - * behaviour don't invalidate the replay cache. - * - * Important: this hash is stored in the graph's last-run tree, so any - * format change here must be paired with a `Fingerprint::SCHEMA_VERSION` - * bump — otherwise stale hashes from older graphs would be compared - * against normalised hashes from the new code and everything would - * appear changed. - * * @internal */ final class ContentHash diff --git a/src/Plugins/Tia/Contracts/State.php b/src/Plugins/Tia/Contracts/State.php index d440c4e1..6a0ba155 100644 --- a/src/Plugins/Tia/Contracts/State.php +++ b/src/Plugins/Tia/Contracts/State.php @@ -5,12 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia\Contracts; /** - * Storage contract for TIA's persistent state (graph, baselines, affected - * set, worker partials, coverage snapshots). Modelled as a flat key/value - * store of raw byte blobs so implementations can sit on top of whatever - * backend fits — a directory, a shared cache, a remote object store — and - * TIA's logic stays identical. - * * @internal */ interface State diff --git a/src/Plugins/Tia/CoverageCollector.php b/src/Plugins/Tia/CoverageCollector.php index c1109afa..4fff521e 100644 --- a/src/Plugins/Tia/CoverageCollector.php +++ b/src/Plugins/Tia/CoverageCollector.php @@ -9,16 +9,6 @@ use ReflectionClass; use Throwable; /** - * Extracts per-test file coverage from PHPUnit's shared `CodeCoverage` - * instance. Used when TIA piggybacks on `--coverage` instead of starting - * its own driver session — both share the same PCOV / Xdebug state, so - * running two recorders in parallel would corrupt each other's data. - * - * PHPUnit tags every coverage sample with the current test's id - * (`$test->valueObjectForEvents()->id()`, e.g. `Foo\BarTest::baz`). The - * per-file / per-line coverage map therefore already carries everything - * we need to rebuild TIA edges at the end of the run. - * * @internal */ final class CoverageCollector diff --git a/src/Plugins/Tia/CoverageMerger.php b/src/Plugins/Tia/CoverageMerger.php index 0f984571..1f2c2748 100644 --- a/src/Plugins/Tia/CoverageMerger.php +++ b/src/Plugins/Tia/CoverageMerger.php @@ -11,33 +11,6 @@ use SebastianBergmann\CodeCoverage\CodeCoverage; use Throwable; /** - * Merges the current run's PHPUnit coverage into a cached full-suite - * snapshot so `--tia --coverage` can produce a complete report after - * executing only the affected tests. - * - * Invoked from `Pest\Support\Coverage::report()` right before the coverage - * file is consumed. A marker dropped by the `Tia` plugin gates the - * behaviour — plain `--coverage` runs (no `--tia`) leave the marker absent - * and therefore keep their existing semantics. - * - * Algorithm - * --------- - * The PHPUnit coverage PHP file unserialises to a `CodeCoverage` object. - * Its `ProcessedCodeCoverageData` stores, per source file, per line, the - * list of test IDs that covered that line. We: - * - * 1. Load the cached snapshot from `State` (serialised bytes). - * 2. Strip every test id that re-ran this time from the cached map — - * the tests that ran now are the ones whose attribution is fresh. - * 3. Merge the current run into the stripped cached snapshot via - * `CodeCoverage::merge()`. - * 4. Write the merged result back to the report path (so Pest's report - * generator sees the full suite) and back into `State` (for the - * next invocation). - * - * If no cache exists yet (first `--tia --coverage` run on this machine) - * we serialise the current object and save it — nothing to merge yet. - * * @internal */ final class CoverageMerger diff --git a/src/Plugins/Tia/FileState.php b/src/Plugins/Tia/FileState.php index d1938407..84ee62f4 100644 --- a/src/Plugins/Tia/FileState.php +++ b/src/Plugins/Tia/FileState.php @@ -7,14 +7,6 @@ namespace Pest\Plugins\Tia; use Pest\Plugins\Tia\Contracts\State; /** - * Filesystem-backed implementation of the TIA `State` contract. Each key - * maps verbatim to a file name under `$rootDir`, so existing `.temp/*.json` - * layouts are preserved exactly. - * - * The root directory is created lazily on first write — callers don't have - * to pre-provision it, and reads against a missing directory simply return - * `null` rather than throwing. - * * @internal */ final readonly class FileState implements State diff --git a/src/Plugins/Tia/Fingerprint.php b/src/Plugins/Tia/Fingerprint.php index 0c3758bd..b76b7d64 100644 --- a/src/Plugins/Tia/Fingerprint.php +++ b/src/Plugins/Tia/Fingerprint.php @@ -5,15 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia; /** - * Two-bucket fingerprint for TIA staleness detection. - * - * - **structural**: inputs whose drift means graph *edges* may be wrong → full rebuild. - * `tests/TestCase.php` and `tests/Pest.php` are intentionally absent; they're covered by - * `Recorder::linkAncestorFiles` and the watch pattern, giving precise per-test invalidation. - * - **environmental**: runtime inputs (PHP version, extensions, env files) whose drift means - * edges are still valid but cached results may not reproduce → drop results and re-run. - * Pest's own version is absent; `composer.lock` moves whenever Pest is upgraded. - * * @internal */ final readonly class Fingerprint diff --git a/src/Plugins/Tia/Graph.php b/src/Plugins/Tia/Graph.php index 6d04c5a5..8bbb9b7e 100644 --- a/src/Plugins/Tia/Graph.php +++ b/src/Plugins/Tia/Graph.php @@ -11,9 +11,6 @@ use PHPUnit\Framework\TestStatus\TestStatus; use Symfony\Component\Console\Output\OutputInterface; /** - * Dependency graph: test file → set. Skips unchanged tests on replay. - * Source files are indexed by numeric id to keep the on-disk JSON compact. - * * @internal */ final class Graph diff --git a/src/Plugins/Tia/InertiaEdges.php b/src/Plugins/Tia/InertiaEdges.php index e1c921c9..46992255 100644 --- a/src/Plugins/Tia/InertiaEdges.php +++ b/src/Plugins/Tia/InertiaEdges.php @@ -5,28 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia; /** - * Inertia-aware collaborator: during record mode, attributes every - * Inertia component the test server-side renders to the currently- - * running test file. - * - * Why this exists: a change to `resources/js/Pages/Users/Show.vue` - * should only invalidate tests that actually rendered `Users/Show`. - * The Laravel `WatchDefaults\Inertia` glob is a broad fallback — fine - * for brand-new pages, but noisy once the graph has real data. With - * this armed, each test's recorded edge set grows to include the - * component names it returned through `Inertia::render()`, and - * subsequent replay intersects page-file changes against that set. - * - * Mechanism: listen for `Illuminate\Foundation\Http\Events\RequestHandled` - * on Laravel's event dispatcher. Inertia responses are identifiable by - * either an `X-Inertia` header (XHR / JSON shape) or a `data-page` - * attribute on the root `
` (full HTML shape). Both carry - * the component name in a structured payload we can parse cheaply. - * - * Same dep-free handshake as `BladeEdges` / `TableTracker`: string - * class lookup + method-capability probes so Pest's `require` stays - * Laravel-free. - * * @internal */ final class InertiaEdges diff --git a/src/Plugins/Tia/JsImportParser.php b/src/Plugins/Tia/JsImportParser.php index cfc87ac6..5f9ee53e 100644 --- a/src/Plugins/Tia/JsImportParser.php +++ b/src/Plugins/Tia/JsImportParser.php @@ -5,29 +5,6 @@ declare(strict_types=1); namespace Pest\Plugins\Tia; /** - * Fallback parser for ES module imports under `resources/js/`. - * - * Used only when the Node helper (`bin/pest-tia-vite-deps.mjs`) is - * unavailable — typically when Node isn't on `PATH` or the user's - * `vite.config.*` can't be loaded. Pure PHP, so it degrades - * gracefully on locked-down environments but cannot match the - * full-fidelity Vite resolver. - * - * Known limits (intentional — preserving correctness over precision): - * - Only `@/` and `~/` aliases recognised (both resolve to - * `resources/js/`, the community default). Custom aliases from - * `vite.config.ts` are ignored; anything we can't resolve is - * simply skipped and falls through to the watch-pattern safety - * net. - * - Dynamic imports with variable expressions - * (`import(`./${name}`.vue)`) can't be resolved; the literal - * prefix is ignored and the caller over-runs. Safe. - * - Vue SFC `