Testing
Tips and patterns for testing your PayRex integration in your Laravel application.
Testing Webhook Listeners
Using the Artisan Command
The quickest way to verify your webhook listeners work is the payrex:webhook-test command:
php artisan payrex:webhook-test payment_intent.succeededThis dispatches a synthetic event locally without making any API calls. See Artisan Commands for details.
Dispatching Events in Tests
In your feature or unit tests, dispatch webhook events directly:
use LegionHQ\LaravelPayrex\Events\PaymentIntentSucceeded;
it('fulfills order on payment success', function () {
$order = Order::factory()->create(['status' => 'pending']);
PaymentIntentSucceeded::dispatch([
'id' => 'evt_test_123',
'type' => 'payment_intent.succeeded',
'livemode' => false,
'data' => [
'id' => 'pi_test_456',
'resource' => 'payment_intent',
'amount' => 10000,
'metadata' => ['order_id' => (string) $order->id],
],
'created_at' => now()->timestamp,
'updated_at' => now()->timestamp,
]);
expect($order->fresh()->status)->toBe('paid');
});Asserting Events Were Dispatched
Use Laravel's Event::fake() to verify that webhook processing dispatches the correct events:
use Illuminate\Support\Facades\Event;
use LegionHQ\LaravelPayrex\Events\PaymentIntentSucceeded;
use LegionHQ\LaravelPayrex\Events\WebhookReceived;
it('dispatches payment intent succeeded event', function () {
Event::fake([PaymentIntentSucceeded::class, WebhookReceived::class]);
$payload = json_encode([
'type' => 'payment_intent.succeeded',
'data' => ['id' => 'pi_test', 'resource' => 'payment_intent'],
]);
$timestamp = time();
$signature = hash_hmac('sha256', $timestamp . '.' . $payload, config('payrex.webhook.secret'));
$this->postJson(route('payrex.webhook'), json_decode($payload, true), [
'Payrex-Signature' => "t={$timestamp},te={$signature},li=",
])->assertOk();
Event::assertDispatched(WebhookReceived::class);
Event::assertDispatched(PaymentIntentSucceeded::class);
});Testing API Calls
Faking HTTP Responses
Use Laravel's Http::fake() to mock PayRex API responses:
use Illuminate\Support\Facades\Http;
use LegionHQ\LaravelPayrex\Facades\Payrex;
it('creates a payment intent', function () {
Http::fake([
'api.payrexhq.com/payment_intents' => Http::response([
'id' => 'pi_test_123',
'resource' => 'payment_intent',
'amount' => 10000,
'currency' => 'PHP',
'status' => 'awaiting_payment_method',
'payment_methods' => ['card'],
'livemode' => false,
'created_at' => now()->timestamp,
'updated_at' => now()->timestamp,
]),
]);
$paymentIntent = Payrex::paymentIntents()->create([
'amount' => 10000,
'payment_methods' => ['card'],
]);
expect($paymentIntent->id)->toBe('pi_test_123');
expect($paymentIntent->amount)->toBe(10000);
Http::assertSent(function ($request) {
return $request->url() === 'https://api.payrexhq.com/payment_intents'
&& $request['amount'] === 10000;
});
});Faking Error Responses
Test your error handling by faking error responses:
use Illuminate\Support\Facades\Http;
use LegionHQ\LaravelPayrex\Exceptions\InvalidRequestException;
use LegionHQ\LaravelPayrex\Facades\Payrex;
it('handles validation errors', function () {
Http::fake([
'api.payrexhq.com/payment_intents' => Http::response([
'errors' => [
['detail' => 'Amount must be a positive integer.', 'code' => 'parameter_below_minimum'],
],
], 400),
]);
Payrex::paymentIntents()->create(['amount' => -100, 'payment_methods' => ['card']]);
})->throws(InvalidRequestException::class, 'Amount must be a positive integer.');Faking Paginated Responses
use Illuminate\Support\Facades\Http;
use LegionHQ\LaravelPayrex\Facades\Payrex;
it('lists customers with pagination', function () {
Http::fake([
'api.payrexhq.com/customers*' => Http::response([
'resource' => 'list',
'has_more' => false,
'data' => [
[
'id' => 'cus_test_1',
'resource' => 'customer',
'name' => 'Juan Dela Cruz',
'email' => 'juan@example.com',
'livemode' => false,
'created_at' => now()->timestamp,
'updated_at' => now()->timestamp,
],
],
]),
]);
$customers = Payrex::customers()->list(['limit' => 10]);
expect($customers)->toHaveCount(1);
expect($customers->hasMore)->toBeFalse();
expect($customers->data[0]->name)->toBe('Juan Dela Cruz');
});Test Cards
For test card numbers to simulate successful payments, failures, and 3D Secure scenarios, see the Test Cards reference.
Testing with Test API Keys
For integration tests that hit the real PayRex API, use your test mode API keys. Test keys create real resources in PayRex's test environment but don't process real money.
Set test keys in your phpunit.xml or .env.testing:
<env name="PAYREX_SECRET_KEY" value="sk_test_your_test_key"/>
<env name="PAYREX_PUBLIC_KEY" value="pk_test_your_test_key"/>WARNING
Integration tests against the real API are slower and may be rate-limited. Reserve them for critical payment flows and use Http::fake() for most tests.
Best Practices
Use
Http::fake()for unit/feature tests — Mock API responses instead of hitting the real API. This makes tests fast, reliable, and free from network issues.Test error handling paths — Verify your code handles
AuthenticationException,InvalidRequestException, andResourceNotFoundExceptiongracefully.Test webhook redelivery — Ensure your listeners handle the same event being delivered twice (PayRex may retry failed deliveries).
Use the webhook test command in CI — Run
php artisan payrex:webhook-test payment_intent.succeededin your CI pipeline to verify listeners are registered.
Further Reading
- Artisan Commands — Manage and test webhook endpoints via CLI
- Error Handling — Exception types for testing error paths
- Test Cards — Card numbers for simulating payment scenarios
- Webhook Handling — Event classes and listener setup