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 Expectations Laravel Package

pestphp/pest-plugin-expectations

An extension for the Pest PHP testing framework that adds extra expectation APIs, letting you write fluent, readable assertions with expect(). It supports custom expectation creation and ships additional built-in expectations for cleaner, more expressive test suites.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Framing. The TPM decision is not "adopt or reject a testing library." The capability this package provides — chainable, domain-readable assertions like expect($order)->toBePaid() — is native to Pest 2.x/3.x via expect() and expect()->extend(). The real decisions are: (1) how much engineering capacity we spend confirming that, (2) what we do with the removal, and (3) whether the repo becomes a reusable decision template for the next "community plugin vs. framework-native feature" debate. The deliverable of this evaluation is a decision record, a scoped removal ticket, and a guardrail — not an integration plan.

Architecture fit. Dev-only tooling with a narrow blast radius by construction: no runtime code path, no production service provider, no database, queue, or HTTP surface. It plugs into Pest's expectation registry and delegates the actual assertion to PHPUnit. That is a clean fit with the plugin contract — which is exactly why it became redundant, since Pest absorbed both the expect() entry point and custom-expectation authoring into core. On any current Laravel/Pest stack the package is at best a no-op and at worst a duplicate-registration hazard at test bootstrap. The dangerous failure mode is not a crash; it is green tests that assert less than reviewers believe.

Integration feasibility. Mechanically trivial (composer require --dev, autodiscovery, zero configuration); practically gated by dependency resolution. A final release dated 2021-05-19 implies PHP 7.x/8.0-era and PHPUnit 8/9-era constraints. On PHP 8.2+ with PHPUnit 10/11, Composer will either refuse resolution outright or force downgrades that destabilize the rest of the test toolchain — a cost far larger than the convenience. Diligence flag: any metadata claiming compatibility with Pest 2.x/3.x is unverified and inconsistent with the archive date and the absence of a release after May 2021. The only admissible evidence is a throwaway-branch install — and even a clean install does not create a maintenance path, so a successful spike is not an approval signal.

Technical risk. High and asymmetric. The downside is not that the plugin breaks; it is that the plugin prevents everything else from moving.

Risk Likelihood Impact TPM read
Abandonment / no security response path Certain (archived, 0 dependents) Medium No upstream to inherit fixes from; 100% of burden transfers to us
Duplicate expect() registration / shadowed assertions Medium on Pest 2.x+ High (silent under-testing) The dangerous case is a passing suite that verifies less than the review process assumes
Toolchain ceiling on PHP / PHPUnit / Pest High over 12–18 months High Converts a dev convenience into a blocker on every future upgrade window
Autoload / plugin-discovery conflict with other Pest plugins Low–Medium Medium Manifests as non-obvious bootstrap failures under incident pressure

Key questions for the owning team.

  1. What Pest and PHPUnit versions are pinned in the lockfile, and does core already provide expect() and expect()->extend()?
  2. Does the full suite pass with the plugin removed — i.e. is this a deletion candidate rather than an integration candidate?
  3. Is any bespoke expectation built on this plugin's registration surface, or is it a pass-through to behavior core already owns?
  4. If it is pinned for legacy reasons (Pest v0 / PHPUnit 8–9), what is the owner, cost, and dated exit for the Pest major upgrade that retires it?
  5. What is the CI blast radius if the package stops resolving on a future PHP minor, and who gets paged?
  6. What coverage evidence proves no assertions were silently dropped after removal?

Integration Approach

Stack fit. Laravel + Pest + PHPUnit, require-dev only. If it survives at all, the correct posture is a single dev dependency, no config publishing, no provider registration — and explicitly not alongside or in place of core expectations. Anything more is duplicated surface area with two owners and no clear source of truth.

Migration path. The recommended path is off this package, not onto it. Sequence:

  1. Inventory every expect() call and bespoke expectation across the suite; tag each as deletable, rewrite as core expect()->extend(), or replace with a plain PHPUnit assertion. This same inventory doubles as the sizing input for any adjacent PHPUnit → Pest migration workstream, because custom assertion surface area is exactly what has to be rewritten or retired during the move.
  2. Confirm the host Pest minor supplies expectations natively (2.x+ does) before touching composer.json.
  3. Remove from composer.json, run composer update --dev, execute the full suite plus a coverage diff to catch silently dropped assertions.
  4. Rewrite bespoke expectations as first-class Pest expectations — typically well under an engineer-day, no licensing cost, no supply-chain exposure.
  5. Guard with a composer conflict rule or CI lint step so the dependency cannot be reintroduced by copy-paste. Guardrails are cheaper than re-litigating the decision.

For a genuinely legacy Pest v0 codebase, the path inverts: treat the plugin as a knowingly frozen stopgap, isolate it behind the test bootstrap, and track the Pest major upgrade as the remediation work item — not the plugin. The unit of work is the framework upgrade; the plugin is just a passenger.

Compatibility. Assume PHP ≤8.0 and PHPUnit ≤9 until proven otherwise by a real install in a disposable branch. Do not infer support from the MIT license, from 2021-era green builds, or from package metadata. If validation is required, verify with composer why-not rather than reasoning about it.

Sequencing. Spike → decide → change, and never bundle. Timebox the spike (install, run suite, capture resolution conflicts and deprecation noise), then choose remove (default), pin and freeze (legacy only, with a dated exit), or replace with core. Keep this off the same change window as a PHP or framework upgrade: dependency-resolution interactions are the hardest failures to debug, and they deserve isolated scope and a named owner.

Operational Impact

Maintenance. Zero upstream maintenance and no viable fork strategy at 21 stars and 0 dependents. The artifact is frozen, so 100% of the maintenance burden transfers to us, and the only available maintenance action is eventual removal. Budget for the exit, not for stewardship — a stewardship line item against an archived repo is a budget that can never pay off.

Support. No vendor, no maintainer, no issue triage, no CVE channel. Internal support means one or two engineers reverse-engineering Pest's plugin registration under incident pressure. The dependency's purpose and its removal ticket should be written down at the moment of adoption, or the next team will treat it as load-bearing infrastructure.

Scaling. Runtime cost is nil — dev-only, no effect on latency, throughput, or infrastructure spend. The scaling risk is organizational: the version ceiling propagates to every developer laptop and every CI runner, so its cost grows with headcount and release cadence rather than with traffic. It is a tax that compounds quietly until an upgrade is blocked and nobody can identify the cause.

Failure modes to watch.

  • Composer resolution failure after a PHP or PHPUnit bump, halting CI with an unclear owner.
  • Duplicate expectation registration causing bootstrap fatals or shadowed assertions.
  • Silent assertion drift producing passing tests that verify less than reviewers assume.
  • Plugin-discovery or autoload conflicts with other Pest plugins.
  • Zombie dependency: no one remembers why it is present, so no one removes it during the upgrade that needs it gone.

Ramp-up. Low for engineers — the API is idiomatic Pest and requires no training. The real ramp-up cost is institutional: new joiners reasonably assume anything in composer.json is current and supported. Budget a one-paragraph ADR stating that the package is archived, why it exists if it still does, what replaces it, and who owns the exit.

Recommendation. Do not adopt; do not budget. Own this as a small removal workstream — confirm core expectations cover the suite, delete the dependency, publish the ADR, add the CI guard — and use it as the worked example for a standing rule: test-tooling extensions live in-repo on framework-native extension points, and single-maintainer plugins are permitted only with a named owner and a dated exit. The repo's highest value to us is as a decision template — a clean worked example of capability being real, a community package supplying it, and the framework then absorbing it into core — applied to the next build-vs-buy-vs-use-the-native-feature debate on developer tooling.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource