setUpHasPlanner(); } public function test_user_can_generate_schedule(): void { $planner = $this->planner; $users = User::factory()->planner($planner)->count(2)->create(); // Create users $dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes // Attach dishes to users, ensuring `UserDish` records exist for every user $users->each(function (User $user) use ($dishes) { $dishes->random(50)->each(function (Dish $dish) use ($user) { UserDish::factory()->create([ 'user_id' => $user->id, 'dish_id' => $dish->id, ]); }); }); $this->assertDatabaseEmpty(Schedule::class); $this ->actingAs($planner) ->post(route('api.schedule.generate')) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json ->where('success', true) ->where('payload', null) ->where('errors', null) ); $this->assertDatabaseCount(Schedule::class, 14); } public function test_fresh_schedule_adheres_to_fixed_recurrences(): void { $planner = $this->planner; $targetDate = now()->addDay(); $users = User::factory()->planner($planner)->count(2)->create(); // Create users $dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes // Attach dishes to users, ensuring `UserDish` records exist for every user $users->each(function (User $user) use ($dishes) { $dishes->random(50)->each(function (Dish $dish) use ($user) { UserDish::factory()->create([ 'user_id' => $user->id, 'dish_id' => $dish->id, ]); }); }); $targetUserDish = UserDish::query() ->whereNotNull('dish_id') ->whereNotNull('user_id') ->get() ->random(); $weeklyRecurrence = WeeklyRecurrence::factory()->create([ 'weekday' => $targetDate->dayOfWeek(), ]); $fixedRecurrence = UserDishRecurrence::factory()->create([ 'user_dish_id' => $targetUserDish->id, 'recurrence_id' => $weeklyRecurrence->id, 'recurrence_type' => $weeklyRecurrence::class, ]); $this->assertDatabaseEmpty(Schedule::class); $this ->actingAs($planner) ->post(route('api.schedule.generate')) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json ->where('success', true) ->where('payload', null) ->where('errors', null) ); $this->assertDatabaseCount(Schedule::class, 14); $targetDateSchedule = Schedule::query()->where('date', $targetDate->format('Y-m-d'))->first(); $this->assertNotNull($targetDateSchedule); $targetScheduledUserDishes = $targetDateSchedule ->scheduledUserDishes ->pluck('user_dish_id') ->toArray(); $this->assertContains($targetUserDish->id, $targetScheduledUserDishes); } public function test_schedule_can_be_overwritten(): void { $planner = $this->planner; $users = User::factory()->planner($planner)->count(2)->create(); // Create users $dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes // Attach dishes to users, ensuring `UserDish` records exist for every user $users->each(function (User $user) use ($dishes) { $dishes->random(50)->each(function (Dish $dish) use ($user) { UserDish::factory()->create([ 'user_id' => $user->id, 'dish_id' => $dish->id, ]); }); }); // Assert that every user has `UserDish` records $users->each(fn (User $user) => $this->assertNotEmpty($user->refresh()->userDishes) ); $scheduleDay = Schedule::factory() ->planner($planner) ->create([ 'date' => Carbon::now()->addDay(), ]); $users->each(fn (User $user) => ScheduledUserDish::factory() ->create([ 'user_dish_id' => $user->userDishes->random()->id, 'schedule_id' => $scheduleDay->id, 'user_id' => $user->id, ]) ); $scheduleDay->refresh(); $originalUserDishes = $scheduleDay->scheduledUserDishes->map(fn (ScheduledUserDish $scheduledUserDish) => [ 'user_dish_id' => $scheduledUserDish->user_dish_id, ]); $this->assertDatabaseCount(Schedule::class, 1); $this->assertDatabaseCount(ScheduledUserDish::class, 2); $this ->actingAs($planner) ->post(route('api.schedule.generate'), [ 'overwrite' => true, ]) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json ->where('success', true) ->where('payload', null) ->where('errors', null) ); $this->assertDatabaseCount(Schedule::class, 14); $freshScheduleDay = Schedule::query()->where('date', $scheduleDay->date)->first(); $this->assertNotEquals( $originalUserDishes, $freshScheduleDay->scheduledUserDishes->map(fn (ScheduledUserDish $scheduledUserDish) => [ 'user_dish_id' => $scheduledUserDish->user_dish_id, ]) ); } public function test_fixed_recurrence_takes_precedence_during_overwrite(): void { $targetDate = now()->addDay(); $planner = $this->planner; $users = User::factory()->planner($planner)->count(2)->create(); // Create users $dishes = Dish::factory()->planner($planner)->count(200)->create(); // Create dishes // Attach dishes to users, ensuring `UserDish` records exist for every user $users->each(function (User $user) use ($dishes) { $dishes->random(50)->each(function (Dish $dish) use ($user) { UserDish::factory()->create([ 'user_id' => $user->id, 'dish_id' => $dish->id, ]); }); }); $scheduleDay = Schedule::factory() ->planner($planner) ->date($targetDate) ->create(); $fixedUser = $users->pop(); $targetUserDish = $fixedUser->userDishes->random(); $weeklyRecurrence = WeeklyRecurrence::factory()->create([ 'weekday' => $targetDate->dayOfWeek, ]); UserDishRecurrence::factory()->create([ 'user_dish_id' => $targetUserDish->id, 'recurrence_id' => $weeklyRecurrence->id, 'recurrence_type' => $weeklyRecurrence::class, ]); $users ->map(fn (User $user) => ScheduledUserDish::factory() ->create([ 'schedule_id' => $scheduleDay->id, 'user_dish_id' => $user->userDishes->random()->id, 'user_id' => $user->id, ])); ScheduledUserDish::factory() ->schedule($scheduleDay) ->userDish($targetUserDish) ->create(); $scheduleDay->refresh(); // assert all days have been filled $this->assertDatabaseCount(Schedule::class, 1); $this->assertDatabaseCount(ScheduledUserDish::class, 2); $this ->actingAs($planner) ->post(route('api.schedule.generate'), [ 'overwrite' => true, ]) ->assertStatus(200) ->assertJson(fn (AssertableJson $json) => $json ->where('success', true) ->where('payload', null) ->where('errors', null) ); $this->assertDatabaseCount(Schedule::class, 14); $targetDateSchedule = Schedule::query()->where('date', $targetDate->format('Y-m-d'))->first(); $this->assertNotNull($targetDateSchedule); $targetScheduledUserDishes = $targetDateSchedule ->scheduledUserDishes ->filter(fn (ScheduledUserDish $scheduledUserDish) => $scheduledUserDish->userDish->user->id === $fixedUser->id); $this->assertCount(1, $targetScheduledUserDishes); $this->assertContains($targetUserDish->id, $targetScheduledUserDishes->pluck('user_dish_id')->toArray()); } }