imbo/behat-api-extension
A Behat 3 extension that provides an easy way to test JSON-based APIs with readable Gherkin steps. Inspired by behat/web-api-extension and originally written to test the Imbo API, it simplifies HTTP request and response assertions in your test suite.
Architecture fit
Imbo\BehatApiExtension\) that lives entirely in the acceptance-test tier. It ships Gherkin step definitions, a Guzzle-backed HTTP client, and JSON assertion helpers. It never touches the Laravel container, Eloquent, middleware, queues, or the request lifecycle.$this->postJson() / Http::fake() / assertJsonStructure() run in-process, participate in RefreshDatabase, and are fast. This extension drives a real socket against a running app, which is a different and deliberately slower tier.Integration feasibility
composer require --dev imbo/behat-api-extension. MIT, no procurement, no vendor relationship.behat/behat, a behat.yml with a base_url, a bootstrap that boots or targets the Laravel app, an auth mechanism (bearer tokens minted per run for Sanctum/Passport), and — hardest — test-data seeding, since the package manages none.Technical risk
| Risk | Severity | Assessment and mitigation |
|---|---|---|
| PHP floor pinning | Medium | v6.x requires PHP 8.3+ (v5.x required 8.1). Hard gate on CI and deploy images. Pin the extension major to the platform, or upgrade PHP first. |
| Single-maintainer / bus factor | Medium-High | ~110 stars, 0 recorded dependents, maintained primarily for the Imbo project's own API. Actively released and MIT, with a small surface area — forkable, but assume we may own it. |
| Duplicate/rotting test tier | High | The most probable failure is organisational: Behat scenarios drift, duplicate PHPUnit coverage, then quietly rot. Requires an explicit, documented test-strategy boundary before the first commit. |
| Out-of-process state | High | No RefreshDatabase. Data must be seeded through real endpoints or a resettable environment; suite isolation is our problem, not the package's. |
| Release metadata anomaly | Low | The repository metadata lists the latest release as 2026-10-29, which cannot be current. Verify the actual tag before pinning — do not pin blind off the listing. |
| Version-churn pattern | Medium | v5 → v6 changed internal interfaces and raised the PHP floor. Expect a major bump roughly whenever PHP does. Budget a small upgrade task per cycle. |
Key questions to resolve before committing
.feature files — PM/QA, or engineers only?Stack fit
fileinfo, json, and sockets extensions. On a current Laravel stack this is a dev-only Composer dependency with no runtime footprint and no production blast radius.tests/ stays as-is; a new features/ directory and behat.yml are additive. No changes to phpunit.xml, no changes to application code.Migration path
ApiContext that extends Imbo\BehatApiExtension\Context\ApiContext for auth, seeding, and domain-specific steps only. This is the practical hedge against abandonment: if we ever fork or replace the extension, only the base class changes..feature files as the artifact of record for API versioning decisions ("v1 is frozen while these scenarios pass"). That framing is what makes the maintenance cost defensible to stakeholders.Compatibility
composer.json and commit the lock file. The project's history shows interface changes on majors; an unpinned range will break CI on an unrelated composer update.Sequencing
@smoke, @critical), and who owns each.Maintenance
.feature files become actively misleading documentation. Budget an explicit owner and a recurring review slot, or the suite decays within two quarters.Support
Scaling
Failure modes
| Failure | Signal | Consequence |
|---|---|---|
| Environment flake | Intermittent failures on unchanged code | Team loses trust, gates get bypassed, suite is disabled — the classic death spiral. |
| Test-data collision | Order-dependent failures, polluted DB | False negatives; requires resettable, per-run data. |
| Silent drift/duplication | Same behavior asserted in Behat and PHPUnit | Double maintenance cost, divergent expectations, no added coverage. |
| Shallow assertions | Scenarios assert status code only | False confidence in a "contract" that isn't one. |
| PHP/major-version drift | CI fails on upgrade | Forced mid-sprint upgrade work; mitigated by exact pinning and forecasting. |
| Upstream abandonment | No releases, stale issues | Fork or replace; contained by thin contexts and small surface. |
| Secrets leakage | Tokens committed in behat.yml |
Credential exposure in a repo that is often less carefully reviewed than app code. |
Ramp-up
Bottom line for the TPM decision: the package is cheap, small, MIT, and forkable — the license is not the cost. The cost is a second test harness, an owned seeding strategy, and ongoing editorial discipline over a Gherkin suite. Fund it only if product and QA will actually author the scenarios; otherwise decline and stay with Laravel's in-process HTTP tests.
How can I help you explore Laravel packages today?