create(['email' => 's@set.test', 'is_admin' => false]); $customer = Customer::factory()->create(['email' => 's@set.test', 'user_id' => $user->id, 'name' => 'Acme', 'status' => 'active']); if ($withInstance) { $order = Order::factory()->create(['customer_id' => $customer->id, 'plan' => 'team']); Instance::factory()->create(['customer_id' => $customer->id, 'order_id' => $order->id, 'plan' => 'team', 'status' => 'active', 'subdomain' => 'acme']); } return compact('user', 'customer'); } it('gates settings to authenticated users', function () { $this->get(route('settings'))->assertRedirect('/login'); }); it('blocks a suspended customer from the portal', function () { $user = User::factory()->create(['email' => 'sus@set.test', 'is_admin' => false]); Customer::factory()->create(['email' => 'sus@set.test', 'user_id' => $user->id, 'status' => 'suspended']); $this->actingAs($user)->get(route('dashboard'))->assertRedirect('/login'); expect(auth()->check())->toBeFalse(); }); it('blocks a closed customer from the portal', function () { $user = User::factory()->create(['email' => 'cl@set.test', 'is_admin' => false]); Customer::factory()->create(['email' => 'cl@set.test', 'user_id' => $user->id, 'status' => 'closed', 'closed_at' => now()]); $this->actingAs($user)->get(route('dashboard'))->assertRedirect('/login'); }); it('rejects cancelling a package that is not active', function () { ['user' => $user, 'customer' => $customer] = settingsSetup(); $instance = $customer->instances()->first(); $instance->update(['status' => 'cancellation_scheduled']); Livewire::actingAs($user)->test(ConfirmCancelPackage::class) ->set('confirmName', 'acme') ->call('cancelPackage'); // Still scheduled — not re-transitioned or resurrected. expect($instance->fresh()->status)->toBe('cancellation_scheduled'); }); it('saves the company profile', function () { ['user' => $user, 'customer' => $customer] = settingsSetup(); Livewire::actingAs($user)->test(Settings::class) ->set('companyName', 'Acme GmbH') ->set('vatId', 'ATU12345678') ->set('billingAddress', "Hauptstraße 1\n1010 Wien") ->call('saveProfile') ->assertHasNoErrors(); $customer->refresh(); expect($customer->name)->toBe('Acme GmbH') ->and($customer->vat_id)->toBe('ATU12345678') ->and($customer->billing_address)->toContain('Wien'); }); it('saves branding and resolves defaults when unset', function () { ['user' => $user, 'customer' => $customer] = settingsSetup(); // Unset → resolver reports defaults. expect($customer->brandingResolved()['is_default'])->toBeTrue(); Livewire::actingAs($user)->test(Settings::class) ->set('brandDisplayName', 'Acme Cloud') ->set('brandPrimary', '#123456') ->call('saveBranding') ->assertHasNoErrors(); $customer->refresh(); expect($customer->brand_display_name)->toBe('Acme Cloud') ->and($customer->brandingResolved()['primary_color'])->toBe('#123456') ->and($customer->brandingResolved()['is_default'])->toBeFalse(); }); it('rejects an invalid brand colour', function () { ['user' => $user] = settingsSetup(); Livewire::actingAs($user)->test(Settings::class) ->set('brandPrimary', 'notacolor') ->call('saveBranding') ->assertHasErrors(['brandPrimary']); }); it('schedules package cancellation only with the correct typed confirmation', function () { $stripe = new FakeStripeClient; app()->instance(StripeClient::class, $stripe); ['user' => $user, 'customer' => $customer] = settingsSetup(); $instance = $customer->instances()->first(); // A YEARLY contract, because the assertion below is a date and a monthly // assumption would land eleven months early. This test used to assert only // that `service_ends_at` was not null — a column the code had just written, // which the broken monthly arithmetic satisfied exactly as well as the right // answer does. $contract = Subscription::factory()->plan('team', Subscription::TERM_YEARLY)->create([ 'customer_id' => $customer->id, 'order_id' => $instance->order_id, 'instance_id' => $instance->id, 'stripe_subscription_id' => 'sub_settings', 'current_period_start' => '2026-01-01 00:00:00', 'current_period_end' => '2027-01-01 00:00:00', ]); // Wrong confirmation → no change, and Stripe is not told anything either. Livewire::actingAs($user)->test(ConfirmCancelPackage::class) ->set('confirmName', 'wrong') ->call('cancelPackage') ->assertHasErrors(['confirmName']); expect($instance->fresh()->status)->toBe('active') ->and($stripe->cancellations)->toBeEmpty(); // Correct confirmation → scheduled. Livewire::actingAs($user)->test(ConfirmCancelPackage::class) ->set('confirmName', 'acme') ->call('cancelPackage'); $instance->refresh(); expect($instance->status)->toBe('cancellation_scheduled') // The end of the term that was PAID FOR, stated as a date somebody chose. ->and($instance->service_ends_at->toDateTimeString())->toBe('2027-01-01 00:00:00'); // The contract knows it was cancelled — and is still active, because until // the first of January this is a paying customer with a running cloud. expect($contract->fresh()->cancel_requested_at)->not->toBeNull() ->and($contract->fresh()->status)->toBe('active'); // And Stripe was told to stop, at the period end and not now. expect($stripe->cancellations)->toHaveCount(1) ->and($stripe->cancellations[0]['subscription'])->toBe('sub_settings') ->and($stripe->cancellations[0]['when'])->toBe(StripeClient::CANCEL_AT_PERIOD_END); }); it('blocks closing the account while a package is active', function () { ['user' => $user, 'customer' => $customer] = settingsSetup(); Livewire::actingAs($user)->test(ConfirmCloseAccount::class) ->set('confirmWord', __('settings.close_keyword')) ->call('closeAccount') ->assertHasErrors(['confirmWord']); expect($customer->fresh()->closed_at)->toBeNull(); }); it('closes the account when no package is active', function () { ['user' => $user, 'customer' => $customer] = settingsSetup(withInstance: false); Livewire::actingAs($user)->test(ConfirmCloseAccount::class) ->set('confirmWord', __('settings.close_keyword')) ->call('closeAccount'); expect($customer->fresh()->closed_at)->not->toBeNull(); });