TL;DR
- Bumped Kickoff (my Laravel scaffolder) to Pest 5, PHP 8.4 floor, Symfony Console 8.
- Made
pest --tiathe defaultcomposer test— only re-run tests affected by your change. - Three real gotchas surfaced: Symfony Console's
add()is gone, TIA needs real tests to exist, and a Redis throttle leaked state across runs and threw random 429s.
Kickoff is the tool I use to bootstrap new Laravel projects with sane defaults. Today it moved to Pest 5, and I took the chance to turn on test impact analysis everywhere. Here's what actually mattered.
TIA: run the tests your change touched, nothing else
Test Impact Analysis maps which tests exercise which code, then on the next run only executes the ones your diff could have broken. On a small package it's a nicety; on a big app it's the difference between a 4-second loop and a 4-minute one.
Turning it on is one flag:
"scripts": {
"test": [
"@php vendor/bin/pest --tia"
]
}
The catch: TIA only helps if you have real tests it can map. Which led to the less obvious work below.
Gotcha 1: Symfony Console 8 dropped add()
Pest 5 allows Symfony Console ^8, and Console 8 removed the long-deprecated Application::add(). If your CLI registers commands the old way, it just breaks:
// before
$app->add(new StartCommand());
// after
$app->addCommand(new StartCommand());
Small change, but it's a hard failure on boot, so worth knowing before you bump.
Gotcha 2: ship real tests, not example stubs
TIA is useless against placeholder tests. So the scaffolder now removes the starter kit's example tests during setup and ships Pest conversions of the real ones — auth flows, dashboard — so a freshly generated project has a meaningful test map from commit one.
test('registration screen can be rendered', function () {
$this->get('/register')->assertOk();
});
test('new users can register', function () {
$this->post('/register', [
'name' => 'Test User',
'email' => 'test@example.com',
'password' => 'password',
'password_confirmation' => 'password',
])->assertRedirect(route('dashboard', absolute: false));
$this->assertAuthenticated();
});
Gotcha 3: the Redis throttle that leaked 429s
This one cost me the most time. A rate-limit throttle backed by Redis kept its counter across test runs — so a suite that hammered a throttled route would start returning 429 Too Many Requests on the next run, seemingly at random. The fix is to only reach for the Redis-backed throttle outside testing:
->withMiddleware(function (Middleware $middleware) {
if (! app()->environment('testing')) {
$middleware->throttleWithRedis();
}
})
Lesson: any middleware holding state in an external store is a test-isolation hazard. Either reset it between runs or don't wire it in tests at all.
While I was in there: laravel/doctor
Generated projects now ship with laravel/doctor as a dev dependency — a quick environment/health check so a new project can tell you what's misconfigured before you go hunting.
Takeaway
| Change | Why it matters |
|---|---|
Pest 5 + --tia default |
Fast, targeted test loops |
| Ship real tests in stubs | TIA needs a real map to be useful |
| Guard stateful middleware in tests | Kills flaky cross-run failures |
laravel/doctor in new projects |
Faster diagnosis of setup issues |
TIA is one of those upgrades that pays back every single day — but only if your generated project starts life with tests worth mapping. That's the part worth doing properly.
Top comments (0)