toContain('') ->and($view)->toContain('') ->and($view)->toContain('') ->and(substr_count($view, 'Open Account → API Access.'))->toBe(2) ->and(substr_count($view, 'https://console.vultr.com/user/apiaccess/'))->toBe(2) ->and($view)->not->toContain('cloudProviderTokens->where(\'provider\', $provider)->isEmpty()') ->and($view)->not->toContain('') ->and($component)->toContain("'provider' => 'required|string|in:hetzner,digitalocean,vultr'"); }); it('keeps provider affiliate links on server provider views', function () { $tokenFormView = file_get_contents(__DIR__.'/../../resources/views/livewire/security/cloud-provider-token-form.blade.php'); $hetznerView = file_get_contents(__DIR__.'/../../resources/views/livewire/server/new/by-hetzner.blade.php'); $vultrView = file_get_contents(__DIR__.'/../../resources/views/livewire/server/new/by-vultr.blade.php'); $digitalOceanView = file_get_contents(__DIR__.'/../../resources/views/livewire/server/new/by-digital-ocean.blade.php'); expect($tokenFormView) ->not->toContain('https://coolify.io/hetzner') ->not->toContain('https://coolify.io/vultr') ->and($hetznerView)->toContain('https://coolify.io/hetzner') ->and($vultrView)->toContain('https://coolify.io/vultr') ->and($digitalOceanView)->toContain('https://coolify.io/digitalocean'); }); it('uses a provider dropdown and modal forms on cloud provider tokens page', function () { $view = file_get_contents(__DIR__.'/../../resources/views/livewire/security/cloud-provider-tokens.blade.php'); expect($view)->toContain('+ Add') ->and($view)->toContain('
') ->and($view)->toContain('
') ->and($view)->toContain('class="coolbox group"') ->and($view)->toContain('
') ->and($view)->toContain('
') ->and($view)->toContain('') ->and($view)->toContain('Add Hetzner Token') ->and($view)->toContain('Add DigitalOcean Token') ->and($view)->toContain('Add Vultr Token') ->and($view)->toContain('and($view)->toContain('and($view)->toContain('and($view)->not->toContain('

New Token

') ->and($view)->not->toContain(':modal_mode="false"') ->and($view)->not->toContain('wire:click="validateToken') ->and($view)->not->toContain('submitAction="deleteToken') ->and($view)->not->toContain('Created {{ $savedToken->created_at->diffForHumans() }}'); }); it('shows explicit loading spinners and disables cloud token action buttons while requests run', function () { $tokenFormView = file_get_contents(__DIR__.'/../../resources/views/livewire/security/cloud-provider-token-form.blade.php'); $tokenShowView = file_get_contents(__DIR__.'/../../resources/views/livewire/security/cloud-provider-token/show.blade.php'); $serverTokenView = file_get_contents(__DIR__.'/../../resources/views/livewire/server/cloud-provider-token/show.blade.php'); expect(substr_count($tokenFormView, 'wire:loading.attr="disabled" wire:target="addToken"'))->toBe(2) ->and(substr_count($tokenFormView, ''))->toBe(2) ->and($tokenShowView)->toContain('wire:loading.attr="disabled" wire:target="validateToken"') ->and($tokenShowView)->toContain('') ->and($serverTokenView)->toContain('wire:loading.attr="disabled"') ->and($serverTokenView)->toContain('wire:target="validateToken"') ->and($serverTokenView)->toContain(''); });