mirror of
https://github.com/ericasch6/scrum-poker-internal.git
synced 2026-10-13 19:32:09 +00:00
156 lines
5.3 KiB
PHP
156 lines
5.3 KiB
PHP
<?php
|
|
|
|
use App\Enums\RoomStateChange;
|
|
use App\Events\RoomStateChanged;
|
|
use App\Models\Player;
|
|
use App\Models\Room;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Inertia\Testing\AssertableInertia as Assert;
|
|
|
|
function createRoomForPlayerKick(User $owner, array $attributes = []): Room
|
|
{
|
|
return Room::create([
|
|
'owner_id' => $owner->id,
|
|
'title' => 'Team Planning',
|
|
'current_round' => 1,
|
|
'deck_config' => [
|
|
'name' => 'Fibonacci',
|
|
'cards' => [
|
|
['key' => '3', 'label' => '3'],
|
|
['key' => '5', 'label' => '5'],
|
|
],
|
|
],
|
|
...$attributes,
|
|
]);
|
|
}
|
|
|
|
function addPlayerToKickRoom(
|
|
Room $room,
|
|
string $name,
|
|
?User $user = null,
|
|
bool $isModerator = false,
|
|
): Player {
|
|
return $room->players()->create([
|
|
'user_id' => $user?->id,
|
|
'name' => $name,
|
|
'is_moderator' => $isModerator,
|
|
'last_seen_at' => now(),
|
|
]);
|
|
}
|
|
|
|
test('the room owner sees active room players on the dashboard', function () {
|
|
$owner = User::factory()->create();
|
|
$room = createRoomForPlayerKick($owner);
|
|
$moderator = addPlayerToKickRoom($room, 'Moderator', $owner, true);
|
|
$participant = addPlayerToKickRoom($room, 'Anna');
|
|
addPlayerToKickRoom($room, 'Inactive')->update(['inactive_at' => now()]);
|
|
|
|
$this->actingAs($owner)
|
|
->get(route('dashboard'))
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->has('rooms.0.players', 2)
|
|
->where('rooms.0.players.0.id', $moderator->id)
|
|
->where('rooms.0.players.0.is_moderator', true)
|
|
->where('rooms.0.players.0.is_owner', true)
|
|
->where('rooms.0.players.1.id', $participant->id)
|
|
->where('rooms.0.players.1.is_moderator', false)
|
|
->where('rooms.0.players.1.is_owner', false));
|
|
});
|
|
|
|
test('the room owner can kick an active participant', function () {
|
|
$owner = User::factory()->create();
|
|
$room = createRoomForPlayerKick($owner);
|
|
addPlayerToKickRoom($room, 'Moderator', $owner, true);
|
|
$participant = addPlayerToKickRoom($room, 'Anna');
|
|
$remainingPlayer = addPlayerToKickRoom($room, 'Ben');
|
|
$remainingPlayer->votes()->create([
|
|
'room_id' => $room->id,
|
|
'round' => $room->current_round,
|
|
'value' => '5',
|
|
]);
|
|
$previousVersion = $room->fresh()->state_version;
|
|
|
|
Event::fake([RoomStateChanged::class]);
|
|
|
|
$this->actingAs($owner)
|
|
->delete(route('room.player.destroy', [$room, $participant]))
|
|
->assertRedirect();
|
|
|
|
expect($participant->fresh()->inactive_at)->not->toBeNull()
|
|
->and($room->fresh()->state_version)->toBe($previousVersion + 1);
|
|
|
|
Event::assertDispatched(
|
|
RoomStateChanged::class,
|
|
function (RoomStateChanged $event) use ($participant, $remainingPlayer, $room): bool {
|
|
if (
|
|
$event->roomId !== $room->id
|
|
|| $event->change !== RoomStateChange::PlayerKicked
|
|
|| $event->affectedPlayerId !== $participant->id
|
|
|| $event->state === null
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
$remainingPlayerState = collect($event->state['players'])
|
|
->firstWhere('id', $remainingPlayer->id);
|
|
|
|
return collect($event->state['players'])->doesntContain('id', $participant->id)
|
|
&& $remainingPlayerState['has_voted'] === true
|
|
&& $remainingPlayerState['vote'] === null
|
|
&& $event->broadcastWith()['affected_player_id'] === $participant->id;
|
|
},
|
|
);
|
|
Event::assertDispatchedTimes(RoomStateChanged::class, 1);
|
|
});
|
|
|
|
test('a participant cannot kick another player', function () {
|
|
$owner = User::factory()->create();
|
|
$participantUser = User::factory()->create();
|
|
$room = createRoomForPlayerKick($owner);
|
|
addPlayerToKickRoom($room, 'Moderator', $owner, true);
|
|
addPlayerToKickRoom($room, 'Anna', $participantUser);
|
|
$target = addPlayerToKickRoom($room, 'Ben');
|
|
|
|
Event::fake([RoomStateChanged::class]);
|
|
|
|
$this->actingAs($participantUser)
|
|
->delete(route('room.player.destroy', [$room, $target]))
|
|
->assertForbidden();
|
|
|
|
expect($target->fresh()->inactive_at)->toBeNull();
|
|
Event::assertNotDispatched(RoomStateChanged::class);
|
|
});
|
|
|
|
test('the room owner cannot kick their own player', function () {
|
|
$owner = User::factory()->create();
|
|
$room = createRoomForPlayerKick($owner);
|
|
$moderator = addPlayerToKickRoom($room, 'Moderator', $owner, true);
|
|
|
|
Event::fake([RoomStateChanged::class]);
|
|
|
|
$this->actingAs($owner)
|
|
->delete(route('room.player.destroy', [$room, $moderator]))
|
|
->assertForbidden();
|
|
|
|
expect($moderator->fresh()->inactive_at)->toBeNull();
|
|
Event::assertNotDispatched(RoomStateChanged::class);
|
|
});
|
|
|
|
test('the room owner cannot kick a player from another room', function () {
|
|
$owner = User::factory()->create();
|
|
$otherOwner = User::factory()->create();
|
|
$room = createRoomForPlayerKick($owner);
|
|
$otherRoom = createRoomForPlayerKick($otherOwner, ['title' => 'Other room']);
|
|
$target = addPlayerToKickRoom($otherRoom, 'Anna');
|
|
|
|
Event::fake([RoomStateChanged::class]);
|
|
|
|
$this->actingAs($owner)
|
|
->delete(route('room.player.destroy', [$room, $target]))
|
|
->assertForbidden();
|
|
|
|
expect($target->fresh()->inactive_at)->toBeNull();
|
|
Event::assertNotDispatched(RoomStateChanged::class);
|
|
});
|