user = User::factory() ->active() ->has(Employee::factory()) ->create(); }); function createOutlet(array $attributes = []): Outlet { return Outlet::factory() ->has(OpeningHour::factory()->count(7)) ->has(Facility::factory()->count(5)) ->state(fn () => array_merge([ 'status' => fake()->randomElement(OutletStatus::cases()), ], $attributes)) ->create(); } function mountIndexComponent(User $user): Testable { return Livewire::actingAs($user)->test(Index::class); } it('renders page successfully', function () { mountIndexComponent($this->user) ->assertViewIs('livewire.studio.master.outlet.index') ->assertViewHas('pageTitle', 'Outlet'); }); it('loads outlets as Eloquent collection', function () { $outlet = createOutlet(); $component = mountIndexComponent($this->user); expect($component->get('outlets')) ->toBeInstanceOf(Collection::class) ->and($component->get('outlets')->first()->id)->toBe($outlet->id); }); it('loads outlets with relationships', function () { $outlet = createOutlet(); $component = mountIndexComponent($this->user); $loadedOutlet = $component->get('outlets')->first(); expect($loadedOutlet->openingHours)->toHaveCount(7) ->and($loadedOutlet->facilities)->toHaveCount(5); }); it('displays all outlets', function () { for ($i = 0; $i < 5; $i++) { createOutlet(); } $component = mountIndexComponent($this->user); expect($component->get('outlets'))->toHaveCount(5); expect($component->get('outlets')->first())->toBeInstanceOf(Outlet::class); }); it('prevents delete when user is unauthorized', function () { $outlet = createOutlet(); Gate::define('delete outlet', fn () => false); mountIndexComponent($this->user) ->call('delete', $outlet) ->assertForbidden(); }); it('deletes an outlet successfully when authorized', function () { $permission = Permission::create(['name' => 'delete outlet']); $this->user->givePermissionTo($permission); $outlet = createOutlet(); mountIndexComponent($this->user) ->call('delete', $outlet) ->assertHasNoErrors(); $this->assertSoftDeleted('outlets', ['id' => $outlet->id]); }); it('filters outlets by search query', function () { $outlet1 = createOutlet(['name' => 'Outlet Jakarta']); $outlet2 = createOutlet(['name' => 'Outlet Bandung']); $outlet3 = createOutlet(['name' => 'Toko Surabaya']); $component = mountIndexComponent($this->user); expect($component->get('outlets'))->toHaveCount(3); // Test filtering by Jakarta $component->set('search', 'Jakarta'); $filteredComponent = mountIndexComponent($this->user)->set('search', 'Jakarta'); expect($filteredComponent->get('outlets'))->toHaveCount(1); expect($filteredComponent->get('outlets')->first()->name)->toBe('Outlet Jakarta'); // Test filtering by Outlet $filteredComponent2 = mountIndexComponent($this->user)->set('search', 'Outlet'); expect($filteredComponent2->get('outlets'))->toHaveCount(2); }); it('filters outlets by status', function () { $outlet1 = createOutlet(['status' => OutletStatus::OPERATIONAL]); $outlet2 = createOutlet(['status' => OutletStatus::UNDER_CONSTRUCTION]); $outlet3 = createOutlet(['status' => OutletStatus::TERMINATED]); $component = mountIndexComponent($this->user); expect($component->get('outlets'))->toHaveCount(3); $filteredComponent = mountIndexComponent($this->user)->set('status', [OutletStatus::OPERATIONAL->value]); expect($filteredComponent->get('outlets'))->toHaveCount(1); expect($filteredComponent->get('outlets')->first()->name)->toBe($outlet1->name); // Test filtering by multiple statuses $filteredComponent2 = mountIndexComponent($this->user)->set('status', [ OutletStatus::OPERATIONAL->value, OutletStatus::UNDER_CONSTRUCTION->value, ]); expect($filteredComponent2->get('outlets'))->toHaveCount(2); }); it('filters outlets by both search and status', function () { $outlet1 = createOutlet(['name' => 'Outlet A', 'status' => OutletStatus::OPERATIONAL]); $outlet2 = createOutlet(['name' => 'Outlet B', 'status' => OutletStatus::OPERATIONAL]); $outlet3 = createOutlet(['name' => 'Outlet C', 'status' => OutletStatus::UNDER_CONSTRUCTION]); $component = mountIndexComponent($this->user) ->set('search', 'Outlet') ->set('status', [OutletStatus::OPERATIONAL->value]); expect($component->get('outlets'))->toHaveCount(2); }); it('loads outlets with all required relationships', function () { $outlet = createOutlet(); $component = mountIndexComponent($this->user); $loadedOutlet = $component->get('outlets')->first(); expect($loadedOutlet->openingHours)->toHaveCount(7) ->and($loadedOutlet->facilities)->toHaveCount(5) ->and($loadedOutlet->name)->toBe($outlet->name) ->and($loadedOutlet->phone_number)->toBe($outlet->phone_number); }); it('loads outlets ordered by latest', function () { $outlet1 = createOutlet(['name' => 'First']); sleep(1); $outlet2 = createOutlet(['name' => 'Second']); $component = mountIndexComponent($this->user); expect($component->get('outlets')->first()->name)->toBe('Second'); expect($component->get('outlets')->last()->name)->toBe('First'); }); it('provides helper methods for view formatting', function () { $outlet = createOutlet(); $component = mountIndexComponent($this->user); // Test that outlets are loaded with proper data structure $loadedOutlet = $component->get('outlets')->first(); expect($loadedOutlet)->toBeInstanceOf(Outlet::class); expect($loadedOutlet->openingHours)->toBeInstanceOf(Collection::class); expect($loadedOutlet->facilities)->toBeInstanceOf(Collection::class); }); it('handles empty search results gracefully', function () { createOutlet(['name' => 'Existing Outlet']); $component = mountIndexComponent($this->user)->set('search', 'NonExistentOutlet'); expect($component->get('outlets'))->toHaveCount(0); }); it('maintains search state across component lifecycle', function () { $outlet1 = createOutlet(['name' => 'Test Outlet']); $outlet2 = createOutlet(['name' => 'Another Outlet']); $component = mountIndexComponent($this->user)->set('search', 'Test'); expect($component->get('outlets'))->toHaveCount(1); expect($component->get('search'))->toBe('Test'); // Re-mount should maintain state $newComponent = mountIndexComponent($this->user)->set('search', 'Test'); expect($newComponent->get('outlets'))->toHaveCount(1); }); it('handles status filter with empty array', function () { createOutlet(['status' => OutletStatus::OPERATIONAL]); createOutlet(['status' => OutletStatus::TERMINATED]); $component = mountIndexComponent($this->user)->set('status', []); expect($component->get('outlets'))->toHaveCount(2); }); it('loads outlets efficiently with eager loading', function () { $outlets = collect(); for ($i = 0; $i < 10; $i++) { $outlets->push(createOutlet()); } $component = mountIndexComponent($this->user); // Verify relationships are loaded $loadedOutlets = $component->get('outlets'); foreach ($loadedOutlets as $loadedOutlet) { expect($loadedOutlet->relationLoaded('openingHours'))->toBeTrue(); expect($loadedOutlet->relationLoaded('facilities'))->toBeTrue(); } });