itsgoingd / itsgoingd/clockwork

Test collection silently fails on PHPUnit 12 / Pest 4 — $app is already null when Passed/Failed/Skipped events fire

Open
#761 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
6k
Forks
333
Avg merge
5m
Merged PRs (30d)
1

Description

Thank you for all of the work you have done on Clockwork. I recently ran into an issue getting data while running pest tests. Below is a summary from Claude as to why I am not seeing anything.

============

Environment

  • itsgoingd/clockwork v5.3.5
  • phpunit/phpunit 12.5.33
  • pestphp/pest v4
  • laravel/framework v12
  • PHP 8.3.32

Config

  • config/clockwork.php: tests.collect → true (via CLOCKWORK_TESTS_COLLECT=true)
  • CLOCKWORK_ENABLE=true
  • phpunit.xml has the extension registered correctly:

Symptom
No test metadata is ever written to storage/clockwork when running tests via php artisan test, vendor/bin/pest, or vendor/bin/phpunit, despite tests.collect being enabled and no errors being reported.

Root cause (confirmed via temporary debug logging in ClockworkExtension.php)

  1. ClockworkExtension::bootstrap() runs, and subscribers are registered correctly.
  2. PassedSubscriber/FailedSubscriber/etc. do fire recordTest() for every test.
  3. Inside recordTest(), resolveApp($testCase) returns null on every single test, so the method returns early before ever calling isCollectingTests() or storeRequest().
  4. resolveApp() (in Clockwork/Support/Laravel/Tests/ClockworkExtension.php) reflects on the test case's $app property:
    protected static function resolveApp($testCase)
    {
    $reflectionClass = new \ReflectionClass($testCase);
    if ($reflectionClass->hasProperty('app')) {
    $reflectionProperty = $reflectionClass->getProperty('app');
    $reflectionProperty->setAccessible(true);
    if ($reflectionProperty->getValue($testCase)) {
    return $reflectionProperty->getValue($testCase);
    }
    } elseif (method_exists($testCase, 'createApplication')) {
    return $testCase->createApplication();
    }
    }
  5. Laravel's Illuminate\Foundation\Testing\Concerns\InteractsWithTestCaseLifecycle::tearDownTheTestEnvironment() sets $this->app = null inside tearDown().
  6. In PHPUnit 12's event system, tearDown() runs before the Test\Passed (and Failed/Skipped/Errored) event is emitted (see vendor/phpunit/phpunit/src/Framework/TestCase.php around lines 621–659 — fixture teardown happens, then $emitter->testPassed(...) is dispatched).
  7. So by the time Clockwork's subscriber runs resolveApp(), $app has already been nulled by Laravel's own teardown, and the property check at line 102 (if ($reflectionProperty->getValue($testCase))) fails, causing a silent no-op with no error or log output.

Why this looks new: the CHANGELOG for 5.3.5 lists support for "PHPUnit 11 and Pest 3." This suggests the event-timing relative to tearDown() changed (or was already like this but tolerated differently) by PHPUnit 12, breaking the $app-via-reflection approach for PHPUnit 12 / Pest 4.

Suggested fix direction

  • Capture the app instance earlier in the test lifecycle (e.g. via a PreparedSubscriber or Event\Test\Started hook, before tearDown() runs) and cache it per-test, rather than reflecting on the (possibly torn-down) test case object inside Passed/Failed/Skipped handlers.
  • Alternatively, fall back to Illuminate\Foundation\Application::getInstance() if the reflected $app property is null, if the static instance is still available at that point.

Repro: any Laravel 12 + Pest 4 + PHPUnit 12 project with itsgoingd/clockwork 5.3.5, tests.collect enabled, and the extension registered in phpunit.xml — no test metadata files are ever created in storage/clockwork, and no error/warning is surfaced.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Read Clockwork/Support/Laravel/Tests/ClockworkExtension.php and PHPUnit's vendor/phpunit/phpunit/src/Framework/TestCase.php around lines 621–659 first, then trace the Passed, Failed, Skipped, and Started event subscribers. Confirm that the app remains available when test metadata is recorded under Laravel 12 with PHPUnit 12 and Pest 4, and verify that files are written to storage/clockwork.

Written by the indexing model from the issue text.

Assessment

Tech stack
laravel, php
Domain
testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.