create(); Sanctum::actingAs($user); $response = $this->postJson('/api/meal-posts', [ 'image_url' => 'https://example.com/meal.jpg', 'title' => 'Bowl saumon avocat', 'eaten_at' => '2026-05-16T12:00:00.000Z', 'type' => MealPostType::LUNCH->value, 'ingredients' => [ [ 'position' => 1, 'ingredient' => 'Riz', 'unit' => IngredientUnit::GRAM->value, ], [ 'position' => 2, 'ingredient' => 'Saumon', 'unit' => IngredientUnit::GRAM->value, ], ], ]); $response ->assertCreated() ->assertJsonPath('data.ingredients.0.ingredient', 'Riz') ->assertJsonPath('data.ingredients.0.unit', IngredientUnit::GRAM->value) ->assertJsonPath('data.ingredients.1.ingredient', 'Saumon'); $this->assertDatabaseHas('meal_post_ingredients', [ 'meal_posts_id' => $response->json('data.id'), 'position' => 1, 'ingredient' => 'Riz', 'unit' => IngredientUnit::GRAM->value, ]); }); it('validates meal post ingredients', function () { Sanctum::actingAs(User::factory()->create()); $response = $this->postJson('/api/meal-posts', [ 'image_url' => 'https://example.com/meal.jpg', 'title' => 'Bowl saumon avocat', 'eaten_at' => '2026-05-16T12:00:00.000Z', 'type' => MealPostType::LUNCH->value, 'ingredients' => [ [ 'position' => -1, 'ingredient' => '', 'unit' => 'cup', ], ], ]); $response ->assertUnprocessable() ->assertJsonValidationErrors([ 'ingredients.0.position', 'ingredients.0.ingredient', 'ingredients.0.unit', ]); }); it('replaces meal post ingredients when updating a meal post', function () { $user = User::factory()->create(); $mealPost = MealPosts::factory()->for($user, 'user')->create(); $mealPost->ingredients()->createMany([ [ 'position' => 1, 'ingredient' => 'Riz', 'unit' => IngredientUnit::GRAM, ], [ 'position' => 2, 'ingredient' => 'Saumon', 'unit' => IngredientUnit::GRAM, ], ]); Sanctum::actingAs($user); $response = $this->patchJson("/api/meal-posts/{$mealPost->id}", [ 'ingredients' => [ [ 'position' => 1, 'ingredient' => 'Pates', 'unit' => IngredientUnit::GRAM->value, ], [ 'position' => 2, 'ingredient' => 'Huile olive', 'unit' => IngredientUnit::TABLESPOON->value, ], ], ]); $response ->assertOk() ->assertJsonPath('data.ingredients.0.ingredient', 'Pates') ->assertJsonPath('data.ingredients.1.unit', IngredientUnit::TABLESPOON->value); $this->assertDatabaseMissing('meal_post_ingredients', [ 'meal_posts_id' => $mealPost->id, 'ingredient' => 'Riz', ]); $this->assertDatabaseHas('meal_post_ingredients', [ 'meal_posts_id' => $mealPost->id, 'position' => 1, 'ingredient' => 'Pates', 'unit' => IngredientUnit::GRAM->value, ]); }); it('keeps existing ingredients when updating a meal post without ingredients', function () { $user = User::factory()->create(); $mealPost = MealPosts::factory()->for($user, 'user')->create([ 'title' => 'Ancien titre', ]); $mealPost->ingredients()->create([ 'position' => 1, 'ingredient' => 'Riz', 'unit' => IngredientUnit::GRAM, ]); Sanctum::actingAs($user); $response = $this->patchJson("/api/meal-posts/{$mealPost->id}", [ 'title' => 'Nouveau titre', ]); $response ->assertOk() ->assertJsonPath('data.title', 'Nouveau titre') ->assertJsonPath('data.ingredients.0.ingredient', 'Riz'); $this->assertDatabaseHas('meal_post_ingredients', [ 'meal_posts_id' => $mealPost->id, 'ingredient' => 'Riz', ]); }); it('removes meal post ingredients when updating with an empty ingredients list', function () { $user = User::factory()->create(); $mealPost = MealPosts::factory()->for($user, 'user')->create(); $mealPost->ingredients()->create([ 'position' => 1, 'ingredient' => 'Riz', 'unit' => IngredientUnit::GRAM, ]); Sanctum::actingAs($user); $response = $this->patchJson("/api/meal-posts/{$mealPost->id}", [ 'ingredients' => [], ]); $response ->assertOk() ->assertJsonCount(0, 'data.ingredients'); $this->assertDatabaseMissing('meal_post_ingredients', [ 'meal_posts_id' => $mealPost->id, ]); });