controller-testing
Original:🇺🇸 English
Translated
Writes Pest feature tests for Laravel HTTP controllers using repeatable controller-test patterns across web/session and API/JSON flows. Activates when creating or updating controller tests, nested resource route tests at any depth, CRUD action tests (create, destroy, edit, index, show, store, update), authorization and route-binding scope checks, validation datasets, transport-specific response assertions, and database persistence assertions.
2installs
Sourcehosmelq/agent-skills
Added on
NPX Install
npx skill4agent add hosmelq/agent-skills controller-testingTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Controller Testing
When to Apply
Activate this skill when:
- Creating or updating Pest feature tests for controllers.
- Testing nested resource routes at any depth.
- Building CRUD action test matrices (,
create,destroy,edit,index,show,store) for resource-style controllers.update - Adding authorization, route-binding mismatch, validation dataset, and success-path assertions.
- Testing either:
- web/session controllers (,
get,post,patch), ordelete - API/JSON controllers (,
getJson,postJson,patchJson).deleteJson
- web/session controllers (
Use this skill together with for generic Pest behavior.
pest-testingQuick Start
bash
# Create file only when needed
php artisan make:test --pest Http/Controllers/<Name>ControllerTest --no-interaction
# Run only the affected file
php artisan test --compact tests/Feature/Http/Controllers/<Name>ControllerTest.php
# Optional focused rerun
php artisan test --compact --filter="<test name>"Core Workflow
- Inspect sibling controller tests first.
- Decide mode first from sibling tests: web/session mode or API/JSON mode.
- For resource-style controllers, use blocks in this order:
describe('<action>'),create,destroy,edit,index,show,store.update - For non-resource controllers, test only exposed actions and keep the same assertion patterns.
- For each action, include baseline auth + forbidden + binding mismatch coverage as applicable.
- Use dataset-driven validation tests for and
store.update - Assert success path with transport-specific assertions plus persistence checks.
References
Load only what you need:
-
Transport-mode guide for API/JSON controller tests, including protected-endpoint and public-endpoint patterns, plus full
references/modes/api-json.mdandstoreupdateexamples.describe(...) -
Use for full route naming examples and complete
references/route-patterns.mdparameter maps for flat, one-level, two-level, three-level, and N-level nested resources.route() -
Full
references/actions/create.mdexamples for one-level and two-level nested resources.describe('create') -
Full
references/actions/destroy.mdexamples for one-level and two-level nested resources.describe('destroy') -
Full
references/actions/edit.mdexamples for one-level and two-level nested resources.describe('edit') -
Full
references/actions/index.mdexamples for one-level and two-level nested resources.describe('index') -
Full
references/actions/show.mdexamples for one-level, two-level, and three-level nested resources.describe('show') -
Full
references/actions/store.mdexamples for one-level and two-level nested resources, including baselinedescribe('store')dataset examples.validates fields -
Full
references/actions/update.mdexamples for one-level and two-level nested resources, including baselinedescribe('update')dataset examples and optional stored-bound validation cases.validates fields -
Additional
references/validation/store-validates-fields.mdvalidation dataset snippets to merge when request rules need more coverage.store -
Additional
references/validation/update-validates-fields.mdvalidation dataset snippets to merge when request rules need more coverage.updatePrefer the focused validation references below first when a specific rule pattern matches. -
Focused
references/validation/required-with-and-array.mdsnippets forvalidates fieldsandrequired_withrules inarrayandstore.update -
Focused snippets for scope-aware
references/validation/scoped-exists-and-unique.mdandexistsrules (includinguniqueonignore(...)).update -
Focused snippets for
references/validation/prepare-for-validation.mdside-effects and stored-value dependent validation cases.prepareForValidation() -
Focused public API auth validation snippets (
references/validation/api-login-validation.mdandemail request) with JSON assertions.email login
Action references are web/session-first templates. For API/JSON controllers, use the same action structure and adapt assertions using plus sibling API tests.
references/modes/api-json.mdRequired Baseline Assertions
Shared:
- Policy denial with valid bindings -> .
assertForbidden() - Parent-child binding mismatches (especially with ) ->
scopeBindings.assertNotFound() - Decide vs
403by execution path:404- binding/scope mismatch resolves first ->
404 - binding is valid but authorization fails ->
403
- binding/scope mismatch resolves first ->
Web/session mode:
- -> redirect to login route.
requires authentication - Validation failures -> .
assertRedirectBackWithErrors(...) - Page actions -> +
assertOk().assertInertia(...) - Mutation actions -> redirect + persistence assertions.
- Toast/flash assertions are optional and app-specific:
- if your app has , use it
assertToast(...) - otherwise use your app's existing flash assertion style
- if your app has
API/JSON mode:
- Protected endpoints: ->
requires authentication.assertUnauthorized() - Public endpoints: do not add by default.
requires authentication - Validation failures -> +
assertUnprocessable().assertJsonValidationErrors(...) - Success actions -> /
assertOk()/assertCreated()+ JSON assertions + persistence assertions.assertNoContent()
Notes
- One-level, two-level, and three-level examples are not limits; apply the same pattern to deeper nesting.
- Auth examples use neutral placeholders; adapt to your project helper signature and ensure the authenticated user belongs to the related scope when needed.
login() - For , use model-appropriate persistence assertions:
destroy- when the model uses
assertSoftDeleted(...).SoftDeletes - when it does not.
assertModelMissing(...)
- Use the app's existing identifier shape in assertions (,
id, slug, route key).public_id