api/tests/Feature/WorkoutSessionsTest.php

157 lines
5.0 KiB
PHP

<?php
use App\Enums\WorkoutSource;
use App\Models\User;
use App\Models\WorkoutSessions;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
uses(RefreshDatabase::class);
it('creates a workout for the authenticated user', function () {
$user = User::factory()->create();
Sanctum::actingAs($user);
$response = $this->postJson('/api/workouts', [
'external_id' => 'apple-workout-1',
'source' => WorkoutSource::APPLE_HEALTH->value,
'type' => 'running',
'title' => 'Morning run',
'duration_seconds' => 1800,
'calories_burned' => 450,
'distance_meters' => 5200,
'started_at' => '2026-05-19T07:30:00.000Z',
]);
$response
->assertCreated()
->assertJsonPath('data.externalId', 'apple-workout-1')
->assertJsonPath('data.source', WorkoutSource::APPLE_HEALTH->value)
->assertJsonPath('data.type', 'running')
->assertJsonPath('data.title', 'Morning run')
->assertJsonPath('data.durationSeconds', 1800)
->assertJsonPath('data.caloriesBurned', 450)
->assertJsonPath('data.distanceMeters', 5200);
$this->assertDatabaseHas('workout_sessions', [
'id' => $response->json('data.id'),
'user_id' => $user->id,
'external_id' => 'apple-workout-1',
'source' => WorkoutSource::APPLE_HEALTH->value,
'type' => 'running',
'title' => 'Morning run',
'duration_seconds' => 1800,
'calories_burned' => 450,
'distance_meters' => 5200,
]);
});
it('returns workouts for the authenticated user', function () {
$user = User::factory()->create();
$otherUser = User::factory()->create();
$oldWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
'external_id' => 'manual-1',
'source' => WorkoutSource::MANUAL,
'type' => 'strength',
'title' => 'Upper body',
'duration_seconds' => 2400,
'calories_burned' => 320,
'distance_meters' => 0,
'started_at' => '2026-05-18 10:00:00',
]);
$latestWorkoutSession = WorkoutSessions::factory()->for($user, 'user')->create([
'external_id' => 'apple-1',
'source' => WorkoutSource::APPLE_HEALTH,
'type' => 'running',
'title' => 'Morning run',
'duration_seconds' => 1800,
'calories_burned' => 450,
'distance_meters' => 5200,
'started_at' => '2026-05-19 07:30:00',
]);
$otherWorkoutSession = WorkoutSessions::factory()->for($otherUser, 'user')->create([
'title' => 'Hidden workout',
'started_at' => '2026-05-20 07:30:00',
]);
Sanctum::actingAs($user);
$response = $this->getJson('/api/workouts');
$response
->assertOk()
->assertJsonCount(2, 'data')
->assertJsonPath('data.0.id', $latestWorkoutSession->id)
->assertJsonPath('data.0.externalId', 'apple-1')
->assertJsonPath('data.0.source', WorkoutSource::APPLE_HEALTH->value)
->assertJsonPath('data.0.type', 'running')
->assertJsonPath('data.0.title', 'Morning run')
->assertJsonPath('data.0.durationSeconds', 1800)
->assertJsonPath('data.0.caloriesBurned', 450)
->assertJsonPath('data.0.distanceMeters', 5200)
->assertJsonPath('data.1.id', $oldWorkoutSession->id)
->assertJsonMissing([
'id' => $otherWorkoutSession->id,
]);
});
it('validates the workouts pagination size', function () {
Sanctum::actingAs(User::factory()->create());
$this
->getJson('/api/workouts?per_page=101')
->assertUnprocessable()
->assertJsonValidationErrors(['per_page']);
});
it('validates workout creation data', function () {
Sanctum::actingAs(User::factory()->create());
$this
->postJson('/api/workouts', [
'source' => 'invalid',
'type' => '',
'title' => '',
'duration_seconds' => 0,
'calories_burned' => -1,
'distance_meters' => -1,
'started_at' => 'not-a-date',
])
->assertUnprocessable()
->assertJsonValidationErrors([
'source',
'type',
'title',
'duration_seconds',
'calories_burned',
'distance_meters',
'started_at',
]);
});
it('validates workout external ids per source', function () {
$user = User::factory()->create();
WorkoutSessions::factory()->create([
'external_id' => 'manual-1',
'source' => WorkoutSource::MANUAL,
]);
Sanctum::actingAs($user);
$this
->postJson('/api/workouts', [
'external_id' => 'manual-1',
'source' => WorkoutSource::MANUAL->value,
'type' => 'running',
'title' => 'Morning run',
'duration_seconds' => 1800,
'calories_burned' => 450,
'distance_meters' => 5200,
])
->assertUnprocessable()
->assertJsonValidationErrors(['external_id']);
});