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

Phiremock Codeception Extension Laravel Package

mcustiel/phiremock-codeception-extension

A Codeception extension that starts a Phiremock Server before a test suite and stops it afterward. Configure listen address, binary path, logs, debug, readiness waits, and expectations for easier HTTP mocking.

View on GitHub
Deep Wiki
Context7

Getting Started

First, decide whether this package earns its place. This extension does exactly one thing: it starts phiremock-server before a suite runs and stops it afterwards. If your Laravel tests call external APIs through Http/Guzzle inside the same PHP process, Http::fake() + Http::preventStrayRequests() already gives you isolation with no port, no child process, and no extra harness. Adopt this package when the mock must be a real listening HTTP server: browser/acceptance tests, queue workers or Octane running out-of-process, SDKs that bypass Laravel's client, a package under test that hardcodes curl, or a third party that needs to call you (webhooks).

Install (mind the version fork — this package's majors track Codeception and phiremock-server majors):

# Codeception 5 / PHP 8 / phiremock-server v2 / Symfony 8
composer require --dev mcustiel/phiremock-codeception-extension:^4.0

# Laravel 11 era, Codeception 5, phiremock-server v1
composer require --dev mcustiel/phiremock-codeception-extension:^3.1

phiremock-server is an optional dependency — the extension will happily exec a phar, a global binary, or a Docker wrapper instead. If you want the default vendor/bin/phiremock resolution to work, install it locally too.

Second install: the module. Since v2.0 the extension no longer talks to the server. It only performs lifecycle. Creating, resetting, and verifying expectations is the job of mcustiel/phiremock-codeception-module. Skipping this is the single most common "why is nothing stubbed" mistake.

composer require --dev mcustiel/phiremock-codeception-module

Enable it in the suite's *.suite.yml, not the global codeception.yml. Per-suite config has been supported since Codeception 2.2.7 and prevents the server starting for suites that never need it:

# tests/Acceptance/api.suite.yml
actor: ApiTester
modules:
    enabled:
        - REST:
            depends: PhpBrowser
            url: http://127.0.0.1:18080
        - \Mcustiel\Phiremock\Module\Phiremock:
            host: 127.0.0.1
            port: 18080
extensions:
    enabled:
        - \Codeception\Extension\Phiremock
    config:
        \Codeception\Extension\Phiremock:
            listen: 127.0.0.1:18080
            wait_until_ready: true
            debug: true
            expectations_path: tests/_expectations/payments

First use case — stub a flaky vendor for an acceptance suite. Drop JSON expectations in tests/_expectations/payments/, point your app's base URL at http://127.0.0.1:18080 via an env var in codeception.yml's params/env block (e.g. PAYMENTS_BASE_URL), bind that var into config/services.php, and run vendor/bin/codecept run Acceptance. The suite boots the mock server, the JSON files are loaded at startup, and teardown kills the process.

Where to look first: the module's README for the expectation API, then the extension's Parameters section for wait_until_ready, expectations_path, and extra_instances. Avoid the extension README's examples verbatim — some still show pre-v2 configuration.

Implementation Patterns

Fixture-first expectations. Keep durable, hand-written JSON in expectations_path (they're loaded when the server boots), and use the module for per-test expectations in _before():

public function _before(ApiTester $I): void
{
    $I->haveHttpStubFor(\Mcustiel\Phiremock\Client\Utils\A::getRequest()
        ->andUrl(\Mcustiel\Phiremock\Client\Utils\A::isEqualTo('/v1/charges'))
        ->andHeader('Idempotency-Key', \Mcustiel\Phiremock\Client\Utils\A::matches('/^ch_/')));
}

The distinction matters: file-based expectations are shared across the whole suite; module-created stubs can be reset between tests ($I->cleanExpectations()), which is what you want for anything asserting call counts or one-shot responses.

One extension block, env-var-driven base URL. Since the port is fixed in YAML, make it a parameter so CI can shift it (listen: 127.0.0.1:%PHIREMOCK_PORT%) and mirror that same value into the app config. Any drift here produces connection-refused errors that look like application bugs.

Use extra_instances for the second endpoint, not a second extension. HTTP + HTTPS, or two different vendors on two ports:

config:
    \Codeception\Extension\Phiremock:
        listen: 127.0.0.1:18080
        expectations_path: tests/_expectations/payments
    extra_instances:
        -
            listen: 127.0.0.1:18081
            expectations_path: tests/_expectations/shipping
            suites: [acceptance, api]

Give each instance its own expectations_path, or they will load the same files and you'll get cross-talk between vendors.

HTTPS vendors. Supply certificate, certificate_key, and cert_passphrase. The mock server serves the cert; your HTTP client still needs to be told to trust it — set verify => /path/to/cert (or disable verification in the test env only) in the Laravel HTTP client config you inject during the suite.

Boot readiness: prefer wait_until_ready: true (requires phiremock-client via composer) over start_delay. start_delay is a blind sleep and will either slow every suite down or occasionally race. If you're stuck on a phar-only setup where the client isn't installed, start_delay: 1 plus a retry at the test level is the fallback.

Docker in CI. Point bin_path at a launcher script you own that translates the server flags to docker run (or at a checked-in phar). The extension simply execs the binary with a flag string, so any executable that forwards argv works. Note server_factory is unavailable in this mode — it requires phiremock-server as a local composer dependency.

Contract capture. Run once against the real sandbox with debug: true, harvest the response bodies from the log, and freeze them as JSON expectations. From then on the suite runs hermetically. This is the highest-leverage pattern here: it converts a credentialed, rate-limited sandbox into a checked-in fixture.

Log hygiene. Send logs_path to tests/_output/phiremock so Codeception's artifacts pick it up and CI uploads it on failure. Turn debug on for the whole CI job but leave it off locally; the request trace is what tells you whether an expectation failed to match (server responded 404 with a phiremock explanation) or never reached the mock at all.

Gotchas and Tips

Extension ≠ module, post-v2. The extension starts and stops the process; it cannot create expectations and never will. If composer require leaves you with only the extension, you have a running mock server that 404s everything.

suites: [] means all suites, not none. The empty array is the "no filter" sentinel. If you're trying to restrict the server to one suite, you must actually list it.

Port collisions in parallel test runs. 0.0.0.0:8086 is the default and will bite you on any machine running two checkouts, or under Paratest-style fan-out. Always pin 127.0.0.1 and a non-default port, and derive it from a param.

wait_until_ready hard-depends on phiremock-client. Enabling it without that package installed isn't a config error the extension catches gracefully — you'll get a class-not-found failure at suite boot that points at the extension, not at the missing client. If you're on the phar path, either install the client or use start_delay.

bin_path resolution. Default is codeception_dir/../vendor/bin; absolute-path detection was fixed relatively late (v2.1.2). If you're on an older release and have Windows or symlinked checkouts, pass a fully qualified path and verify it's executable before blaming the mock.

Orphaned processes. A fatal error or SIGINT during a suite can leave the server holding the port, and the next run fails with a bind error rather than a clear lifecycle message. When a suite fails to start, check ps aux | grep phiremock and the port before touching config.

Log file may not be created when PCNTL is disabled (fixed in 1.4.1, but the symptom — silent absence of logs — persists if logs_path isn't writable). Assert the directory exists and is writable in your CI bootstrap.

Editing expectation JSON mid-suite has no effect. They're read at server startup. For dynamic or per-test stubs, use the module; restart the server (or add an expectation via the client) otherwise.

server_factory is scoped to composer installs only. It lets you swap in a Guzzle 7 ClientInterface when phiremock-server v1 assumed Guzzle 6. On v4/phiremock-server v2 this is largely resolved — don't copy the factory example unless you're on v1.

Version triple-alignment. extension v4 ↔ phiremock-server v2 ↔ Codeception 5 ↔ PHP 8; extension v3.x for Laravel 11-era Symfony components. Mixing an extension v2-era config (which owned the connection) with a v3/v4 module produces confusing "expectation not applied" failures.

Vendor risk is real. 31 stars, zero dependents, single maintainer, and a hard Codeception dependency. Contain the blast radius: keep every phiremock reference inside the .suite.yml files and one thin helper class, so swapping to WireMock, Mockoon, or an in-process Http::fake() during a PHPUnit/Pest migration is a config change rather than a rewrite. And surface that migration in any stack-modernization plan — adopting this is an implicit vote to keep Codeception.

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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums