user = User::factory() ->active() ->has(Employee::factory()) ->create(); }); function mountEditComponent(User $user, Outlet $outlet) { return Livewire::actingAs($user)->test(Edit::class, ['outlet' => $outlet]); } it('renders page successfully', function () { $outlet = Outlet::factory()->operational()->create(); mountEditComponent($this->user, $outlet) ->assertViewIs('livewire.studio.master.outlet.form') ->assertViewHas('pageTitle', 'Ubah Outlet'); }); it('mounts days and sets form with outlet', function () { $outlet = Outlet::factory()->operational()->create(); $component = mountEditComponent($this->user, $outlet); $days = Day::cases(); expect($component->days)->toHaveCount(count($days)); expect($component->form->outlet->id)->toBe($outlet->id); }); it('prevents update when user is unauthorized', function () { $outlet = Outlet::factory()->operational()->create(); Gate::define('update outlet', fn () => false); mountEditComponent($this->user, $outlet) ->call('save') ->assertForbidden(); }); it('updates outlet successfully when authorized', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outletModel = Outlet::factory()->operational()->create(); // model instance $outletData = Outlet::factory()->operational()->raw(); // data for update $facilities = Facility::factory()->count(5)->raw(); $featuredImage = makeLivewireFile('featured.jpg'); for ($i = 1; $i <= 5; $i++) { $images[] = makeLivewireFile("image{$i}.jpg"); } $openingHours = collect(Day::cases()) ->mapWithKeys(fn ($day) => [ $day->value => [ 'day' => $day->value, 'open_time' => fake()->time('H:i'), 'close_time' => fake()->time('H:i'), ], ]) ->toArray(); $data = array_merge($outletData, [ 'opening_hours' => $openingHours, 'facilities' => collect($facilities)->pluck('name')->toArray(), 'featured_image' => [$featuredImage], 'images' => $images, ]); mountEditComponent($this->user, $outletModel) ->set('form.name', $data['name']) ->set('form.phone_number', $data['phone_number']) ->set('form.address', $data['address']) ->set('form.landmark', $data['landmark']) ->set('form.maps_url', $data['maps_url']) ->set('form.opened_date', $data['opened_date']) ->set('form.status', $data['status']->value) ->set('form.opening_hours', $data['opening_hours']) ->set('form.facilities', $data['facilities']) ->set('form.featured_image', $data['featured_image']) ->set('form.images', $data['images']) ->call('save') ->assertHasNoErrors() ->assertRedirect(Index::class); $outletModel->refresh(); $this->assertDatabaseHas('outlets', [ 'id' => $outletModel->id, 'name' => $data['name'], 'phone_number' => $data['phone_number'], ]); $this->assertCount(1, $outletModel->getMedia('featured_image')); $this->assertCount(5, $outletModel->getMedia('images')); expect($outletModel->getFirstMedia('featured_image')->getPath())->toBeFile(); foreach ($outletModel->getMedia('images') as $media) { expect($media->getPath())->toBeFile(); } }); it('loads outlet data into form correctly', function () { $outlet = Outlet::factory() ->operational() ->has(OpeningHour::factory()->count(7)) ->has(Facility::factory()->count(3)) ->create(); $component = mountEditComponent($this->user, $outlet); expect($component->form->outlet->id)->toBe($outlet->id); expect($component->form->name)->toBe($outlet->name); expect($component->form->phone_number)->toBe($outlet->phone_number); expect($component->form->address)->toBe($outlet->address); expect($component->form->landmark)->toBe($outlet->landmark); expect($component->form->status)->toBe($outlet->status->value); expect($component->form->facilities)->toBe($outlet->facilities->pluck('name')->toArray()); }); it('loads opening hours into form correctly', function () { $outlet = Outlet::factory()->operational()->create(); // Create specific opening hours $openingHours = []; foreach (Day::cases() as $day) { $openingHours[] = OpeningHour::factory()->create([ 'outlet_id' => $outlet->id, 'day' => $day, 'open_time' => '09:00', 'close_time' => '21:00', ]); } $component = mountEditComponent($this->user, $outlet); foreach (Day::cases() as $day) { expect($component->form->opening_hours[$day->value]['open_time'])->toBe('09:00'); expect($component->form->opening_hours[$day->value]['close_time'])->toBe('21:00'); } }); it('updates outlet with partial data changes', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory() ->operational() ->has(Facility::factory()->count(2)) ->create(); $newName = 'Updated Outlet Name'; $images = [makeLivewireFile('image1.jpg')]; $featuredImage = makeLivewireFile('featured.jpg'); mountEditComponent($this->user, $outlet) ->set('form.name', $newName) ->set('form.opening_hours', makeValidOpeningHours()) ->set('form.facilities', ['Parkir']) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors() ->assertRedirect(Index::class); $outlet->refresh(); expect($outlet->name)->toBe($newName); expect($outlet->phone_number)->toBe($outlet->phone_number); // Unchanged }); it('updates outlet status to TERMINATED and sets closed_date', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory()->operational()->create(); $featuredImage = makeLivewireFile('featured.jpg'); $images = [makeLivewireFile('image1.jpg')]; mountEditComponent($this->user, $outlet) ->set('form.status', OutletStatus::TERMINATED->value) ->set('form.opening_hours', makeValidOpeningHours()) ->set('form.facilities', ['Parkir']) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors(); $outlet->refresh(); expect($outlet->status->value)->toBe(OutletStatus::TERMINATED->value); expect($outlet->closed_date)->not->toBeNull(); }); it('updates facilities correctly', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory() ->operational() ->has(Facility::factory()->count(2)) ->create(); $featuredImage = makeLivewireFile('featured.jpg'); $images = [makeLivewireFile('image1.jpg')]; $newFacilities = ['WiFi', 'AC', 'Parking']; mountEditComponent($this->user, $outlet) ->set('form.facilities', $newFacilities) ->set('form.opening_hours', makeValidOpeningHours()) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors(); $outlet->refresh(); expect($outlet->facilities->pluck('name')->toArray())->toBe($newFacilities); }); it('updates opening hours correctly', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory()->operational()->create(); $featuredImage = makeLivewireFile('featured.jpg'); $images = [makeLivewireFile('image1.jpg')]; $newOpeningHours = makeValidOpeningHours(); mountEditComponent($this->user, $outlet) ->set('form.opening_hours', $newOpeningHours) ->set('form.facilities', ['Parkir']) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors(); $outlet->refresh(); expect($outlet->openingHours)->toHaveCount(count(Day::cases())); foreach ($outlet->openingHours as $openingHour) { expect($openingHour->open_time)->toBe('09:00'); expect($openingHour->close_time)->toBe('21:00'); } }); it('validates required fields on update', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory()->operational()->create(); mountEditComponent($this->user, $outlet) ->set('form.name', '') // Empty required field ->call('save') ->assertHasErrors(['form.name']); }); it('maintains outlet relationships integrity', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory() ->operational() ->has(Facility::factory()->count(3)) ->create(); $originalOpeningHoursCount = count(Day::cases()); // Should be 7 after setOutlet $originalFacilitiesCount = 1; // We set facilities to ['Parkir'] in the test $featuredImage = makeLivewireFile('featured.jpg'); $images = [makeLivewireFile('image1.jpg')]; mountEditComponent($this->user, $outlet) ->set('form.name', 'Updated Name') ->set('form.opening_hours', makeValidOpeningHours()) ->set('form.facilities', ['Parkir']) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors(); $outlet->refresh(); expect($outlet->openingHours)->toHaveCount($originalOpeningHoursCount); expect($outlet->facilities)->toHaveCount($originalFacilitiesCount); }); it('handles outlet with no existing media', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory()->operational()->create(); $featuredImage = makeLivewireFile('featured.jpg'); $images = [makeLivewireFile('image1.jpg')]; mountEditComponent($this->user, $outlet) ->set('form.opening_hours', makeValidOpeningHours()) ->set('form.facilities', ['Parkir']) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors(); $outlet->refresh(); expect($outlet->getMedia('featured_image'))->toHaveCount(1); }); it('preserves outlet slug when updating', function () { $permission = Permission::create(['name' => 'update outlet']); $this->user->givePermissionTo($permission); $outlet = Outlet::factory()->operational()->create(); $originalSlug = $outlet->slug; $featuredImage = makeLivewireFile('featured.jpg'); $images = [makeLivewireFile('image1.jpg')]; mountEditComponent($this->user, $outlet) ->set('form.phone_number', '0812 3456 7890') // Change non-slug field ->set('form.opening_hours', makeValidOpeningHours()) ->set('form.facilities', ['Parkir']) ->set('form.featured_image', [$featuredImage]) ->set('form.images', $images) ->call('save') ->assertHasNoErrors(); $outlet->refresh(); expect($outlet->slug)->toBe($originalSlug); });