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 Global Assertions Laravel Package

pestphp/pest-plugin-global-assertions

A Pest plugin that adds global assertion helpers like assertTrue(), assertEquals(), and assertSame() to your test suite, bringing familiar PHPUnit-style assertion functions to Pest tests without extra imports or setup.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Verify the constraint surface before you install. The plugin is Pest-only (it does nothing for a PHPUnit-only suite) and has single-digit stars with no downstream dependents, so the version matrix is your first question, not your last:

composer require --dev pestphp/pest-plugin-global-assertions
composer show pestphp/pest-plugin-global-assertions   # Pest/PHPUnit/PHP constraints

Confirm the listed Pest major matches the one your suite runs, then pin the resolved version (commit composer.lock). Keep it strictly in require-dev.

2. Read the source before the README. The published docs describe intent ("define reusable assertions once, use them anywhere") but not the contract: the registration signature, how $this is bound inside an assertion, and whether an assertion returns a value you can chain from. Open vendor/pestphp/pest-plugin-global-assertions/src/ and read the single registration class — it is small, and it is the only authoritative documentation. Fifteen minutes there prevents a day of guessing at the call site.

3. Know where declarations live. Plugins are auto-discovered via extra.pest.plugins; your assertions get declared once in tests/Pest.php (or a file that tests/Pest.php requires) — the bootstrap Pest loads before every test in the suite. That placement is the whole point: no uses(SomeTrait::class) in every file.

4. Smoke-test with one trivial assertion. Register something with an obvious pass and fail path, call it from a single test, run ./vendor/bin/pest --filter=YourTest, and deliberately break it so you see what a failing global assertion prints. Read that output critically: does it name the assertion and show the offending value? If not, that's a cost you're accepting for the whole suite.

5. Pick the right first use case. Not "custom assertions are nice." Pick one helper closure that is copy-pasted across three or more test files — most likely a cross-cutting policy check (assertValidTaxId, assertWithinSla, a Money formatting rule`) — and make only that global. A one-file convenience should stay a local helper.

Implementation Patterns

Build a catalogue, not a dumping ground. Add assertions one domain at a time, each in a named file required from tests/Pest.php (e.g. tests/Assertions/Billing.php). A flat append-only list becomes unowned within a quarter; a file per domain keeps ownership obvious and makes grep the discovery mechanism.

Name for the domain, prefix for the namespace. Assertions registered globally share a namespace with core expectations and any other plugin. Use domain-language, verb-first names (toBeRefundable, toBeWithinDays, toAllBePublished) and consider a short domain prefix in monorepos where several teams register into the same suite. Collisions surface as confusing "unknown method" or wrong-behaviour failures, not as install errors.

Match the tool to the shape of the check. If the assertion is a matcher over one value, expect()->extend() in tests/Pest.php already does it with no dependency — use that. Reach for a global assertion when the check is multi-step or process-shaped: verifying a state transition, a side effect, a composite business rule that would otherwise be a chain of expect() calls repeated verbatim. Being honest about this boundary is what keeps the plugin justified.

Treat failure messages as the deliverable. A global assertion is consumed by reviewers who weren't there when it was written. Spend the effort on the message: name the rule, include the actual value. A global assertion with a weak message is a net negative — the reviewer can't tell whether to blame the assertion or the code.

Write tests for your assertions. A global assertion that silently passes is worse than duplicated inline code. Keep a small Pest file that exercises every assertion's pass and fail paths; it's the only guard against a refactor quietly inverting a rule that dozens of suites depend on.

Parameterise rather than proliferate. toBeWithinDays(14) beats toBeWithinTwoWeeks() / toBeWithinThirtyDays(). Every parameter added is one fewer name in the global namespace and one fewer collision candidate.

Monorepo wiring. In a multi-package repo, each package's tests/Pest.php is its own bootstrap. If the catalogue should be shared, either require it from each Pest.php (explicit, survives refactors) or publish it as an internal path repository. Don't rely on one package's Pest.php being loaded for another's tests.

Gotchas and Tips

Name collisions are the default failure mode. There is no obvious namespacing story in the registration. Prefix, keep names domain-specific, and re-run the full suite (not just your filter) after adding an assertion — a collision can silently shadow or conflict with an expectation used elsewhere.

Load order and global state. Assertions are registered in the bootstrap, so anything they capture at registration time (a container binding, a config value, $this from a test case) is evaluated in a specific lifecycle moment. Prefer assertions that take everything as arguments and read state at call time. If an assertion needs $this, verify the binding explicitly under RefreshDatabase — the test-case instance changes per test.

Parallel testing is unverified territory. Run pest --parallel early in the pilot, not at the end. A plugin that only works under serial execution will look fine for a sprint and then fail the moment someone flips the CI flag.

Debugging a wrong result. If an assertion passes when it shouldn't, add a temporary test that calls it with obviously-bad input; if it still passes, the assertion never got registered (check the bootstrap actually loads the file) or the closure resolved to something else. If it fails with an unhelpful message, that's your cue to rewrite the message, not to add debugging output at the call site.

Watch the upgrade surface from day one. This is a dev-only dependency with no ecosystem gravity: an unmaintained plugin that breaks on a Pest major bump turns an afternoon's curiosity into a roadmap blocker for the whole framework upgrade. Nominate an owner, track it against your Pest version, and run CI against the oldest and newest Pest/PHP in your support window.

Document the exit path while the pilot is still running. The realistic fallback is folding the assertions back into a local trait or into expect()->extend() + a shared file required from tests/Pest.php. Write that down before adoption, so "we can remove this in an afternoon" stays true. The MIT licence also makes vendoring or forking a genuine hedge if the registry becomes load-bearing.

Never let it into a production conversation. Zero runtime footprint, never shipped to customers. Keep it framed as a test-authoring convention, and keep the boundary explicit when socialising it — it's a readability decision, not an architecture one.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
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