macpaw/behat-api-context
MacPaw's Behat API Context provides ready-made Behat steps for testing HTTP APIs in PHP. Build requests with Guzzle, send them, and assert status codes, headers, JSON payloads, and response structure, making REST API acceptance tests quicker to write and maintain.
Headline finding (unchanged): this is a Symfony Bundle, not a Laravel package. The request frames it as a "Laravel/PHP package," but the repository's own documentation states it is a PHP Composer package and Symfony Bundle. Laravel has no bundle/DI-extension equivalent, so the package's Symfony-specific value (container wiring, configuration tree, service registration) has no host in a Laravel application. Only the Behat context class itself — and only if it accepts its collaborators (HTTP client, base URI, serializer) via constructor — is potentially portable. That distinction drives every downstream conclusion.
What v3.1.0 changes. The release is a chore/maintenance cut, not a feature cut: dependency constraints widened "to support latest packages," an AGENTS.md added, and dependencies refreshed. Two implications matter to us and one does not:
AGENTS.md plus a second-party PR and a prompt release indicates the maintainer is actively stewarding the repo and has started codifying contributor/AI-agent guidance. With 6 stars and 0 dependents, maintenance signal is the scarcest thing this project has; this improves it slightly.Caveat worth stating plainly: "widen dependencies" is a constraint change, not a compatibility claim. Widened ranges expand the untested permutation matrix. There is no evidence in the notes of a CI matrix exercising the newly admitted Symfony/PHP combinations, so the resolution may now succeed without being validated. That is a better failure mode (silent rather than blocking) but still a failure mode.
Architecture fit. The real deliverable here is a Behat ApiContext: Gherkin step definitions that issue HTTP requests and assert on responses. In a Laravel codebase the equivalent is already first-class — $this->getJson() / $this->postJson() on the framework's test case, plus Http::fake() for outbound calls. Adopting this package means adding Behat (a non-trivial runner with its own bootstrap, behat.yml, hooks, and transforms) purely to obtain step definitions that are largely mechanical. Fit is therefore low for the framework, moderate for the tooling — it only makes sense in an organization already committed to Behat as a cross-service BDD standard. Unchanged by v3.1.0.
Integration feasibility. Two paths exist:
behat.yml, construct its dependencies in features/bootstrap, and shim Symfony-typed dependencies with Laravel equivalents (Laravel's Http client behind PSR-18, symfony/serializer or a JSON decoder). Viable only if the class does not reach into Symfony\Component\DependencyInjection or a kernel at runtime.ApiContext of roughly 150–300 lines covering request steps, JSON path assertions, status assertions, and auth headers. Lower total cost, no third-party coupling, no version-conflict surface.v3.1.0 raises the prior probability of path 1 clearing its dependency gate, but does not change path 1's remaining costs — Behat adoption, context shimming, and a step rewrite. The one-to-two day spike still settles it, and it is now cheaper to run because the constraint audit is less likely to dead-end. Do not commit to Behat adoption before that spike closes.
Technical risk. Updated ranking of concrete issues:
--with-all-dependencies gymnastics. Treat a clean resolve as a green light to spike, not as validation.phpcs.xml.dist sets ignore_errors_on_exit=1, so composer run code-style exits 0 even with violations. CI can go green on a dirty tree. Any fork must patch this. Not addressed in this release.docker-compose.yaml targets PHP 8.0 while the package requires 8.1+, so the documented container path is broken — signals that the maintainers' own dev loop has drifted from the stated requirement. Not addressed in this release, and the dependency widening makes the stale compose file more misleading, not less.AGENTS.md modestly improves the fork's onboarding story.Key questions for the spike owner. (Revised — the first one changed meaningfully.)
require and require-dev constraints, and do they resolve cleanly against our Laravel, PHP, and Symfony component versions? Does composer why-not come back empty on our target matrix?composer.json.Extension/Configuration class that the context depends on, or is it optional wiring?@Transform, custom contexts) without forking?AGENTS.md prescribe, and does it conflict with our contribution or vendoring conventions?Stack fit. Poor as a library, acceptable as a reference implementation. The honest framing for stakeholders is unchanged: we would not be "integrating a Laravel package"; we would be borrowing a Symfony-targeted context and either porting or reimplementing it. v3.1.0 makes the borrowing cheaper by removing a likely Composer dead-end; it does not make the package a runtime dependency we should carry. Treat the repository as documentation of a step vocabulary and an assertion style.
Migration path. There is no incremental path from PHPUnit/Pest to Behat — it is a parallel test harness, not an upgrade. If the organization's goal is readable API specifications shared with QA and product, Behat earns its keep and this package is a reasonable starting scaffold. If the goal is more API coverage, stay on Pest/PHPUnit with Laravel's HTTP test helpers; the ROI on Behat is negative for a single Laravel service. The v3.1.0 dependency widening reduces the cost of trying Behat with this scaffold; it does not improve the ROI calculation.
Compatibility. PHP 8.1+ aligns with Laravel 10 (8.1) and Laravel 11/12 (8.2). The previously binding constraint was Symfony component versions; v3.1.0 explicitly widens them, so Laravel 11/12 compatibility is now expected rather than doubtful — but confirm the resolution empirically in a throwaway branch. The Symfony Bundle registration step must still be omitted entirely outside a Symfony kernel; attempting kernel bundle registration in Laravel will fail at bootstrap. Behat's parallel execution and per-scenario app isolation must still be solved by us; this package does not address them.
Sequencing. (Step 1 is now cheaper and lower-variance; the rest is unchanged.)
composer.json constraints against the target Laravel version in a throwaway branch. Confirm upstream CI covers the combination we land on. Stop here on conflicts.GET feature end to end.ignore_errors_on_exit disabled.Maintenance. Low direct maintenance cost if the package is used as shipped (isolated to require-dev), and the upstream support picture is marginally better than at last assessment: two merged PRs, a release, and an AGENTS.md signal an engaged maintainer rather than a dormant repo. It remains the case that with 6 stars and 0 dependents we should assume we are effectively the maintainer of our copy — the recent release date is a weak signal given the user base size, and one maintenance release is not a trend. MIT licensing and max-level PHPStan make a fork a half-day exercise rather than a rewrite; budget for it as a contingency, not a plan. Note that widened dependency ranges increase the chance a future composer update pulls in an untested component version; pin exact versions in our lockfile and bump deliberately.
Support. No commercial support, no community. Escalation is: read the source. Any team adopting this needs at least one engineer comfortable debugging Behat context internals, not just writing Gherkin. Factor that into ramp-up cost, not license cost (which is zero). AGENTS.md is a small onboarding assist for the fork scenario but is not support.
Scaling. Unchanged and independent of the release — a test dependency has no production footprint. Behat suites grow superlinearly in wall-clock time because each scenario incurs a full app boot and HTTP round trip. Plan for parallel workers with isolated databases early, or the suite crosses the 10-minute threshold within a quarter and engineers start skipping it. Network-bound steps against a live environment are the primary scaling failure; all requests must hit an in-process or ephemeral app instance.
Failure modes, ranked. (Reranked in response to v3.1.0.)
ignore_errors_on_exit=1 lets style violations pass CI unnoticed. Patch immediately in any fork. Now the top unresolved defect.require-dev, lockfile-pin, and audit at every major Laravel bump.Ramp-up. Engineers new to Behat need roughly two to three days to become productive with Gherkin, context classes, hooks, and transforms — a cost independent of this package and unaffected by v3.1.0. If the team already runs Behat elsewhere, that cost is zero and this package becomes a modest accelerator. If it does not, the Behat adoption decision dominates the package decision and should be made first, on its own merits.
TPM recommendation. Treat as a reference implementation, not a dependency. v3.1.0 improves the odds that the dependency audit passes and demonstrates a maintainer who is still attentive; it does not ship a single new step definition and does not narrow the framework mismatch. Run the (now cheaper) dependency-and-spike audit; if constraints resolve cleanly and the shipped step vocabulary covers more than half of our API surface, adopt with a shim and a patched fork under internal ownership. Otherwise, lift the step vocabulary and write a ~250-line Laravel-native context. Given 0 dependents, no new functionality in this release, and a persistent framework mismatch, the expected value of a native context remains higher in most Laravel scenarios — and the low opportunity score (33.07) still reinforces that this niche is neither growing nor differentiated enough to warrant strategic dependency.
How can I help you explore Laravel packages today?