app/tests/Feature/Schedule/ScheduleEdgeCasesTest.php

254 lines
8 KiB
PHP

<?php
namespace Tests\Feature\Schedule;
use App\Models\Dish;
use App\Models\Planner;
use App\Models\Schedule;
use App\Models\ScheduledUserDish;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use Tests\Traits\HasPlanner;
class ScheduleEdgeCasesTest extends TestCase
{
use HasPlanner;
use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
$this->setUpHasPlanner();
}
public function test_generate_schedule_creates_schedule_records(): void
{
$planner = $this->planner;
$user = User::factory()->planner($planner)->create();
$dish = Dish::factory()->planner($planner)->create();
$dish->users()->attach($user);
$this->assertDatabaseEmpty(Schedule::class);
$response = $this
->actingAs($planner)
->post(route('api.schedule.generate'), [
'overwrite' => false,
]);
$response->assertStatus(200);
// Should create 14 schedule records (2 weeks)
$this->assertDatabaseCount(Schedule::class, 14);
}
public function test_overwrite_false_preserves_existing_schedules(): void
{
$planner = $this->planner;
$user = User::factory()->planner($planner)->create();
$dish1 = Dish::factory()->planner($planner)->create(['name' => 'Dish 1']);
$dish2 = Dish::factory()->planner($planner)->create(['name' => 'Dish 2']);
$dish1->users()->attach($user);
$dish2->users()->attach($user);
// Create a pre-existing schedule for today
$schedule = Schedule::factory()->create([
'planner_id' => $planner->id,
'date' => now()->format('Y-m-d'),
]);
$userDish1 = $user->userDishes()->where('dish_id', $dish1->id)->first();
$existingScheduledDish = ScheduledUserDish::factory()->create([
'schedule_id' => $schedule->id,
'user_id' => $user->id,
'user_dish_id' => $userDish1->id,
]);
// Generate with overwrite = false
$response = $this
->actingAs($planner)
->post(route('api.schedule.generate'), [
'overwrite' => false,
]);
$response->assertStatus(200);
// The existing scheduled dish should remain unchanged
$this->assertDatabaseHas(ScheduledUserDish::class, [
'id' => $existingScheduledDish->id,
'user_dish_id' => $userDish1->id,
]);
}
public function test_schedule_isolation_between_planners(): void
{
$planner1 = $this->planner;
$planner2 = Planner::factory()->create();
$user1 = User::factory()->planner($planner1)->create();
$user2 = User::factory()->planner($planner2)->create();
$dish1 = Dish::factory()->planner($planner1)->create();
$dish2 = Dish::factory()->planner($planner2)->create();
$dish1->users()->attach($user1);
$dish2->users()->attach($user2);
// Generate schedule for planner1
$this
->actingAs($planner1)
->post(route('api.schedule.generate'), ['overwrite' => false])
->assertStatus(200);
// Generate schedule for planner2
$this
->actingAs($planner2)
->post(route('api.schedule.generate'), ['overwrite' => false])
->assertStatus(200);
// Verify each planner only has their own schedules
$planner1Schedules = Schedule::withoutGlobalScopes()
->where('planner_id', $planner1->id)
->count();
$planner2Schedules = Schedule::withoutGlobalScopes()
->where('planner_id', $planner2->id)
->count();
$this->assertEquals(14, $planner1Schedules);
$this->assertEquals(14, $planner2Schedules);
}
public function test_skip_schedule_day_nullifies_user_dish(): void
{
$planner = $this->planner;
$user = User::factory()->planner($planner)->create();
$dish = Dish::factory()->planner($planner)->create();
$dish->users()->attach($user);
$userDish = $user->userDishes()->first();
$date = now()->format('Y-m-d');
// Create a schedule with a dish
$schedule = Schedule::factory()->create([
'planner_id' => $planner->id,
'date' => $date,
]);
$scheduledUserDish = ScheduledUserDish::factory()->create([
'schedule_id' => $schedule->id,
'user_id' => $user->id,
'user_dish_id' => $userDish->id,
'is_skipped' => false,
]);
// Mark the day as skipped
$response = $this
->actingAs($planner)
->put(route('api.schedule.update', ['date' => $date]), [
'is_skipped' => true,
]);
$response->assertStatus(200);
// Verify schedule is marked as skipped
$this->assertDatabaseHas(Schedule::class, [
'id' => $schedule->id,
'is_skipped' => true,
]);
// Verify scheduled user dish has null user_dish_id
$scheduledUserDish->refresh();
$this->assertNull($scheduledUserDish->user_dish_id);
}
public function test_delete_scheduled_user_dish_removes_record(): void
{
$planner = $this->planner;
$user = User::factory()->planner($planner)->create();
$dish = Dish::factory()->planner($planner)->create();
$dish->users()->attach($user);
$userDish = $user->userDishes()->first();
$schedule = Schedule::factory()->create([
'planner_id' => $planner->id,
'date' => now()->format('Y-m-d'),
]);
$scheduledUserDish = ScheduledUserDish::factory()->create([
'schedule_id' => $schedule->id,
'user_id' => $user->id,
'user_dish_id' => $userDish->id,
]);
$response = $this
->actingAs($planner)
->delete(route('api.scheduled-user-dishes.destroy', ['scheduledUserDish' => $scheduledUserDish->id]));
$response->assertStatus(200);
$this->assertDatabaseMissing(ScheduledUserDish::class, [
'id' => $scheduledUserDish->id,
]);
}
public function test_planner_cannot_delete_other_planners_scheduled_dish(): void
{
$planner1 = $this->planner;
$planner2 = Planner::factory()->create();
$user = User::factory()->planner($planner2)->create();
$dish = Dish::factory()->planner($planner2)->create();
$dish->users()->attach($user);
$userDish = $user->userDishes()->first();
$schedule = Schedule::factory()->create([
'planner_id' => $planner2->id,
'date' => now()->format('Y-m-d'),
]);
$scheduledUserDish = ScheduledUserDish::factory()->create([
'schedule_id' => $schedule->id,
'user_id' => $user->id,
'user_dish_id' => $userDish->id,
]);
// Try to delete as planner1 (should fail)
$response = $this
->actingAs($planner1)
->delete(route('api.scheduled-user-dishes.destroy', ['scheduledUserDish' => $scheduledUserDish->id]));
$response->assertStatus(403);
// Record should still exist
$this->assertDatabaseHas(ScheduledUserDish::class, [
'id' => $scheduledUserDish->id,
]);
}
public function test_schedule_show_creates_schedule_if_not_exists(): void
{
$planner = $this->planner;
$futureDate = now()->addDays(30)->format('Y-m-d');
$this->assertDatabaseMissing(Schedule::class, [
'planner_id' => $planner->id,
'date' => $futureDate,
]);
$response = $this
->actingAs($planner)
->get(route('api.schedule.show', ['date' => $futureDate]));
$response->assertStatus(200);
// Schedule should now exist
$this->assertDatabaseHas(Schedule::class, [
'planner_id' => $planner->id,
'date' => $futureDate,
]);
}
}