create()); MealImageAnalyzer::fake([ [ 'title' => ' Bowl saumon avocat ', 'caption' => 'Un bowl avec du saumon, du riz et de l’avocat.', 'type' => MealPostType::LUNCH->value, 'calories' => 612, 'proteins' => 39.4, 'carbs' => 58.2, 'fats' => 25.1, 'ingredients' => [ [ 'position' => 12, 'ingredient' => ' Riz ', 'quantity' => 150, 'unit' => IngredientUnit::GRAM->value, ], [ 'position' => 13, 'ingredient' => 'Saumon', 'quantity' => 120, 'unit' => IngredientUnit::GRAM->value, ], ], ], ]); $response = $this ->withHeader('Accept', 'application/json') ->post('/api/meal-posts/analyze-image', [ 'image' => fakeMealAnalysisImage(), ]); $response ->assertOk() ->assertJsonPath('data.title', 'Bowl saumon avocat') ->assertJsonPath('data.type', MealPostType::LUNCH->value) ->assertJsonPath('data.calories', 612) ->assertJsonPath('data.proteins', 39.4) ->assertJsonPath('data.ingredients.0.position', 1) ->assertJsonPath('data.ingredients.0.ingredient', 'Riz') ->assertJsonPath('data.ingredients.1.ingredient', 'Saumon'); MealImageAnalyzer::assertPrompted( fn ($prompt): bool => str_contains($prompt->prompt, "Analyse l'image") && $prompt->attachments->count() === 1 ); }); it('requires authentication to analyze a meal image', function () { $this ->withHeader('Accept', 'application/json') ->post('/api/meal-posts/analyze-image', [ 'image' => fakeMealAnalysisImage(), ]) ->assertUnauthorized(); }); it('validates the analyzed image', function () { Sanctum::actingAs(User::factory()->create()); $this ->postJson('/api/meal-posts/analyze-image') ->assertUnprocessable() ->assertJsonValidationErrors(['image']); });