role('Owner')->create(); Livewire::actingAs($owner, 'operator') ->test(ConfirmRescueTunnel::class) ->assertSee(__('admin_settings.rescue_title')); }); it('refuses to even mount the confirmation for an operator without site.manage', function () { // Eine Livewire-Komponente ist ein oeffentlicher Endpunkt — auch das // Modal selbst, nicht nur die Aktion, die es am Ende auslöst. $staff = Operator::factory()->create(); Livewire::actingAs($staff, 'operator') ->test(ConfirmRescueTunnel::class) ->assertForbidden(); }); it('leaves the deed to the page component, and only dispatches', function () { // R23: das Modal mutiert nichts. Die Berechtigungsprüfung UND das // eigentliche Anfordern bleiben an der einen Stelle, an der sie schon // stehen (App\Livewire\Admin\Settings::rescueTunnel()). $owner = Operator::factory()->role('Owner')->create(); Livewire::actingAs($owner, 'operator') ->test(ConfirmRescueTunnel::class) ->call('confirm') ->assertDispatched('rescue-tunnel-confirmed'); expect(File::exists(storage_path('app/deploy/update-request.json')))->toBeFalse(); }); it('leaves a rescue request for the agent once the confirmation comes back', function () { // Die Ereignis-Verdrahtung Modal → Seite: Settings faengt // 'rescue-tunnel-confirmed' per #[On(...)] auf, genau wie beim Sperre- // Loesen daneben. $owner = Operator::factory()->role('Owner')->create(); Livewire::actingAs($owner, 'operator') ->test(AdminSettings::class) ->dispatch('rescue-tunnel-confirmed'); $request = json_decode(File::get(storage_path('app/deploy/update-request.json')), true); expect($request['kind'])->toBe('rescue-tunnel') ->and($request['requested_by'])->toBe($owner->email); }); it('refuses to rescue the tunnel for an operator without the capability, even via the event', function () { $staff = Operator::factory()->create(); Livewire::actingAs($staff, 'operator') ->test(AdminSettings::class) ->dispatch('rescue-tunnel-confirmed') ->assertForbidden(); expect(File::exists(storage_path('app/deploy/update-request.json')))->toBeFalse(); });