build the backend structure and the fe for the Game

This commit is contained in:
2026-08-15 22:37:53 +02:00
parent c5fd3f9d79
commit 4340ca9e12
37 changed files with 1611 additions and 56 deletions
+1 -1
View File
@@ -74,4 +74,4 @@ test('users are rate limited', function () {
]);
$response->assertTooManyRequests();
});
});
+1 -1
View File
@@ -98,4 +98,4 @@ test('already verified user visiting verification link is redirected without fir
Event::assertNotDispatched(Verified::class);
expect($user->fresh()->hasVerifiedEmail())->toBeTrue();
});
});
@@ -19,4 +19,4 @@ test('password confirmation requires authentication', function () {
$response = $this->get(route('password.confirm'));
$response->assertRedirect(route('login'));
});
});
+1 -1
View File
@@ -75,4 +75,4 @@ test('password cannot be reset with invalid token', function () {
]);
$response->assertSessionHasErrors('email');
});
});
+1 -1
View File
@@ -22,4 +22,4 @@ test('new users can register', function () {
$this->assertAuthenticated();
$response->assertRedirect(route('dashboard', absolute: false));
});
});
@@ -32,4 +32,4 @@ test('two factor challenge can be rendered', function () {
->assertInertia(fn (Assert $page) => $page
->component('auth/TwoFactorChallenge'),
);
});
});
@@ -31,4 +31,4 @@ test('does not send verification notification if email is verified', function ()
->assertRedirect(route('dashboard', absolute: false));
Notification::assertNothingSent();
});
});
+1 -1
View File
@@ -13,4 +13,4 @@ test('authenticated users can visit the dashboard', function () {
$response = $this->get(route('dashboard'));
$response->assertOk();
});
});
+1 -1
View File
@@ -4,4 +4,4 @@ test('returns a successful response', function () {
$response = $this->get(route('home'));
$response->assertOk();
});
});
+160
View File
@@ -0,0 +1,160 @@
<?php
use App\Models\Room;
use App\Models\Vote;
use Inertia\Testing\AssertableInertia as Assert;
function createVotingRoom(): array
{
$room = Room::create([
'title' => 'Sprint Planning',
'deck_config' => [
'name' => 'Fibonacci',
'cards' => [
['key' => '3', 'label' => '3'],
['key' => '5', 'label' => '5'],
['key' => '8', 'label' => '8'],
],
],
]);
$moderator = $room->players()->create([
'name' => 'Eric',
'is_moderator' => true,
]);
$player = $room->players()->create([
'name' => 'Anna',
'is_moderator' => false,
]);
return [$room, $moderator, $player];
}
test('a participant can vote and change their vote in the current round', function () {
[$room, $moderator] = createVotingRoom();
$session = ["room_players.{$room->id}" => $moderator->id];
$this->withSession($session)
->post(route('room.vote.store', $room), ['value' => '5'])
->assertRedirect();
$this->assertDatabaseHas('votes', [
'room_id' => $room->id,
'player_id' => $moderator->id,
'round' => 1,
'value' => '5',
]);
$this->withSession($session)
->post(route('room.vote.store', $room), ['value' => '8'])
->assertRedirect();
expect(Vote::query()->count())->toBe(1);
expect(Vote::query()->value('value'))->toBe('8');
});
test('a participant cannot vote with a card outside the room deck', function () {
[$room, $moderator] = createVotingRoom();
$this->withSession(["room_players.{$room->id}" => $moderator->id])
->post(route('room.vote.store', $room), ['value' => '100'])
->assertSessionHasErrors('value');
$this->assertDatabaseCount('votes', 0);
});
test('other votes stay hidden until the moderator reveals the round', function () {
[$room, $moderator, $player] = createVotingRoom();
$player->votes()->create([
'room_id' => $room->id,
'round' => 1,
'value' => '8',
]);
$session = ["room_players.{$room->id}" => $moderator->id];
$this->withSession($session)
->get(route('room.show', $room))
->assertInertia(fn (Assert $page) => $page
->component('rooms/Show')
->where('room.revealed', false)
->where('room.players.1.has_voted', true)
->where('room.players.1.vote', null));
$this->withSession($session)
->post(route('room.reveal', $room))
->assertRedirect();
$this->withSession($session)
->get(route('room.show', $room))
->assertInertia(fn (Assert $page) => $page
->where('room.revealed', true)
->where('room.players.1.vote', '8'));
});
test('only the moderator may reveal cards', function () {
[$room, , $player] = createVotingRoom();
$this->withSession(["room_players.{$room->id}" => $player->id])
->post(route('room.reveal', $room))
->assertForbidden();
expect($room->fresh()->revealed_at)->toBeNull();
});
test('starting the next round clears the revealed state', function () {
[$room, $moderator] = createVotingRoom();
$room->update(['revealed_at' => now()]);
$this->withSession(["room_players.{$room->id}" => $moderator->id])
->post(route('room.next-round', $room))
->assertRedirect();
$room->refresh();
expect($room->current_round)->toBe(2)
->and($room->revealed_at)->toBeNull();
});
test('the moderator can reset only the votes from the current round', function () {
[$room, $moderator, $player] = createVotingRoom();
$room->update([
'current_round' => 2,
'revealed_at' => now(),
]);
$player->votes()->create([
'room_id' => $room->id,
'round' => 1,
'value' => '3',
]);
$player->votes()->create([
'room_id' => $room->id,
'round' => 2,
'value' => '8',
]);
$this->withSession(["room_players.{$room->id}" => $moderator->id])
->post(route('room.reset', $room))
->assertRedirect();
$this->assertDatabaseHas('votes', [
'room_id' => $room->id,
'player_id' => $player->id,
'round' => 1,
'value' => '3',
]);
$this->assertDatabaseMissing('votes', [
'room_id' => $room->id,
'round' => 2,
]);
expect($room->fresh()->revealed_at)->toBeNull();
});
+1 -1
View File
@@ -82,4 +82,4 @@ test('correct password must be provided to delete account', function () {
->assertRedirect(route('profile.edit'));
expect($user->fresh())->not->toBeNull();
});
});
+1 -1
View File
@@ -101,4 +101,4 @@ test('correct password must be provided to update password', function () {
$response
->assertSessionHasErrors('current_password')
->assertRedirect(route('security.edit'));
});
});
+1 -1
View File
@@ -2,4 +2,4 @@
test('that true is true', function () {
expect(true)->toBeTrue();
});
});