trypost/tests/Feature/Billing/WorkspaceQuantitySyncTest.php

76 lines
2.6 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
fix: merge-readiness — close two billing/network bugs, harden tests Bugs (both with regression tests): - OnboardingController::store now guards already-subscribed accounts (mirrors index), preventing a second Stripe Checkout / double subscription if a subscribed user re-POSTs /onboarding. - SocialAccountObserver: drop the `platform_user_id != …` clause from the creating-time one-per-network check. On create there is no "self" to exclude, so it only weakened the rule — the same account connected via two network variants (e.g. Instagram standalone + via Facebook, same id) could slip a second account into the network. Now any account in the network blocks. Robustness: - CreateWorkspace wraps create + member attach + switchWorkspace in a transaction (cache-forget / quantity-sync run after), so a partial failure can't leave an orphan workspace that inflates the Stripe seat count — covers both the signup and the add-workspace paths. Test honesty & coverage: - Scope the ten "connect multiple <platform> accounts" tests to self-hosted mode (config + name); they only passed because the test env defaults SELF_HOSTED=true, and in cloud the one-per-network rule blocks them. - network_taken popup now has controller-level tests on all six OAuth controllers (added Threads, YouTube, LinkedInPage, and a new InstagramFacebook test file; LinkedInPage/InstagramFacebook also exercise variant collapse). - Wiring tests that creating/deleting a workspace actually calls syncWorkspaceQuantity (guards per-seat billing against silent breakage). - Strengthen TrialLengthTest to assert the configured length reaches trial_ends_at; add a same-id network-variant block test.
2026-06-22 12:26:31 +00:00
use App\Actions\Workspace\CreateWorkspace;
use App\Actions\Workspace\DeleteWorkspace;
use App\Models\Account;
fix: merge-readiness — close two billing/network bugs, harden tests Bugs (both with regression tests): - OnboardingController::store now guards already-subscribed accounts (mirrors index), preventing a second Stripe Checkout / double subscription if a subscribed user re-POSTs /onboarding. - SocialAccountObserver: drop the `platform_user_id != …` clause from the creating-time one-per-network check. On create there is no "self" to exclude, so it only weakened the rule — the same account connected via two network variants (e.g. Instagram standalone + via Facebook, same id) could slip a second account into the network. Now any account in the network blocks. Robustness: - CreateWorkspace wraps create + member attach + switchWorkspace in a transaction (cache-forget / quantity-sync run after), so a partial failure can't leave an orphan workspace that inflates the Stripe seat count — covers both the signup and the add-workspace paths. Test honesty & coverage: - Scope the ten "connect multiple <platform> accounts" tests to self-hosted mode (config + name); they only passed because the test env defaults SELF_HOSTED=true, and in cloud the one-per-network rule blocks them. - network_taken popup now has controller-level tests on all six OAuth controllers (added Threads, YouTube, LinkedInPage, and a new InstagramFacebook test file; LinkedInPage/InstagramFacebook also exercise variant collapse). - Wiring tests that creating/deleting a workspace actually calls syncWorkspaceQuantity (guards per-seat billing against silent breakage). - Strengthen TrialLengthTest to assert the configured length reaches trial_ends_at; add a same-id network-variant block test.
2026-06-22 12:26:31 +00:00
use App\Models\User;
use App\Models\Workspace;
use Laravel\Cashier\Subscription;
test('syncWorkspaceQuantity does not touch Stripe in self-hosted mode', function () {
config()->set('trypost.self_hosted', true);
$subscription = mock(Subscription::class);
$subscription->shouldReceive('active')->andReturnTrue();
$subscription->shouldReceive('updateQuantity')->never();
$account = mock(Account::class)->makePartial();
$account->shouldReceive('subscription')->with(Account::SUBSCRIPTION_NAME)->andReturn($subscription);
$account->shouldReceive('workspaces->count')->andReturn(3);
$account->syncWorkspaceQuantity();
});
test('syncWorkspaceQuantity does not touch Stripe without an active subscription', function () {
config()->set('trypost.self_hosted', false);
$subscription = mock(Subscription::class);
$subscription->shouldReceive('active')->andReturnFalse();
$subscription->shouldReceive('updateQuantity')->never();
$account = mock(Account::class)->makePartial();
$account->shouldReceive('subscription')->with(Account::SUBSCRIPTION_NAME)->andReturn($subscription);
$account->syncWorkspaceQuantity();
});
test('syncWorkspaceQuantity updates the subscription quantity to the workspace count', function () {
config()->set('trypost.self_hosted', false);
$subscription = mock(Subscription::class);
$subscription->shouldReceive('active')->andReturnTrue();
$subscription->shouldReceive('updateQuantity')->once()->with(3);
$account = mock(Account::class)->makePartial();
$account->shouldReceive('subscription')->with(Account::SUBSCRIPTION_NAME)->andReturn($subscription);
$account->shouldReceive('workspaces->count')->andReturn(3);
$account->syncWorkspaceQuantity();
});
fix: merge-readiness — close two billing/network bugs, harden tests Bugs (both with regression tests): - OnboardingController::store now guards already-subscribed accounts (mirrors index), preventing a second Stripe Checkout / double subscription if a subscribed user re-POSTs /onboarding. - SocialAccountObserver: drop the `platform_user_id != …` clause from the creating-time one-per-network check. On create there is no "self" to exclude, so it only weakened the rule — the same account connected via two network variants (e.g. Instagram standalone + via Facebook, same id) could slip a second account into the network. Now any account in the network blocks. Robustness: - CreateWorkspace wraps create + member attach + switchWorkspace in a transaction (cache-forget / quantity-sync run after), so a partial failure can't leave an orphan workspace that inflates the Stripe seat count — covers both the signup and the add-workspace paths. Test honesty & coverage: - Scope the ten "connect multiple <platform> accounts" tests to self-hosted mode (config + name); they only passed because the test env defaults SELF_HOSTED=true, and in cloud the one-per-network rule blocks them. - network_taken popup now has controller-level tests on all six OAuth controllers (added Threads, YouTube, LinkedInPage, and a new InstagramFacebook test file; LinkedInPage/InstagramFacebook also exercise variant collapse). - Wiring tests that creating/deleting a workspace actually calls syncWorkspaceQuantity (guards per-seat billing against silent breakage). - Strengthen TrialLengthTest to assert the configured length reaches trial_ends_at; add a same-id network-variant block test.
2026-06-22 12:26:31 +00:00
test('creating a workspace syncs the stripe quantity', function () {
$user = User::factory()->create();
$account = mock(Account::class)->makePartial();
$account->shouldReceive('syncWorkspaceQuantity')->once();
$user->setRelation('account', $account);
CreateWorkspace::execute($user, ['name' => 'Wiring']);
});
test('deleting a workspace syncs the stripe quantity', function () {
$user = User::factory()->create();
$workspace = Workspace::factory()->create([
'account_id' => $user->account_id,
'user_id' => $user->id,
]);
$account = mock(Account::class)->makePartial();
$account->shouldReceive('syncWorkspaceQuantity')->once();
$workspace->setRelation('account', $account);
DeleteWorkspace::execute($user, $workspace);
});