trypost/tests/Feature/Billing/BillingCycleTest.php
Paulo Castellano 7cc88f1036 fix: address PR review findings
- LinkedInController: catch NetworkAlreadyConnectedException so a profile
  colliding with a connected Page shows the specific network_taken message
  instead of the generic error (+ test).
- Billing.vue: pass a string to transChoice replacements (vue-tsc TS2322).
- NetworkConnectGrid: drop the now-unused 'connect' emit (no listener after
  AddSocialDialog removal).
- Tests: assert the BillingCycle trial window; fix a stale section comment in
  StripeEventListenerTest.
2026-06-22 12:53:13 -03:00

123 lines
4.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Models\Account;
use App\Models\AiUsageLog;
use App\Models\Plan;
use App\Models\Workspace;
use App\Support\BillingCycle;
use Illuminate\Support\Carbon;
test('monthly allotment is credits per workspace times workspace count', function () {
$account = billingAccount('price_month', workspaces: 3);
expect(BillingCycle::for($account)->creditAllotment())->toBe(7500);
});
test('yearly allotment grants twelve months upfront per workspace', function () {
$account = billingAccount('price_year', workspaces: 2);
expect(BillingCycle::for($account)->creditAllotment())->toBe(60000);
});
test('during trial the allotment is the monthly amount even on a yearly price', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_year', [
'created_at' => Carbon::parse('2026-06-18'),
'trial_ends_at' => Carbon::parse('2026-06-25'),
], workspaces: 1);
expect(BillingCycle::for($account)->creditAllotment())->toBe(2500);
});
test('during trial the window spans the subscription creation to the trial end', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_year', [
'created_at' => Carbon::parse('2026-06-18'),
'trial_ends_at' => Carbon::parse('2026-06-25'),
], workspaces: 1);
$cycle = BillingCycle::for($account);
expect($cycle->periodStart()->toDateString())->toBe('2026-06-18')
->and($cycle->periodEnd()->toDateString())->toBe('2026-06-25');
});
test('monthly cycle window spans the anchor day to the next month', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_month', ['created_at' => Carbon::parse('2026-03-05')]);
$cycle = BillingCycle::for($account);
expect($cycle->periodStart()->toDateString())->toBe('2026-06-05')
->and($cycle->periodEnd()->toDateString())->toBe('2026-07-05');
});
test('yearly cycle window spans one year from the anchor', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_year', ['created_at' => Carbon::parse('2025-02-10')]);
$cycle = BillingCycle::for($account);
expect($cycle->periodStart()->toDateString())->toBe('2026-02-10')
->and($cycle->periodEnd()->toDateString())->toBe('2027-02-10');
});
test('used credits counts only usage within the current cycle window', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_month', ['created_at' => Carbon::parse('2026-03-05')]);
$workspace = $account->workspaces()->first();
AiUsageLog::factory()->text(credits: 10)->create([
'account_id' => $account->id,
'workspace_id' => $workspace->id,
'created_at' => Carbon::parse('2026-06-10'),
]);
AiUsageLog::factory()->text(credits: 99)->create([
'account_id' => $account->id,
'workspace_id' => $workspace->id,
'created_at' => Carbon::parse('2026-06-01'),
]);
expect(BillingCycle::for($account)->usedCredits())->toBe(10);
});
test('without a subscription the allotment falls back to a monthly amount', function () {
$plan = Plan::query()->firstOrFail();
$account = Account::factory()->create(['plan_id' => $plan->id, 'trial_ends_at' => null]);
Workspace::factory()->count(2)->create(['account_id' => $account->id]);
expect(BillingCycle::for($account)->creditAllotment())->toBe(5000);
});
test('monthly window clamps an end-of-month anchor without drift', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_month', ['created_at' => Carbon::parse('2026-01-31')]);
$cycle = BillingCycle::for($account);
expect($cycle->periodStart()->toDateString())->toBe('2026-05-31')
->and($cycle->periodEnd()->toDateString())->toBe('2026-06-30');
});
test('yearly window clamps a leap-day anchor without drift', function () {
Carbon::setTestNow('2026-06-20 12:00:00');
$account = billingAccount('price_year', ['created_at' => Carbon::parse('2024-02-29')]);
$cycle = BillingCycle::for($account);
expect($cycle->periodStart()->toDateString())->toBe('2026-02-28')
->and($cycle->periodEnd()->toDateString())->toBe('2027-02-28');
});
test('allotment is zero when the account has no plan', function () {
$account = Account::factory()->create(['plan_id' => null, 'trial_ends_at' => null]);
Workspace::factory()->count(2)->create(['account_id' => $account->id]);
expect(BillingCycle::for($account)->creditAllotment())->toBe(0);
});