'Teamraum', 'deck_config' => [ 'name' => 'Fibonacci', 'cards' => [ ['key' => '3', 'label' => '3'], ['key' => '5', 'label' => '5'], ], ], ...$attributes, ]); } test('room settings default to moderator control and normal retention', function () { $room = createSettingsRoom(); expect($room->allow_participants_to_manage_rounds)->toBeFalse() ->and($room->is_persistent)->toBeFalse(); }); test('the owner can view and update room settings', function () { $owner = User::factory()->create(); $room = createSettingsRoom(['owner_id' => $owner->id]); $this->actingAs($owner) ->get(route('room.settings.edit', $room)) ->assertInertia(fn (Assert $page) => $page ->component('rooms/Settings') ->where('room.id', $room->id) ->where('room.allow_participants_to_manage_rounds', false) ->where('room.is_persistent', false)); Event::fake(); $this->actingAs($owner) ->patch(route('room.settings.update', $room), [ 'allow_participants_to_manage_rounds' => true, 'is_persistent' => true, ]) ->assertRedirect(); $room->refresh(); expect($room->allow_participants_to_manage_rounds)->toBeTrue() ->and($room->is_persistent)->toBeTrue() ->and($room->state_version)->toBe(2); Event::assertDispatched( RoomStateChanged::class, fn (RoomStateChanged $event): bool => $event->change === RoomStateChange::RoomSettingsUpdated && $event->state['allow_participants_to_manage_rounds'] === true, ); }); test('a user who does not own a room cannot manage its settings', function () { $owner = User::factory()->create(); $otherUser = User::factory()->create(); $room = createSettingsRoom(['owner_id' => $owner->id]); $this->actingAs($otherUser) ->get(route('room.settings.edit', $room)) ->assertForbidden(); $this->actingAs($otherUser) ->patch(route('room.settings.update', $room), [ 'allow_participants_to_manage_rounds' => true, 'is_persistent' => true, ]) ->assertForbidden(); expect($room->fresh()->allow_participants_to_manage_rounds)->toBeFalse(); }); test('all active participants can manage rounds when the room setting is enabled', function () { $room = createSettingsRoom(['allow_participants_to_manage_rounds' => true]); $player = $room->players()->create([ 'name' => 'Anna', 'is_moderator' => false, ]); $this->withSession(["room_players.{$room->id}" => $player->id]) ->post(route('room.reveal', $room)) ->assertNoContent(); expect($room->fresh()->revealed_at)->not->toBeNull(); }); test('normal participants remain unable to manage rounds when the setting is disabled', function () { $room = createSettingsRoom(); $player = $room->players()->create([ 'name' => 'Anna', 'is_moderator' => false, ]); $this->withSession(["room_players.{$room->id}" => $player->id]) ->post(route('room.reveal', $room)) ->assertForbidden(); }); test('persistent rooms are excluded from automatic closing', function () { $persistentRoom = createSettingsRoom([ 'owner_id' => User::factory()->create()->id, 'is_persistent' => true, 'last_activity_at' => now()->subDays(60), ]); $expiringRoom = createSettingsRoom([ 'owner_id' => User::factory()->create()->id, 'last_activity_at' => now()->subDays(60), ]); (new CloseInactiveRooms)->handle(); expect($persistentRoom->fresh()->closed_at)->toBeNull() ->and($expiringRoom->fresh()->closed_at)->not->toBeNull(); }); test('room settings broadcasts never expose hidden vote values', function () { $owner = User::factory()->create(); $room = createSettingsRoom(['owner_id' => $owner->id]); $player = $room->players()->create([ 'name' => 'Anna', 'is_moderator' => false, ]); $player->votes()->create([ 'room_id' => $room->id, 'round' => 1, 'value' => '5', ]); Event::fake(); $this->actingAs($owner)->patch(route('room.settings.update', $room), [ 'allow_participants_to_manage_rounds' => true, 'is_persistent' => false, ]); Event::assertDispatched( RoomStateChanged::class, function (RoomStateChanged $event) use ($player): bool { $broadcastPlayer = collect($event->state['players'])->firstWhere('id', $player->id); return $broadcastPlayer['has_voted'] === true && $broadcastPlayer['vote'] === null; }, ); });