Weave Code
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 Laravel Package

mcustiel/phiremock

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup for Laravel

  1. Install via Composer (dev dependency):

    composer require-dev mcustiel/phiremock guzzlehttp/guzzle
    
  2. Start the Phiremock Server:

    vendor/bin/phiremock-server
    

    (Default port: 8080. Configure via --port flag if needed.)

  3. First Mock in a Test:

    use Mcustiel\Phiremock\Client;
    use Mcustiel\Phiremock\Expectation;
    
    // In your Laravel test (e.g., FeatureTest)
    public function test_mocked_api_call()
    {
        $client = new Client('http://localhost:8080');
        $client->addExpectation(
            Expectation::create()
                ->withMethod('GET')
                ->withUrl('/api/users')
                ->withResponse(200, ['name' => 'John Doe'])
        );
    
        // Make a request to your Laravel app that calls the mocked endpoint
        $response = Http::get('http://your-app.test/api/external-users');
        $this->assertEquals('John Doe', $response['name']);
    }
    
  4. Verify Requests:

    $requests = $client->getRequests();
    $this->assertCount(1, $requests);
    

First Use Case: Mocking a Payment Gateway

Mock Stripe’s API to test a payment flow without hitting live endpoints:

$client->addExpectation(
    Expectation::create()
        ->withMethod('POST')
        ->withUrl('/v1/charges')
        ->withHeader('Authorization', 'Bearer sk_test_*')
        ->withBodyMatches('/"amount":1000/') // Regex match
        ->withResponse(200, [
            'id' => 'ch_123',
            'status' => 'succeeded'
        ])
);

Implementation Patterns

Workflow: Test-Driven API Development

  1. Define Mocks Early: Create JSON expectation files (e.g., tests/phiremock/stripe.json) for reusable mocks:

    {
      "expectations": [
        {
          "method": "POST",
          "url": "/v1/charges",
          "headers": { "Authorization": "Bearer sk_test_.*" },
          "bodyPattern": "\"amount\":1000",
          "response": {
            "status": 200,
            "body": { "id": "ch_123", "status": "succeeded" }
          }
        }
      ]
    }
    

    Load them in setUp():

    $client->loadExpectationsFromDirectory(__DIR__.'/phiremock');
    
  2. Dynamic Responses: Use request data in responses (e.g., echo back a user_id):

    $client->addExpectation(
        Expectation::create()
            ->withMethod('POST')
            ->withUrl('/api/register')
            ->withResponse(201, [
                'user_id' => '$request.body.user_id', // Dynamic value
                'message' => 'User created'
            ])
    );
    
  3. Stateful Testing: Simulate sequences (e.g., OAuth token flow):

    // First call: Return a token
    $client->addExpectation(
        Expectation::create()
            ->withMethod('POST')
            ->withUrl('/oauth/token')
            ->withResponse(200, ['access_token' => 'abc123'])
    );
    
    // Second call: Require the token
    $client->addExpectation(
        Expectation::create()
            ->withMethod('GET')
            ->withUrl('/api/protected')
            ->withHeader('Authorization', 'Bearer abc123')
            ->withResponse(200, ['data' => 'secret'])
    );
    
  4. Latency Simulation: Add artificial delay for realistic testing:

    $client->addExpectation(
        Expectation::create()
            ->withMethod('GET')
            ->withUrl('/api/slow-endpoint')
            ->withLatency(1500) // 1.5 seconds
            ->withResponse(200, ['data' => 'loaded'])
    );
    

Integration with Laravel

  1. Service Provider: Register Phiremock as a singleton in AppServiceProvider:

    public function register()
    {
        $this->app->singleton('phiremock.client', function () {
            return new Client('http://phiremock:8080');
        });
    }
    
  2. Test Helpers: Create a base test case:

    abstract class PhiremockTestCase extends TestCase
    {
        protected $client;
    
        protected function setUp(): void
        {
            parent::setUp();
            $this->client = app('phiremock.client');
            $this->client->reset(); // Clear expectations
        }
    
        protected function mockApi($method, $url, $response)
        {
            $this->client->addExpectation(
                Expectation::create()
                    ->withMethod($method)
                    ->withUrl($url)
                    ->withResponse($response)
            );
        }
    }
    
  3. Proxy Mode: Forward requests to a real API during development:

    $client->addExpectation(
        Expectation::create()
            ->withMethod('GET')
            ->withUrl('/api/external')
            ->withProxy('https://real-api.example.com')
    );
    

Codeception Integration

  1. Extension Setup: Install the extension:

    composer require-dev mcustiel/phiremock-codeception-extension
    

    Configure in codeception.yml:

    extensions:
        enabled:
            - Mcustiel\Phiremock\Codeception\Extension
    
  2. Module Usage:

    <?php
    $I = new AcceptanceTester($scenario);
    $I->wantTo('Mock a payment API');
    $I->haveHttpMockExpectation(
        'POST',
        '/v1/charges',
        200,
        ['id' => 'ch_123']
    );
    $I->sendGET('/checkout');
    $I->seeResponseCodeIs(200);
    

Gotchas and Tips

Pitfalls

  1. Port Conflicts:

    • Default port (8080) may clash with other services. Use --port flag or configure in config/phiremock.php (if available).
    • Fix: Run Phiremock in a separate Docker container or use a random port:
      vendor/bin/phiremock-server --port $(shuf -i 8080-9999 -n 1)
      
  2. Stateful Mocks Leak Between Tests:

    • Expectations persist across tests unless reset. Always call $client->reset() in setUp() or tearDown().
    • Fix: Use ->withStateful(false) for stateless mocks or wrap in transactions:
      DB::beginTransaction();
      try {
          // Test logic
          DB::commit();
      } catch (\Exception $e) {
          DB::rollBack();
      }
      
  3. Regex Matching Quirks:

    • Body matching with regex (withBodyMatches()) can be fragile. Prefer exact matches (withBody()) for simple cases.
    • Tip: Escape special characters in JSON paths:
      ->withBodyMatches('/"amount":\\d+/') // Matches "amount": 100
      
  4. Latency Simulation Inconsistencies:

    • Latency (withLatency()) is approximate and may vary across environments (e.g., Docker vs. local).
    • Workaround: Use PHP’s usleep() in tests for deterministic delays:
      usleep(1500000); // 1.5 seconds
      
  5. JSON Response Parsing:

    • Responses with JSON bodies must be valid JSON. Phiremock does not auto-serialize arrays.
    • Fix: Explicitly convert responses:
      ->withResponse(200, json_encode(['key' => 'value']))
      
  6. Proxy Mode Limitations:

    • Proxying (withProxy()) does not preserve the original request’s headers/body for verification.
    • Tip: Use proxy mode only for development; replace with explicit mocks for tests.

Debugging Tips

  1. Inspect Requests: Use the REST API to debug:

    $requests = $client->getRequests();
    dd($requests[0]->getBody()); // Inspect raw request body
    
  2. Enable Verbose Logging: Start the server with:

    vendor/bin/phiremock-server --verbose
    
  3. Reset Stuck State: If expectations behave unexpectedly, reset the server:

    vendor/bin/phiremock-server --reset
    
  4. Priority Conflicts: When multiple expectations match, the first 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.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime