133 lines
4.3 KiB
PHP
133 lines
4.3 KiB
PHP
<?php
|
|
|
|
use App\Enums\PacePreference;
|
|
use App\Enums\WeeklyReviewStatus;
|
|
use App\Enums\WeightGoal;
|
|
use App\Models\MealPosts;
|
|
use App\Models\NutritionPlan;
|
|
use App\Models\User;
|
|
use Carbon\CarbonImmutable;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Laravel\Sanctum\Sanctum;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
CarbonImmutable::setTestNow('2026-08-17 10:00:00');
|
|
});
|
|
|
|
afterEach(function () {
|
|
CarbonImmutable::setTestNow();
|
|
});
|
|
|
|
it('returns an insufficient data review without changing the plan', function () {
|
|
$user = User::factory()->create();
|
|
Sanctum::actingAs($user);
|
|
|
|
$this->getJson('/api/weekly-reviews/current')
|
|
->assertOk()
|
|
->assertJsonPath('data.periodStart', '2026-08-10')
|
|
->assertJsonPath('data.periodEnd', '2026-08-16')
|
|
->assertJsonPath('data.status', WeeklyReviewStatus::INSUFFICIENT_DATA->value)
|
|
->assertJsonPath('data.recommendedCalorieAdjustment', 0);
|
|
|
|
$this->assertDatabaseCount('nutrition_plans', 1);
|
|
});
|
|
|
|
it('proposes and applies a small confirmed adjustment', function () {
|
|
$user = User::factory()->create([
|
|
'weight_goal' => WeightGoal::LOSE_WEIGHT,
|
|
'pace_preference' => PacePreference::NORMAL,
|
|
]);
|
|
$user->weightEntries()->delete();
|
|
|
|
foreach ([
|
|
['2026-08-03 07:00:00', 70.0],
|
|
['2026-08-07 07:00:00', 69.98],
|
|
['2026-08-12 07:00:00', 69.95],
|
|
['2026-08-16 07:00:00', 69.90],
|
|
] as [$measuredAt, $weightKg]) {
|
|
$user->weightEntries()->create([
|
|
'weight_kg' => $weightKg,
|
|
'measured_at' => $measuredAt,
|
|
]);
|
|
}
|
|
|
|
foreach (range(10, 14) as $day) {
|
|
MealPosts::factory()->for($user, 'user')->create([
|
|
'calories' => 2200,
|
|
'proteins' => 112,
|
|
'carbs' => 286,
|
|
'fats' => 61,
|
|
'eaten_at' => "2026-08-{$day} 12:00:00",
|
|
]);
|
|
}
|
|
|
|
Sanctum::actingAs($user);
|
|
|
|
$reviewResponse = $this->getJson('/api/weekly-reviews/current')
|
|
->assertOk()
|
|
->assertJsonPath('data.status', WeeklyReviewStatus::ADJUSTMENT_RECOMMENDED->value)
|
|
->assertJsonPath('data.recommendedCalorieAdjustment', -100);
|
|
|
|
$reviewId = $reviewResponse->json('data.id');
|
|
|
|
$this->postJson("/api/weekly-reviews/{$reviewId}/accept")
|
|
->assertCreated()
|
|
->assertJsonPath('data.source', 'weekly_adjustment');
|
|
|
|
$this->assertDatabaseCount('nutrition_plans', 2);
|
|
$this->assertDatabaseHas('weekly_reviews', [
|
|
'id' => $reviewId,
|
|
'recommended_calorie_adjustment' => -100,
|
|
]);
|
|
|
|
expect($user->weeklyReviews()->findOrFail($reviewId)->accepted_at)->not->toBeNull();
|
|
});
|
|
|
|
it('does not allow accepting another users review', function () {
|
|
$user = User::factory()->create();
|
|
$otherUser = User::factory()->create();
|
|
$review = $otherUser->weeklyReviews()->create([
|
|
'period_start' => '2026-08-10',
|
|
'period_end' => '2026-08-16',
|
|
'status' => WeeklyReviewStatus::ADJUSTMENT_RECOMMENDED,
|
|
'recommended_calorie_adjustment' => -100,
|
|
'message_code' => 'WEEKLY_REVIEW_ADJUSTMENT',
|
|
'metrics' => [],
|
|
'generated_at' => now(),
|
|
]);
|
|
Sanctum::actingAs($user);
|
|
|
|
$this->postJson("/api/weekly-reviews/{$review->id}/accept")->assertNotFound();
|
|
});
|
|
|
|
it('rejects an adjustment generated for a plan that is no longer active', function () {
|
|
$user = User::factory()->create();
|
|
$previousPlan = $user->nutritionPlans()->where('is_active', true)->firstOrFail();
|
|
$review = $user->weeklyReviews()->create([
|
|
'nutrition_plan_id' => $previousPlan->getKey(),
|
|
'period_start' => '2026-08-10',
|
|
'period_end' => '2026-08-16',
|
|
'status' => WeeklyReviewStatus::ADJUSTMENT_RECOMMENDED,
|
|
'recommended_calorie_adjustment' => -100,
|
|
'message_code' => 'WEEKLY_REVIEW_ADJUSTMENT',
|
|
'metrics' => [],
|
|
'generated_at' => now(),
|
|
]);
|
|
$previousPlan->update([
|
|
'is_active' => false,
|
|
'effective_until' => now(),
|
|
]);
|
|
NutritionPlan::factory()->for($user)->create([
|
|
'is_active' => true,
|
|
'effective_from' => now()->addMinute(),
|
|
]);
|
|
Sanctum::actingAs($user);
|
|
|
|
$this->postJson("/api/weekly-reviews/{$review->id}/accept")
|
|
->assertStatus(409);
|
|
|
|
expect($review->fresh()->accepted_at)->toBeNull();
|
|
});
|