presseportale/tests/Feature/Billing/AdminPlansPageTest.php
2026-06-12 13:54:53 +00:00

159 lines
4.8 KiB
PHP

<?php
use App\Models\Plan;
use App\Models\User;
use App\Services\Billing\StripePlanSyncService;
use Database\Seeders\RolesAndPermissionsSeeder;
use Livewire\Volt\Volt as LivewireVolt;
use Tests\TestCase;
beforeEach(function (): void {
/** @var TestCase $this */
$this->seed(RolesAndPermissionsSeeder::class);
});
function plansPageAdmin(): User
{
$admin = User::factory()->create(['is_active' => true]);
$admin->assignRole('admin');
return $admin;
}
test('the plans page lists active and inactive plans with prices', function () {
/** @var TestCase $this */
Plan::factory()->create([
'name' => 'Business',
'monthly_price_cents' => 4900,
'yearly_price_cents' => 49000,
'press_release_quota' => 10,
'daily_limit' => 2,
'stripe_product_id' => 'prod_test',
'stripe_price_id_monthly' => 'price_test_m',
'stripe_price_id_yearly' => 'price_test_y',
]);
Plan::factory()->inactive()->create(['name' => 'Altpaket']);
$this->actingAs(plansPageAdmin());
LivewireVolt::test('admin.payments.plans')
->assertSee('Tarife & Pakete')
->assertSee('Business')
->assertSee('49,00 €')
->assertSee('490,00 €')
->assertSee('10 PM / Monat')
->assertSee('max. 2 / Tag')
->assertSee('verknüpft')
->assertSee('Altpaket')
->assertSee('Inaktiv');
});
test('a plan without stripe ids is marked as unsynced', function () {
/** @var TestCase $this */
Plan::factory()->create(['name' => 'Neu', 'stripe_product_id' => null]);
$this->actingAs(plansPageAdmin());
LivewireVolt::test('admin.payments.plans')
->assertSee('nicht synchronisiert');
});
test('saving a plan updates the local record and triggers the stripe sync', function () {
/** @var TestCase $this */
$plan = Plan::factory()->create([
'name' => 'Business',
'monthly_price_cents' => 4900,
'yearly_price_cents' => 49000,
'press_release_quota' => 10,
'daily_limit' => null,
]);
$this->mock(StripePlanSyncService::class, function ($mock) use ($plan) {
$mock->shouldReceive('syncAfterUpdate')
->once()
->withArgs(function (Plan $synced, array $changes) use ($plan): bool {
return $synced->is($plan)
&& array_key_exists('monthly_price_cents', $changes)
&& array_key_exists('name', $changes);
});
});
$this->actingAs(plansPageAdmin());
LivewireVolt::test('admin.payments.plans')
->call('edit', $plan->id)
->set('name', 'Business Plus')
->set('monthlyPrice', '59,00')
->set('yearlyPrice', '590')
->set('quota', '15')
->set('dailyLimit', '3')
->call('save')
->assertHasNoErrors()
->assertSee('Bestandsabos behalten ihren bisherigen Preis');
$plan->refresh();
expect($plan->name)->toBe('Business Plus')
->and($plan->monthly_price_cents)->toBe(5900)
->and($plan->yearly_price_cents)->toBe(59000)
->and($plan->press_release_quota)->toBe(15)
->and($plan->daily_limit)->toBe(3);
});
test('saving without a price change shows the plain success message', function () {
/** @var TestCase $this */
$plan = Plan::factory()->create([
'name' => 'Starter',
'monthly_price_cents' => 2900,
'yearly_price_cents' => 29000,
'daily_limit' => 1,
]);
$this->mock(StripePlanSyncService::class, function ($mock) {
$mock->shouldReceive('syncAfterUpdate')->once();
});
$this->actingAs(plansPageAdmin());
LivewireVolt::test('admin.payments.plans')
->call('edit', $plan->id)
->set('quota', '5')
->set('dailyLimit', '')
->call('save')
->assertHasNoErrors()
->assertSee('Tarif „Starter" gespeichert.')
->assertDontSee('Bestandsabos behalten');
$plan->refresh();
expect($plan->press_release_quota)->toBe(5)
->and($plan->daily_limit)->toBeNull();
});
test('invalid prices are rejected with validation errors', function () {
/** @var TestCase $this */
$plan = Plan::factory()->create();
$this->mock(StripePlanSyncService::class, function ($mock) {
$mock->shouldNotReceive('syncAfterUpdate');
});
$this->actingAs(plansPageAdmin());
LivewireVolt::test('admin.payments.plans')
->call('edit', $plan->id)
->set('monthlyPrice', '-5')
->set('quota', 'abc')
->call('save')
->assertHasErrors(['monthlyPrice', 'quota']);
});
test('the plans page is not accessible for customers', function () {
/** @var TestCase $this */
$customer = User::factory()->create(['is_active' => true]);
$customer->assignRole('customer');
$this->actingAs($customer)
->get(route('admin.payments.plans'))
->assertForbidden();
});