From 8b5fb4170191df19cd5578f8c50b82a127c38875 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Mon, 13 Apr 2026 13:08:35 -0600 Subject: [PATCH 1/3] Add pest-testing rules from Tim's tweet --- .ai/pest/3/skill/pest-testing/SKILL.blade.php | 41 +++++++++++++++++++ .ai/pest/4/skill/pest-testing/SKILL.blade.php | 40 ++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/.ai/pest/3/skill/pest-testing/SKILL.blade.php b/.ai/pest/3/skill/pest-testing/SKILL.blade.php index b2486359..702173d9 100644 --- a/.ai/pest/3/skill/pest-testing/SKILL.blade.php +++ b/.ai/pest/3/skill/pest-testing/SKILL.blade.php @@ -106,3 +106,44 @@ - Using `assertStatus(200)` instead of `assertSuccessful()` - Forgetting datasets for repetitive validation tests - Deleting tests without approval + +## Performance Optimization + +Optimize test execution speed with these techniques: + +### Database & Factories + +- **Use `$factory->recycle($model)`** for nested model creations to avoid creating unnecessary top-level models +- **Use `LazilyRefreshDatabase`** trait for tests that do not hit the database +- **Use `WithCachedConfig` and `WithCachedRoutes`** traits to reduce configuration loading overhead + +### Environment Configuration + +- **Disable Debug mode** in testing environment +- **Disable pcov** code coverage driver at scale +- **Set `BCRYPT_ROUNDS=4`** to reduce hashing overhead + +### HTTP Client + +- **Call `Http::preventingStrleRequests()`** in test suite to prevent stray HTTP requests from slowing down tests. This applies only to Laravel's HTTP client—review other request mechanisms (e.g., direct Guzzle use) + +### Background Services + +- **Disable packages** such as Pulse, Telescope, Nightwatch, and similar third-party packages that perform background work +- **Fake the queue** when testing HTTP endpoints that dispatch jobs not relevant to test assertions +- **Fake other services** as needed: `Notification::fake()`, `Mail::fake()`, `Bus::fake()` +- **Fake exceptions** to prevent attempting to report exceptions to third-party services: `Exceptions::fake()` + +### Time & Events + +- **Use `Sleep::fake(syncWithCarbon: true)`** to prevent actual sleeps during tests. Ensure your code uses the `sleep` helper instead of PHP's `sleep` functions +- **Fake events** to prevent unrelated event listeners from executing work during tests +- **Review event listeners** — simple test actions may trigger listeners performing unrelated work + +### Build Tools + +- **Call `withoutVite()` or `withoutMix()`** in test setup to skip asset compilation + +### Profiling + +- **Use Pest's `--profile` option** to identify slowest tests. Investigate these tests and apply optimizations broadly. Laravel's event system is useful for debugging unexpected work within tests diff --git a/.ai/pest/4/skill/pest-testing/SKILL.blade.php b/.ai/pest/4/skill/pest-testing/SKILL.blade.php index 0b8225ac..5cf7abc5 100644 --- a/.ai/pest/4/skill/pest-testing/SKILL.blade.php +++ b/.ai/pest/4/skill/pest-testing/SKILL.blade.php @@ -153,3 +153,43 @@ - Forgetting datasets for repetitive validation tests - Deleting tests without approval - Forgetting `assertNoJavaScriptErrors()` in browser tests + +## Performance Optimization + +Optimize test execution speed with these techniques: + +### Database & Factories + +- Use `$factory->recycle($model)` for nested model creations to avoid creating unnecessary top-level models +- Use `LazilyRefreshDatabase` trait for tests that do not hit the database +- Use `WithCachedConfig` and `WithCachedRoutes` traits to reduce configuration loading overhead + +### Environment Configuration + +- Disable Debug mode in testing environment +- Set `BCRYPT_ROUNDS=4` to reduce hashing overhead + +### HTTP Client + +- Call `Http::preventingStrayRequests()` in test suite to prevent stray HTTP requests from slowing down tests. This applies only to Laravel's HTTP client—review other request mechanisms (e.g., direct Guzzle use) + +### Background Services + +- Disable packages such as Pulse, Telescope, Nightwatch, and similar third-party packages that perform background work +- Fake the queue when testing HTTP endpoints that dispatch jobs not relevant to test assertions +- Fake other services as needed: `Notification::fake()`, `Mail::fake()`, `Bus::fake()` +- Fake exceptions to prevent attempting to report exceptions to third-party services: `Exceptions::fake()` + +### Time & Events + +- Use `Sleep::fake(syncWithCarbon: true)` to prevent actual sleeps during tests. Ensure your code uses the `sleep` helper instead of PHP's `sleep` functions +- Fake events to prevent unrelated event listeners from executing work during tests +- Review event listeners — simple test actions may trigger listeners performing unrelated work + +### Build Tools + +- Call `withoutVite()` or `withoutMix()` in test setup to skip asset compilation + +### Profiling + +- Use Pest's `--profile` option to identify slowest tests. Investigate these tests and apply optimizations broadly. Laravel's event system is useful for debugging unexpected work within tests From 16f36484a307081a55f5a10e5bcab57a7c67bd63 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Mon, 13 Apr 2026 13:10:30 -0600 Subject: [PATCH 2/3] save changes --- .ai/pest/3/skill/pest-testing/SKILL.blade.php | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/.ai/pest/3/skill/pest-testing/SKILL.blade.php b/.ai/pest/3/skill/pest-testing/SKILL.blade.php index 702173d9..67f9e964 100644 --- a/.ai/pest/3/skill/pest-testing/SKILL.blade.php +++ b/.ai/pest/3/skill/pest-testing/SKILL.blade.php @@ -113,37 +113,36 @@ ### Database & Factories -- **Use `$factory->recycle($model)`** for nested model creations to avoid creating unnecessary top-level models -- **Use `LazilyRefreshDatabase`** trait for tests that do not hit the database -- **Use `WithCachedConfig` and `WithCachedRoutes`** traits to reduce configuration loading overhead +- Use `$factory->recycle($model)` for nested model creations to avoid creating unnecessary top-level models +- Use `LazilyRefreshDatabase` trait for tests that do not hit the database +- Use `WithCachedConfig` and `WithCachedRoutes` traits to reduce configuration loading overhead ### Environment Configuration -- **Disable Debug mode** in testing environment -- **Disable pcov** code coverage driver at scale -- **Set `BCRYPT_ROUNDS=4`** to reduce hashing overhead +- Disable Debug mode in testing environment +- Set `BCRYPT_ROUNDS=4` to reduce hashing overhead ### HTTP Client -- **Call `Http::preventingStrleRequests()`** in test suite to prevent stray HTTP requests from slowing down tests. This applies only to Laravel's HTTP client—review other request mechanisms (e.g., direct Guzzle use) +- Call `Http::preventingStrleRequests()` in test suite to prevent stray HTTP requests from slowing down tests. This applies only to Laravel's HTTP client—review other request mechanisms (e.g., direct Guzzle use) ### Background Services -- **Disable packages** such as Pulse, Telescope, Nightwatch, and similar third-party packages that perform background work -- **Fake the queue** when testing HTTP endpoints that dispatch jobs not relevant to test assertions -- **Fake other services** as needed: `Notification::fake()`, `Mail::fake()`, `Bus::fake()` -- **Fake exceptions** to prevent attempting to report exceptions to third-party services: `Exceptions::fake()` +- Disable packages such as Pulse, Telescope, Nightwatch, and similar third-party packages that perform background work +- Fake the queue when testing HTTP endpoints that dispatch jobs not relevant to test assertions +- Fake other services as needed: `Notification::fake()`, `Mail::fake()`, `Bus::fake()` +- Fake exceptions to prevent attempting to report exceptions to third-party services: `Exceptions::fake()` ### Time & Events -- **Use `Sleep::fake(syncWithCarbon: true)`** to prevent actual sleeps during tests. Ensure your code uses the `sleep` helper instead of PHP's `sleep` functions -- **Fake events** to prevent unrelated event listeners from executing work during tests -- **Review event listeners** — simple test actions may trigger listeners performing unrelated work +- Use `Sleep::fake(syncWithCarbon: true)` to prevent actual sleeps during tests. Ensure your code uses the `sleep` helper instead of PHP's `sleep` functions +- Fake events to prevent unrelated event listeners from executing work during tests +- Review event listeners — simple test actions may trigger listeners performing unrelated work ### Build Tools -- **Call `withoutVite()` or `withoutMix()`** in test setup to skip asset compilation +- Call `withoutVite()` or `withoutMix()` in test setup to skip asset compilation ### Profiling -- **Use Pest's `--profile` option** to identify slowest tests. Investigate these tests and apply optimizations broadly. Laravel's event system is useful for debugging unexpected work within tests +- Use Pest's `--profile` option to identify slowest tests. Investigate these tests and apply optimizations broadly. Laravel's event system is useful for debugging unexpected work within tests From d8bf2f4e2b8e90b44b2374327ad92acec15e93ad Mon Sep 17 00:00:00 2001 From: Pushpak Chhajed Date: Tue, 14 Apr 2026 23:00:37 +0530 Subject: [PATCH 3/3] Update guidance --- .ai/pest/3/skill/pest-testing/SKILL.blade.php | 55 ++++++------------ .../pest-testing/reference/performance.md | 39 +++++++++++++ .ai/pest/4/skill/pest-testing/SKILL.blade.php | 57 ++++++------------- .../pest-testing/reference/performance.md | 39 +++++++++++++ 4 files changed, 113 insertions(+), 77 deletions(-) create mode 100644 .ai/pest/3/skill/pest-testing/reference/performance.md create mode 100644 .ai/pest/4/skill/pest-testing/reference/performance.md diff --git a/.ai/pest/3/skill/pest-testing/SKILL.blade.php b/.ai/pest/3/skill/pest-testing/SKILL.blade.php index 67f9e964..7a9b054f 100644 --- a/.ai/pest/3/skill/pest-testing/SKILL.blade.php +++ b/.ai/pest/3/skill/pest-testing/SKILL.blade.php @@ -100,49 +100,28 @@ Pest 3 provides improved type coverage analysis. Run with `--type-coverage` flag. -## Common Pitfalls - -- Not importing `use function Pest\Laravel\mock;` before using mock -- Using `assertStatus(200)` instead of `assertSuccessful()` -- Forgetting datasets for repetitive validation tests -- Deleting tests without approval - -## Performance Optimization - -Optimize test execution speed with these techniques: - -### Database & Factories - -- Use `$factory->recycle($model)` for nested model creations to avoid creating unnecessary top-level models -- Use `LazilyRefreshDatabase` trait for tests that do not hit the database -- Use `WithCachedConfig` and `WithCachedRoutes` traits to reduce configuration loading overhead +## Performance -### Environment Configuration +### Database -- Disable Debug mode in testing environment -- Set `BCRYPT_ROUNDS=4` to reduce hashing overhead +- **Prefer `LazilyRefreshDatabase` over `RefreshDatabase`.** Tests that never touch the DB skip the migration/truncation cost entirely. Only use `RefreshDatabase` when the test specifically needs fresh migrations. +- **Use `$factory->recycle($model)`** to create a shared parent once and thread it through nested factory calls, instead of each nested factory creating its own parent. +- **Create only the models the test needs.** Audit factory usage — avoid nested `create()` calls that spawn extra rows the test never inspects. -### HTTP Client +### Faking -- Call `Http::preventingStrleRequests()` in test suite to prevent stray HTTP requests from slowing down tests. This applies only to Laravel's HTTP client—review other request mechanisms (e.g., direct Guzzle use) +Fake any external interaction that is not the subject of the test: -### Background Services +- `Notification::fake()`, `Mail::fake()`, `Bus::fake()`, `Event::fake()`, `Queue::fake()`. +- If the test hits an HTTP endpoint that dispatches jobs, fake the queue unless the test is asserting job behavior — otherwise jobs execute inline and pull in everything they touch. -- Disable packages such as Pulse, Telescope, Nightwatch, and similar third-party packages that perform background work -- Fake the queue when testing HTTP endpoints that dispatch jobs not relevant to test assertions -- Fake other services as needed: `Notification::fake()`, `Mail::fake()`, `Bus::fake()` -- Fake exceptions to prevent attempting to report exceptions to third-party services: `Exceptions::fake()` +For project-level environment and CI optimizations, see [reference/performance.md](reference/performance.md). -### Time & Events - -- Use `Sleep::fake(syncWithCarbon: true)` to prevent actual sleeps during tests. Ensure your code uses the `sleep` helper instead of PHP's `sleep` functions -- Fake events to prevent unrelated event listeners from executing work during tests -- Review event listeners — simple test actions may trigger listeners performing unrelated work - -### Build Tools - -- Call `withoutVite()` or `withoutMix()` in test setup to skip asset compilation - -### Profiling +## Common Pitfalls -- Use Pest's `--profile` option to identify slowest tests. Investigate these tests and apply optimizations broadly. Laravel's event system is useful for debugging unexpected work within tests +- Not importing `use function Pest\Laravel\mock;` before using mock +- Using `assertStatus(200)` instead of `assertSuccessful()` +- Forgetting datasets for repetitive validation tests +- Deleting tests without approval +- Enabling `RefreshDatabase` on every test even when the test does not hit the DB +- Adding `Queue::fake()` but still asserting side effects of the job (those will never happen) diff --git a/.ai/pest/3/skill/pest-testing/reference/performance.md b/.ai/pest/3/skill/pest-testing/reference/performance.md new file mode 100644 index 00000000..d68da01d --- /dev/null +++ b/.ai/pest/3/skill/pest-testing/reference/performance.md @@ -0,0 +1,39 @@ +# Test Performance Reference + +Environment and tooling optimizations for faster Laravel test suites. These are project-level or CI-level settings — not per-test code changes. + +## Environment and config + +- **Set `BCRYPT_ROUNDS=4`** in `.env.testing` (or `phpunit.xml`). Default is 12 and hashing dominates auth tests. +- **Disable XDebug.** Disable pcov too at scale unless you specifically need coverage. +- **Disable background packages** in the testing environment: Pulse, Telescope, Nightwatch, and similar 3rd-party packages that do work on every request/command. +- **Use `WithCachedConfig` and `WithCachedRoutes` traits** to avoid re-parsing config and routes on every test. +- **Call `withoutVite()` (or `withoutMix()`)** in your test setup so the framework does not try to resolve built assets. +- **`Http::preventingStrayRequests()`** in your base `Pest.php`. A single slow stray request can punish every test. Note this only catches requests made through Laravel's HTTP client. Audit direct Guzzle / cURL usage separately. +- **`Sleep::fake(syncWithCarbon: true)`** in your base `Pest.php` so retries and backoffs do not actually sleep. +- **`Exceptions::fake()`** to make sure you are not reporting to Flare/Sentry/Bugsnag from within tests. + +## Profile and diagnose + +- **`./vendor/bin/pest --profile`** prints the slowest tests per shard. Start there. Patterns in the top-10 often apply suite-wide. +- When a slow test is mysterious, instrument event listeners or add temporary logging to find the unexpected work happening behind the scenes. + +## Quick reference + +| Area | Action | +|------|--------| +| Hashing | `BCRYPT_ROUNDS=4` | +| Debuggers | Disable XDebug, disable pcov | +| Background pkgs | Disable Pulse, Telescope, Nightwatch | +| Config / routes | `WithCachedConfig`, `WithCachedRoutes` | +| Assets | `withoutVite()` / `withoutMix()` | +| HTTP | `Http::preventingStrayRequests()` | +| Sleep | `Sleep::fake(syncWithCarbon: true)` | +| Exceptions | `Exceptions::fake()` | +| Profiling | `pest --profile` | + +## Common environment mistakes + +- Running the suite with XDebug loaded "just in case" a test fails. +- Leaving `BCRYPT_ROUNDS` at the default because `.env.testing` was never created. +- Calling real `sleep()` or using Carbon in production code, which prevents `Sleep::fake()` from helping. diff --git a/.ai/pest/4/skill/pest-testing/SKILL.blade.php b/.ai/pest/4/skill/pest-testing/SKILL.blade.php index 5cf7abc5..86cc13a8 100644 --- a/.ai/pest/4/skill/pest-testing/SKILL.blade.php +++ b/.ai/pest/4/skill/pest-testing/SKILL.blade.php @@ -146,50 +146,29 @@ ->toHaveSuffix('Controller'); @endboostsnippet -## Common Pitfalls - -- Not importing `use function Pest\Laravel\mock;` before using mock -- Using `assertStatus(200)` instead of `assertSuccessful()` -- Forgetting datasets for repetitive validation tests -- Deleting tests without approval -- Forgetting `assertNoJavaScriptErrors()` in browser tests - -## Performance Optimization - -Optimize test execution speed with these techniques: - -### Database & Factories - -- Use `$factory->recycle($model)` for nested model creations to avoid creating unnecessary top-level models -- Use `LazilyRefreshDatabase` trait for tests that do not hit the database -- Use `WithCachedConfig` and `WithCachedRoutes` traits to reduce configuration loading overhead +## Performance -### Environment Configuration +### Database -- Disable Debug mode in testing environment -- Set `BCRYPT_ROUNDS=4` to reduce hashing overhead +- **Prefer `LazilyRefreshDatabase` over `RefreshDatabase`.** Tests that never touch the DB skip the migration/truncation cost entirely. Only use `RefreshDatabase` when the test specifically needs fresh migrations. +- **Use `$factory->recycle($model)`** to create a shared parent once and thread it through nested factory calls, instead of each nested factory creating its own parent. +- **Create only the models the test needs.** Audit factory usage — avoid nested `create()` calls that spawn extra rows the test never inspects. -### HTTP Client +### Faking -- Call `Http::preventingStrayRequests()` in test suite to prevent stray HTTP requests from slowing down tests. This applies only to Laravel's HTTP client—review other request mechanisms (e.g., direct Guzzle use) +Fake any external interaction that is not the subject of the test: -### Background Services +- `Notification::fake()`, `Mail::fake()`, `Bus::fake()`, `Event::fake()`, `Queue::fake()`. +- If the test hits an HTTP endpoint that dispatches jobs, fake the queue unless the test is asserting job behavior — otherwise jobs execute inline and pull in everything they touch. -- Disable packages such as Pulse, Telescope, Nightwatch, and similar third-party packages that perform background work -- Fake the queue when testing HTTP endpoints that dispatch jobs not relevant to test assertions -- Fake other services as needed: `Notification::fake()`, `Mail::fake()`, `Bus::fake()` -- Fake exceptions to prevent attempting to report exceptions to third-party services: `Exceptions::fake()` +For project-level environment and CI optimizations, see [reference/performance.md](reference/performance.md). -### Time & Events - -- Use `Sleep::fake(syncWithCarbon: true)` to prevent actual sleeps during tests. Ensure your code uses the `sleep` helper instead of PHP's `sleep` functions -- Fake events to prevent unrelated event listeners from executing work during tests -- Review event listeners — simple test actions may trigger listeners performing unrelated work - -### Build Tools - -- Call `withoutVite()` or `withoutMix()` in test setup to skip asset compilation - -### Profiling +## Common Pitfalls -- Use Pest's `--profile` option to identify slowest tests. Investigate these tests and apply optimizations broadly. Laravel's event system is useful for debugging unexpected work within tests +- Not importing `use function Pest\Laravel\mock;` before using mock +- Using `assertStatus(200)` instead of `assertSuccessful()` +- Forgetting datasets for repetitive validation tests +- Deleting tests without approval +- Forgetting `assertNoJavaScriptErrors()` in browser tests +- Enabling `RefreshDatabase` on every test even when the test does not hit the DB +- Adding `Queue::fake()` but still asserting side effects of the job (those will never happen) diff --git a/.ai/pest/4/skill/pest-testing/reference/performance.md b/.ai/pest/4/skill/pest-testing/reference/performance.md new file mode 100644 index 00000000..d68da01d --- /dev/null +++ b/.ai/pest/4/skill/pest-testing/reference/performance.md @@ -0,0 +1,39 @@ +# Test Performance Reference + +Environment and tooling optimizations for faster Laravel test suites. These are project-level or CI-level settings — not per-test code changes. + +## Environment and config + +- **Set `BCRYPT_ROUNDS=4`** in `.env.testing` (or `phpunit.xml`). Default is 12 and hashing dominates auth tests. +- **Disable XDebug.** Disable pcov too at scale unless you specifically need coverage. +- **Disable background packages** in the testing environment: Pulse, Telescope, Nightwatch, and similar 3rd-party packages that do work on every request/command. +- **Use `WithCachedConfig` and `WithCachedRoutes` traits** to avoid re-parsing config and routes on every test. +- **Call `withoutVite()` (or `withoutMix()`)** in your test setup so the framework does not try to resolve built assets. +- **`Http::preventingStrayRequests()`** in your base `Pest.php`. A single slow stray request can punish every test. Note this only catches requests made through Laravel's HTTP client. Audit direct Guzzle / cURL usage separately. +- **`Sleep::fake(syncWithCarbon: true)`** in your base `Pest.php` so retries and backoffs do not actually sleep. +- **`Exceptions::fake()`** to make sure you are not reporting to Flare/Sentry/Bugsnag from within tests. + +## Profile and diagnose + +- **`./vendor/bin/pest --profile`** prints the slowest tests per shard. Start there. Patterns in the top-10 often apply suite-wide. +- When a slow test is mysterious, instrument event listeners or add temporary logging to find the unexpected work happening behind the scenes. + +## Quick reference + +| Area | Action | +|------|--------| +| Hashing | `BCRYPT_ROUNDS=4` | +| Debuggers | Disable XDebug, disable pcov | +| Background pkgs | Disable Pulse, Telescope, Nightwatch | +| Config / routes | `WithCachedConfig`, `WithCachedRoutes` | +| Assets | `withoutVite()` / `withoutMix()` | +| HTTP | `Http::preventingStrayRequests()` | +| Sleep | `Sleep::fake(syncWithCarbon: true)` | +| Exceptions | `Exceptions::fake()` | +| Profiling | `pest --profile` | + +## Common environment mistakes + +- Running the suite with XDebug loaded "just in case" a test fails. +- Leaving `BCRYPT_ROUNDS` at the default because `.env.testing` was never created. +- Calling real `sleep()` or using Carbon in production code, which prevents `Sleep::fake()` from helping.