255 lines
8 KiB
PHP
255 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,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
}
|