mirror of
https://github.com/ericasch6/scrum-poker-internal.git
synced 2026-10-13 14:12:08 +00:00
302 lines
9.7 KiB
PHP
302 lines
9.7 KiB
PHP
<?php
|
|
|
|
use App\Enums\RoomStateChange;
|
|
use App\Events\RoomStateChanged;
|
|
use App\Jobs\RemoveAbsentPlayers;
|
|
use App\Models\Room;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Inertia\Testing\AssertableInertia as Assert;
|
|
|
|
function createEmbeddedRoom(array $attributes = []): Room
|
|
{
|
|
return Room::create([
|
|
'title' => 'Fillibri Planning',
|
|
'deck_config' => [
|
|
'name' => 'Fibonacci',
|
|
'cards' => [
|
|
['key' => '3', 'label' => '3'],
|
|
['key' => '5', 'label' => '5'],
|
|
],
|
|
],
|
|
...$attributes,
|
|
]);
|
|
}
|
|
|
|
test('a guest automatically joins the embedded room', function () {
|
|
$room = createEmbeddedRoom();
|
|
$response = $this->get(route('embedded.room', [
|
|
'join_code' => strtolower($room->join_code),
|
|
'player_name' => ' Nico ',
|
|
]))
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('embedded/Room')
|
|
->where('room.id', $room->id)
|
|
->where('currentPlayer.name', 'Nico'));
|
|
|
|
$player = $room->players()->sole();
|
|
|
|
expect($player->user_id)->toBeNull()
|
|
->and($player->is_moderator)->toBeTrue();
|
|
|
|
$response->assertSessionHas("room_players.{$room->id}", $player->id);
|
|
});
|
|
|
|
test('embedded guest access reuses the session player and applies a changed display name', function () {
|
|
$room = createEmbeddedRoom();
|
|
$player = $room->players()->create([
|
|
'name' => 'Old name',
|
|
]);
|
|
|
|
$this->withSession(["room_players.{$room->id}" => $player->id])
|
|
->get(route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'New name',
|
|
]))
|
|
->assertOk();
|
|
|
|
expect($room->players()->count())->toBe(1)
|
|
->and($player->fresh()->name)->toBe('New name');
|
|
});
|
|
|
|
test('an authenticated user automatically joins the embedded room', function () {
|
|
$user = User::factory()->create();
|
|
$room = createEmbeddedRoom(['allow_participants_to_manage_rounds' => true]);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('embedded.room', [
|
|
'join_code' => strtolower($room->join_code),
|
|
'player_name' => ' Nico ',
|
|
]))
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('embedded/Room')
|
|
->where('room.id', $room->id)
|
|
->where('room.allow_participants_to_manage_rounds', true)
|
|
->where('currentPlayer.name', 'Nico'))
|
|
->assertSessionHas("room_players.{$room->id}");
|
|
|
|
$this->assertDatabaseHas('players', [
|
|
'room_id' => $room->id,
|
|
'user_id' => $user->id,
|
|
'name' => 'Nico',
|
|
'is_moderator' => true,
|
|
]);
|
|
});
|
|
|
|
test('a persistent room owner regains moderation through the embedded room', function () {
|
|
$owner = User::factory()->create();
|
|
$room = createEmbeddedRoom([
|
|
'owner_id' => $owner->id,
|
|
'is_persistent' => true,
|
|
]);
|
|
$oldModerator = $room->players()->create([
|
|
'user_id' => $owner->id,
|
|
'name' => 'Nico',
|
|
'is_moderator' => true,
|
|
'last_seen_at' => now()->subHour(),
|
|
]);
|
|
|
|
app()->call([new RemoveAbsentPlayers, 'handle']);
|
|
|
|
$this->actingAs($owner)
|
|
->withSession(["room_players.{$room->id}" => $oldModerator->id])
|
|
->get(route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]))
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->where('currentPlayer.is_moderator', true));
|
|
|
|
expect($room->players()->where('user_id', $owner->id)->sole()->id)->not->toBe($oldModerator->id);
|
|
});
|
|
|
|
test('a persistent room owner does not take over another account session when becoming moderator', function () {
|
|
$owner = User::factory()->create();
|
|
$otherUser = User::factory()->create();
|
|
$room = createEmbeddedRoom([
|
|
'owner_id' => $owner->id,
|
|
'is_persistent' => true,
|
|
]);
|
|
$otherPlayer = $room->players()->create([
|
|
'user_id' => $otherUser->id,
|
|
'name' => 'Anna',
|
|
]);
|
|
|
|
$this->actingAs($owner)
|
|
->withSession(["room_players.{$room->id}" => $otherPlayer->id])
|
|
->get(route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]))
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->where('currentPlayer.is_moderator', true));
|
|
|
|
expect($otherPlayer->fresh()->is_moderator)->toBeFalse()
|
|
->and($room->players()->where('user_id', $owner->id)->sole()->is_moderator)->toBeTrue();
|
|
});
|
|
|
|
test('embedded access reuses the user player and applies a changed display name', function () {
|
|
$user = User::factory()->create();
|
|
$room = createEmbeddedRoom();
|
|
$player = $room->players()->create([
|
|
'user_id' => $user->id,
|
|
'name' => 'Old name',
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'New name',
|
|
]))
|
|
->assertOk();
|
|
|
|
expect($room->players()->count())->toBe(1)
|
|
->and($player->fresh()->name)->toBe('New name');
|
|
});
|
|
|
|
test('an embedded guest keeps the same player after logging in separately', function () {
|
|
$user = User::factory()->create([
|
|
'email' => 'nico@example.com',
|
|
]);
|
|
$room = createEmbeddedRoom();
|
|
$url = route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]);
|
|
|
|
$this->get($url)->assertOk();
|
|
|
|
$player = $room->players()->sole();
|
|
|
|
$this->post(route('login.store'), [
|
|
'email' => 'nico@example.com',
|
|
'password' => 'password',
|
|
])->assertRedirect();
|
|
|
|
$this->get($url)->assertOk();
|
|
|
|
expect($room->players()->count())->toBe(1)
|
|
->and($player->fresh()->user_id)->toBe($user->id);
|
|
});
|
|
|
|
test('embedded guest access shows a dedicated error when the display name is taken', function () {
|
|
$user = User::factory()->create([
|
|
'email' => 'nico@example.com',
|
|
]);
|
|
$room = createEmbeddedRoom();
|
|
$room->players()->create([
|
|
'user_id' => $user->id,
|
|
'name' => 'Nico',
|
|
]);
|
|
$url = route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]);
|
|
|
|
$this->get($url)
|
|
->assertUnprocessable()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('embedded/Error')
|
|
->where('message', 'Dieser Anzeigename ist in dem Raum bereits vorhanden.')
|
|
->where('showLoginAction', true))
|
|
->assertSessionHas('url.intended', $url);
|
|
|
|
$this->post(route('login.store'), [
|
|
'email' => 'nico@example.com',
|
|
'password' => 'password',
|
|
])->assertRedirect($url);
|
|
|
|
$this->get($url)
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('embedded/Room')
|
|
->where('currentPlayer.name', 'Nico'));
|
|
});
|
|
|
|
test('a new account instance takes over the embedded player and kicks the previous instance', function () {
|
|
Event::fake([RoomStateChanged::class]);
|
|
$user = User::factory()->create();
|
|
$room = createEmbeddedRoom();
|
|
$player = $room->players()->create([
|
|
'user_id' => $user->id,
|
|
'name' => 'Nico',
|
|
'active_instance_id' => '019b8f80-37c4-71a3-b415-5f2697332c16',
|
|
]);
|
|
$url = route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->withSession([
|
|
'room_player_instance_id' => '019b8f80-37c4-71a3-b415-5f2697332c17',
|
|
])
|
|
->get($url)
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->where('currentPlayer.id', $player->id)
|
|
->where('currentPlayer.instance_id', '019b8f80-37c4-71a3-b415-5f2697332c17'));
|
|
|
|
expect($player->fresh()->active_instance_id)
|
|
->toBe('019b8f80-37c4-71a3-b415-5f2697332c17');
|
|
|
|
Event::assertDispatched(
|
|
RoomStateChanged::class,
|
|
fn (RoomStateChanged $event): bool => $event->change === RoomStateChange::PlayerInstanceReplaced
|
|
&& $event->affectedPlayerId === $player->id
|
|
&& $event->affectedInstanceId === '019b8f80-37c4-71a3-b415-5f2697332c16',
|
|
);
|
|
|
|
$this->withSession([
|
|
"room_players.{$room->id}" => $player->id,
|
|
'room_player_instance_id' => '019b8f80-37c4-71a3-b415-5f2697332c16',
|
|
])
|
|
->post(route('room.vote.store', $room), ['value' => '5'])
|
|
->assertRedirect(route('room.join', ['join_code' => $room->join_code]));
|
|
|
|
$this->assertDatabaseCount('votes', 0);
|
|
});
|
|
|
|
test('embedded access shows a dedicated error for an unknown room code', function () {
|
|
$this->get(route('embedded.room', [
|
|
'join_code' => 'ABC234',
|
|
'player_name' => 'Nico',
|
|
]))
|
|
->assertUnprocessable()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('embedded/Error')
|
|
->where('message', 'Dieser Raumcode existiert nicht.')
|
|
->where('showLoginAction', false));
|
|
});
|
|
|
|
test('embedded logout returns to the same room as a guest without duplicating the player', function () {
|
|
$user = User::factory()->create();
|
|
$room = createEmbeddedRoom();
|
|
$url = route('embedded.room', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]);
|
|
|
|
$this->actingAs($user)->get($url)->assertOk();
|
|
|
|
$player = $room->players()->sole();
|
|
|
|
$this
|
|
->followingRedirects()
|
|
->post(route('embedded.logout', [
|
|
'join_code' => $room->join_code,
|
|
'player_name' => 'Nico',
|
|
]))
|
|
->assertOk()
|
|
->assertInertia(fn (Assert $page) => $page
|
|
->component('embedded/Room')
|
|
->where('currentPlayer.id', $player->id));
|
|
|
|
$this->assertGuest()
|
|
->assertDatabaseCount('players', 1);
|
|
});
|