Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pest Plugin Route Testing Laravel Package

spatie/pest-plugin-route-testing

Easily test every GET route in your Laravel app with Pest. Assert all routes return successful responses, include or exclude patterns, and bind models for routes with route model bindings.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. The package occupies a single, well-bounded layer: the test suite. It is a --dev Composer dependency that reads the application's route table (via route:list since the 0.0.3 refactor), fans the results into Pest data providers, dispatches each route through Laravel's standard HTTP test harness, and forwards assertions to TestResponse. There is no service provider in the production boot path, no migrations, no configuration surface, no runtime dependency, and no data model. Coupling is limited to two public Laravel contracts — the route listing and TestResponse assertions — both of which are stable and versioned. Reversibility is a single composer remove commit plus deletion of one test file. For a TPM this is about as low-stakes an addition to a roadmap as exists: it is a testing ergonomics improvement, not a platform decision, and should be scoped and resourced accordingly.

Integration feasibility. Effort is low (estimated 1–2 engineer-days including CI wiring and triage of the first run), but there is one hard gate: the application must use Pest. This is a Pest plugin, not a PHPUnit plugin. The package version is therefore not a free choice — it is determined by the stack:

  • 1.2.x → Pest 5, PHP 8.4 minimum, Testbench ^11 (Laravel 13).
  • 1.1.x → Pest 3 era; suitable for teams on PHP 8.2/8.3 and Laravel 11/12.

Teams on older PHP or Laravel land on 1.1.x and should plan on that branch being effectively frozen. Teams with no Pest at all face a framework migration (Pest is a PHPUnit superset, so the path is incremental, but it touches every existing test) — that is a separate initiative and should not be smuggled in under this package. The cheap alternative for non-Pest shops is a hand-rolled PHPUnit data provider over route:list, roughly 50–100 lines, functionally equivalent for the smoke-test use case.

Technical risk. Low code risk, moderate perception risk. The library is small, MIT-licensed, and forkable by a single engineer if Spatie archives it. The genuine risk is that the initiative delivers a green badge that means less than stakeholders believe:

  • Coverage illusion. GET-only, plus route-model bindings skipped by default, means "all routes pass" is false by construction on any app with user/{user}-style paths. On a typical CRUD app the skipped set can be the majority of the interesting routes. The skip report mitigates but does not eliminate this; the mitigation is a documented, named skipped-route baseline reviewed each sprint.
  • Assertion shallowness. assertSuccessful() proves the route returns 200 — not that it returns the right page, the right authorization boundary, or the right data. A 200 from a mis-rendered view or a leaked admin page passes. This is a smoke test; position it internally as such and resist pressure to count it as coverage.
  • Side effects and state. Route tests execute real controller code against a test database. Seeded state, queue dispatch, outbound HTTP, and file writes all become latent flakiness sources at suite scale. Expect an initial triage wave, not a clean first run.
  • Auth-shaped false greens. Without setUp() + actingAs(), protected routes return 302/403 and will fail assertSuccessful(); teams often "fix" this by excluding them, silently removing the most security-relevant routes from the check.

Key questions. (1) Which Pest/PHP/Laravel triple are we on, and therefore which package line do we pin? (2) What fraction of our GET routes are skipped for missing bindings, and who owns that list? (3) Does the first run land in CI as blocking or advisory? (4) Who triages initial failures, and is that budgeted? (5) Do we accept a non-Pest fallback, or is Pest adoption a prerequisite deliverable? (6) What is our internal definition of "done" — package installed, or skipped-route baseline driven below an agreed threshold?

Integration Approach

Stack fit. The package slots into any Pest-based Laravel repo with zero application changes. The practical prerequisite chain is: Composer dev dependency → Pest present → route table resolvable in the test environment. That last point matters more than it appears: routes gated behind feature flags, environment guards, or module providers that do not register in testing will simply be absent from the run and will not announce themselves. Confirm early that route:list in CI shows a route count comparable to production, and treat a wide gap as a finding in its own right.

Migration path. Nothing to migrate — this is additive, dev-only, and removable. The two real paths are:

  • Pest shop (fast path): pin to the line matching the stack, add one test file with routeTesting('all GET routes')->assertSuccessful(), run locally, triage, then wire into CI. 1–2 days.
  • PHPUnit shop (slower path): either defer and implement the equivalent data provider in-house (~2 days, no new dependency, no Pest bet), or sequence Pest adoption as its own initiative and attach this package afterwards. Do not conflate them — the second is a multi-week change with test-suite-wide blast radius and deserves its own business case.

Compatibility. Two axes to pin explicitly in composer.json: the package line (1.2.x vs 1.1.x) and the Pest major. 1.2.0's jump to PHP 8.4 / Testbench ^11 means an upgrade of the package is effectively an upgrade of the runtime and the framework test harness — it will not be a routine patch bump and should be scheduled as a platform task, not a dependency chore. Note also that 1.1.x has a history of small compatibility fixes (named-parameter handling in 1.1.2, TestResponse macro dispatch in 1.1.3, PHPStan resolution of TestResponse methods in 1.2.1), which tells you the surface is thin but not inert. Watch the 1.1.x branch: with 1.2.0 pushing to PHP 8.4, backports there are unlikely.

Sequencing. (1) Confirm stack triple and pin the version. (2) Author the baseline test locally and capture the full pass/fail/skip report — this is the actual deliverable of phase one, not the green build. (3) Triage failures into genuine bugs, environment gaps, and pre-existing known-broken routes; route the first category into the backlog as discovered defects, which is where the package usually pays for itself immediately. (4) Add include()/exclude() scoping to carve out deliberately untestable surfaces (_debugbar, telescope, horizon, webhook receivers), documenting each exclusion with a reason. (5) Add setUp() + actingAs() blocks per auth tier so protected routes are tested rather than excluded. (6) Add bind() fixtures for the highest-traffic model-bound routes. (7) Only then promote the job from advisory to blocking in CI.

Operational Impact

Maintenance. Near-zero for the dependency, non-zero for the test file, and the non-zero part is where TPM attention belongs. Every new route with a model binding adds a skip; every new auth tier adds a setUp() block; every intentional exclusion adds a line that must be re-justified when the route changes. Budget roughly a half-day per quarter for baseline hygiene, and assign a named owner. Upstream, the project is a single-maintainer Spatie package with 141 stars and 0 dependents — small, healthy, but not load-bearing for anyone else. If it is abandoned, forking or inlining the ~50–100 line equivalent is a day's work. Do not let it acquire the status of critical infrastructure in planning documents.

Support. Community-only, MIT, no SLA, no vendor relationship to manage. Internal support burden is entirely "who understands the route baseline and the exclusion list." That is a single-engineer bus factor and should be written into the test file as comments so it survives turnover. Escalation for a package bug is a GitHub issue with no timeline; the realistic response is a fork.

Scaling. Two scaling behaviours to anticipate. First, route count: each route is a data-provider case executing a full HTTP kernel boot and DB transaction. At a few hundred routes this is minutes; at a few thousand it will dominate CI wall-clock and needs sharding or a --parallel strategy. Model the suite growth against current CI duration before making it blocking, because a blocking job that adds ten minutes to every PR gets disabled by engineers within a month regardless of policy. Second, fixture cost: setUp() blocks creating factories per auth tier multiply across every route in scope. Use shared fixtures or RefreshDatabase with seeding rather than per-case factories.

Failure modes. Ranked by likelihood and damage:

  1. Silent skip drift — bindings accumulate, skipped routes grow, the suite stays green while checking less. Highest-likelihood, highest-damage. Mitigate with ignoreRoutesWithMissingBindings() deliberately not used, and a CI assertion or periodic report on skipped-route count with a threshold.
  2. Exclusion sprawl — engineers exclude failing routes instead of fixing them. Mitigate with mandatory reasons on every exclude() and review of the exclusion list at each planning cycle.
  3. Flakiness from side effects — queues, HTTP fakes, seeding order. Mitigate with Queue::fake(), Http::fake(), and RefreshDatabase in the base test case; expect this to be the bulk of week-one triage.
  4. False confidence — leadership reads "all routes green" as coverage. Mitigate by never reporting this metric without the skip count beside it.
  5. Version cliff — a Pest/PHP upgrade forces the 1.2.x move and the package becomes a blocker on a platform upgrade rather than a bystander. Mitigate by pinning and treating the bump as a scheduled platform task.
  6. CI cost — see scaling above.

Ramp-up. Effectively flat for anyone who has written a Pest test: the DSL is four methods (include, exclude, bind, setUp) plus any TestResponse assertion. First-value time is measured in hours, and the first run typically surfaces one or two real 500s, which is the fastest way to buy credibility for the initiative. The learning curve is not the API — it is the discipline of maintaining the skip baseline and resisting exclusion sprawl. Frame the rollout around that discipline, not around the install, and set the success metric accordingly: not "package installed and green," but "skipped-route percentage trending down quarter over quarter, with every exclusion carrying a written justification."

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode