app/tests/Feature/Schedule/GenerateScheduleTest.php

258 lines
9 KiB
PHP
Raw Normal View History

2025-10-13 14:57:11 +02:00
<?php
namespace Tests\Feature\Schedule;
use App\Models\Dish;
use App\Models\Planner;
use App\Models\UserDish;
use App\Models\UserDishRecurrence;
use App\Models\Schedule;
use App\Models\ScheduledUserDish;
use App\Models\User;
use App\Models\WeeklyRecurrence;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Illuminate\Testing\Fluent\AssertableJson;
use Tests\TestCase;
use Tests\Traits\HasPlanner;
class GenerateScheduleTest extends TestCase
{
use HasPlanner;
use RefreshDatabase;
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());
}
}