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

Behat Api Context Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Require it as a dev dependency. It's a Composer package, not an app, so it belongs in require-dev:

    composer require --dev macpaw/behat-api-context
    

    The package requires PHP 8.1+ (the repo's docker-compose.yaml targets 8.0 and is stale — use a local 8.1+ runtime). As of v3.1.0 the dependency constraints were widened to support the latest versions of its transitive packages, so if an earlier 3.x install was blocked by an upper-bound conflict in your lockfile, retry on ^3.1.

  • Register the bundle (Symfony). Because it ships as a Symfony Bundle, add it to config/bundles.php if your app uses Symfony's bundle registration, or rely on Flex auto-registration. Then make the bundle's services available to the test kernel.

  • Wire it into behat.yml. Activate the provided API context in your suite, passing at minimum a base URL:

    default:
      suites:
        api:
          contexts:
            - MacPaw\BehatApiContext\Context\ApiContext:
                base_url: '%env(API_BASE_URL)%'
          paths: [ '%paths.base%/features/api' ]
    

    Exact parameter names should be confirmed against the package's context constructor — run vendor/bin/behat -dl after enabling it and you'll get the authoritative step list.

  • Look here first: the package README for the step catalog, then src/Context/ApiContext.php for constructor options and request/assert helpers, then CONTRIBUTING.md, AGENTS.md (added in v3.1.0 — the maintainers' agent-facing conventions, useful as a condensed map of the repo), and the composer.json scripts for how the maintainers expect it to be exercised.

  • First use case — a smoke spec. A single-feature file that hits one JSON endpoint, asserts status and a field, is the fastest way to validate your config:

    Feature: Health
      Scenario: API is up
        When I send a GET request to "/health"
        Then the response status code should be 200
        And the response body should contain "ok"
    

    Treat the quoted step text as illustrative; confirm the real phrasing with behat -dl.

Implementation Patterns

  • Base URL + profiles. Drive base_url (and any auth defaults) from environment variables, and add Behat profiles for local, ci, and staging. This is the single biggest ergonomic win — the same feature runs against any deployed environment.

  • Background for shared headers. Put common Authorization, Accept: application/json, and API-version headers in a Background: block per feature file, or in a @BeforeScenario hook in a small custom context, rather than repeating them in every scenario.

  • Payloads via PyStringNode or data tables. The natural pattern for JSON bodies is a heredoc string the context POSTs with the right Content-Type, e.g. When I send a POST request to "/users" with body: followed by a JSON docstring. Data tables are better for flat form-style or header sets.

  • Chain requests to test real flows. Create → fetch → update → delete within one scenario, asserting on each response. This is where a Behat API context shines versus one-off HTTP tests: you keep readable Given/When/Then while exercising stateful behavior.

  • Extend, don't duplicate. Subclass the base ApiContext to add domain steps (Given a user "alice" exists), and keep HTTP mechanics in the parent. Behat composes multiple contexts per suite, so separate "HTTP transport" from "domain setup" cleanly.

  • Fixtures and resets. Pair it with a DB-reset hook (Doctrine PurgeDatabase-style or a truncate script) in @BeforeScenario. API contexts tend to leak server state between scenarios; resetting is a prerequisite for parallel/repeatable runs.

  • Tag-driven setup. Use @auth, @slow, @skip-ci tags with hooks to swap credentials or skip flaky external calls. Keeps a single suite usable from laptop to pipeline.

  • Assert on structure, not strings where possible. Prefer JSON-path/field assertions over body contains "..." for anything that matters; substring checks are brittle against key ordering and whitespace. Where the package only exposes substring/JSON checks, wrap stricter assertions in a custom step.

Gotchas and Tips

  • docker-compose.yaml is outdated. It targets PHP 8.0 but the package needs 8.1+. Use a local PHP 8.1+ install for dev/test rather than the provided compose file.

  • composer run code-style always exits 0. phpcs.xml.dist sets ignore_errors_on_exit=1, so CI will happily "pass" with violations. Grep the output for ERROR lines, or run vendor/bin/phpcs directly in your own pipeline.

  • PHPUnit deprecation noise is expected. phpunit.xml.dist uses PHPUnit 10-deprecated attributes; don't chase those warnings when triaging your own failures.

  • Watch for scenario state leakage. Cookies, auth tokens, and the underlying HTTP client can persist across scenarios depending on how the context is constructed. Explicitly reset client/cookies in @BeforeScenario so a green suite isn't order-dependent.

  • Content-Type and encoding mismatches. A body sent without Content-Type: application/json will often fail server-side validation and look like an API bug. If a request "mysteriously" 400s, dump the outgoing headers first.

  • Type strictness in assertions. JSON decodes integers/floats and strings differently; assertions comparing "200" vs 200 or comparing floats exactly will trip you up. Normalize types in custom steps.

  • Trailing-slash and base-URL joining. Concatenating base_url + path naively produces //health or drops path segments. Verify how the context joins URLs, especially when profiles differ.

  • Small ecosystem (single-digit stars, no dependents). Expect thin docs and occasional gaps. Budget time to read src/, and pin the version in composer.json — a ^3.1 constraint is now reasonably safe (v3.1.0 is a dependency-widening/doc release with no API changes), but don't float on * or dev-main in a sprint-critical pipeline. Be prepared to vendor-patch or subclass if a step doesn't cover your case.

  • Upgrading 3.0.x → 3.1.0 is low-risk. No new or renamed steps, no deprecations, no constructor changes were announced — the release is dependency widening plus the addition of AGENTS.md. A composer update macpaw/behat-api-context and a full Behat run is adequate verification; you should not need to touch feature files or context subclasses.

  • Debugging moves: vendor/bin/behat -dl to enumerate steps, --format=pretty --stop-on-failure for readable failures, and a temporary custom step that dumps the last response body/headers. These three cover most "why did this assertion fail" investigations.

  • Extend at the edges. The supported extension points are almost certainly subclassing the context and adding steps; overriding core request methods is possible but ties you to internals. Prefer new steps over monkey-patching protected methods, so upgrades stay cheap.

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.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect