api/tests/Feature/HuntProgressTest.php

137 lines
4.3 KiB
PHP

<?php
use App\Enums\ParticipateStatus;
use App\Models\Hunts;
use App\Models\HuntSteps;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('registers a participant without starting the hunt', function () {
$user = User::factory()->create();
$hunt = Hunts::withoutSyncingToSearch(fn () => Hunts::factory()->create());
$response = $this
->actingAs($user, 'sanctum')
->postJson("/api/hunts/{$hunt->id}/participate");
$response
->assertOk()
->assertJsonPath('participation_status.current_step_number', 0)
->assertJsonPath('participation_status.status', ParticipateStatus::Registered->value);
$this->assertDatabaseHas('hunt_participants', [
'user_id' => $user->id,
'hunt_id' => $hunt->id,
'current_step_number' => 0,
'status' => ParticipateStatus::Registered->value,
]);
});
it('starts a joined hunt only when the user is inside the start radius', function () {
$user = User::factory()->create();
$hunt = Hunts::withoutSyncingToSearch(fn () => Hunts::factory()->create([
'latitude' => 44.837789,
'longitude' => -0.57918,
'start_radius_m' => 40,
]));
$step = HuntSteps::factory()->create([
'hunt_id' => $hunt->id,
'step_number' => 1,
'latitude' => 44.838,
'longitude' => -0.579,
]);
$hunt->participants()->attach($user->id, [
'current_step_number' => 0,
'status' => ParticipateStatus::Registered->value,
]);
$tooFarResponse = $this
->actingAs($user, 'sanctum')
->postJson("/api/hunts/{$hunt->id}/start", [
'latitude' => 44.85,
'longitude' => -0.59,
]);
$tooFarResponse->assertBadRequest();
$response = $this
->actingAs($user, 'sanctum')
->postJson("/api/hunts/{$hunt->id}/start", [
'latitude' => 44.837789,
'longitude' => -0.57918,
]);
$response
->assertOk()
->assertJsonPath('participation_status.current_step_number', 1)
->assertJsonPath('participation_status.status', ParticipateStatus::InProgress->value)
->assertJsonPath('current_step.id', $step->id)
->assertJsonPath('current_step.step_number', 1);
});
it('does not expose a current step before the hunt is started', function () {
$user = User::factory()->create();
$hunt = Hunts::withoutSyncingToSearch(fn () => Hunts::factory()->create());
$hunt->participants()->attach($user->id, [
'current_step_number' => 0,
'status' => ParticipateStatus::Registered->value,
]);
$response = $this
->actingAs($user, 'sanctum')
->getJson("/api/hunts/{$hunt->id}/current-step");
$response
->assertStatus(409)
->assertJsonPath('participation_status.status', ParticipateStatus::Registered->value);
});
it('validates the current step and returns the next step target', function () {
$user = User::factory()->create();
$hunt = Hunts::withoutSyncingToSearch(fn () => Hunts::factory()->create());
$firstStep = HuntSteps::factory()->create([
'hunt_id' => $hunt->id,
'step_number' => 1,
'title' => 'First clue',
'hint_text' => 'Go to the next chest',
'latitude' => 44.837789,
'longitude' => -0.57918,
'radius_m' => 30,
]);
$nextStep = HuntSteps::factory()->create([
'hunt_id' => $hunt->id,
'step_number' => 2,
'latitude' => 44.838,
'longitude' => -0.579,
]);
$hunt->participants()->attach($user->id, [
'current_step_number' => 1,
'status' => ParticipateStatus::InProgress->value,
]);
$response = $this
->actingAs($user, 'sanctum')
->postJson("/api/hunts/{$hunt->id}/steps/{$firstStep->id}/validate", [
'latitude' => 44.837789,
'longitude' => -0.57918,
]);
$response
->assertOk()
->assertJsonPath('revealed_hint.hint_text', 'Go to the next chest')
->assertJsonPath('next_step.id', $nextStep->id)
->assertJsonPath('next_step.step_number', 2);
$this->assertDatabaseHas('hunt_participants', [
'user_id' => $user->id,
'hunt_id' => $hunt->id,
'current_step_number' => 2,
'status' => ParticipateStatus::InProgress->value,
]);
});