Files
SkinbaseNova/tests/Feature/Academy/AcademyStripeWebhookTest.php

131 lines
4.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature\Academy;
use App\Models\AcademyBillingEvent;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Laravel\Cashier\Events\WebhookHandled;
use Laravel\Cashier\Events\WebhookReceived;
use Tests\TestCase;
final class AcademyStripeWebhookTest extends TestCase
{
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
config()->set('academy_billing.plans', [
'creator_monthly' => [
'label' => 'Creator Monthly',
'tier' => 'creator',
'interval' => 'monthly',
'stripe_price_id' => 'price_creator_month',
'featured' => false,
],
'pro_monthly' => [
'label' => 'Pro Monthly',
'tier' => 'pro',
'interval' => 'monthly',
'stripe_price_id' => 'price_pro_month',
'featured' => true,
],
]);
}
public function test_webhook_listener_stores_safe_audit_summary_and_records_handling_outcome(): void
{
$user = User::factory()->create([
'stripe_id' => 'cus_webhook_test',
'email_verified_at' => now(),
]);
Cache::put('academy.billing.account.'.$user->id, 'stale', 300);
event(new WebhookReceived([
'id' => 'evt_academy_billing_test',
'type' => 'customer.subscription.updated',
'data' => [
'object' => [
'id' => 'sub_webhook_test',
'customer' => 'cus_webhook_test',
'status' => 'active',
'items' => [
'data' => [[
'price' => [
'id' => 'price_creator_month',
],
]],
],
'metadata' => [
'academy_plan' => 'creator_monthly',
'academy_tier' => 'creator',
'user_id' => (string) $user->id,
],
],
],
]));
$subscription = $user->subscriptions()->create([
'type' => 'academy',
'stripe_id' => 'sub_webhook_test',
'stripe_status' => 'active',
'stripe_price' => 'price_creator_month',
'quantity' => 1,
]);
$subscription->items()->create([
'stripe_id' => 'si_webhook_test',
'stripe_product' => 'prod_creator_month',
'stripe_price' => 'price_creator_month',
'quantity' => 1,
]);
event(new WebhookHandled([
'id' => 'evt_academy_billing_test',
'type' => 'customer.subscription.updated',
'data' => [
'object' => [
'id' => 'sub_webhook_test',
'customer' => 'cus_webhook_test',
'status' => 'active',
'items' => [
'data' => [[
'price' => [
'id' => 'price_creator_month',
'product' => 'prod_creator_month',
],
'quantity' => 1,
'id' => 'si_webhook_test',
]],
],
'metadata' => [
'academy_plan' => 'creator_monthly',
'academy_tier' => 'creator',
'user_id' => (string) $user->id,
],
'subscription' => 'sub_webhook_test',
],
],
]));
$billingEvent = AcademyBillingEvent::query()->where('stripe_event_id', 'evt_academy_billing_test')->first();
$this->assertNotNull($billingEvent);
$this->assertSame('customer.subscription.updated', $billingEvent->event_type);
$this->assertSame('creator_monthly', $billingEvent->academy_plan);
$this->assertSame('creator', $billingEvent->academy_tier);
$this->assertSame('cus_webhook_test', $billingEvent->stripe_customer_id);
$this->assertSame(['price_creator_month'], $billingEvent->payload_summary['price_ids'] ?? []);
$this->assertTrue($billingEvent->payload_summary['received'] ?? false);
$this->assertTrue($billingEvent->payload_summary['handled'] ?? false);
$this->assertSame('local_subscription_synced', $billingEvent->payload_summary['outcome'] ?? null);
$this->assertTrue($billingEvent->payload_summary['cache_cleared'] ?? false);
$this->assertFalse(Cache::has('academy.billing.account.'.$user->id));
}
}