- menyesuaikan testing - menghapus route untuk delete karena tidak lewat route - menyesuaikan tipe prop dan lainnya
426 lines
15 KiB
PHP
426 lines
15 KiB
PHP
<?php
|
|
|
|
require_once __DIR__.'/TestHelpers.php';
|
|
|
|
use App\Enums\Day;
|
|
use App\Enums\OutletStatus;
|
|
use App\Livewire\Studio\Master\Outlet\Create;
|
|
use App\Livewire\Studio\Master\Outlet\Index;
|
|
use App\Models\Employee;
|
|
use App\Models\Facility;
|
|
use App\Models\Outlet;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Livewire\Livewire;
|
|
use Spatie\Permission\Models\Permission;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
$this->user = User::factory()
|
|
->active()
|
|
->has(Employee::factory())
|
|
->create();
|
|
});
|
|
|
|
function mountCreateComponent(User $user)
|
|
{
|
|
return Livewire::actingAs($user)->test(Create::class);
|
|
}
|
|
|
|
it('renders page successfully', function () {
|
|
mountCreateComponent($this->user)
|
|
->assertViewIs('livewire.studio.master.outlet.form')
|
|
->assertViewHas('pageTitle', 'Tambah Outlet');
|
|
});
|
|
|
|
it('mounts days and form opening_hours correctly', function () {
|
|
$component = mountCreateComponent($this->user);
|
|
$days = Day::cases();
|
|
|
|
expect($component->days)->toHaveCount(count($days));
|
|
|
|
foreach ($days as $day) {
|
|
expect(array_key_exists($day->value, $component->form->opening_hours))->toBeTrue();
|
|
expect($component->form->opening_hours[$day->value])->toBe(['open_time' => null, 'close_time' => null]);
|
|
}
|
|
});
|
|
|
|
it('prevents create when user is unauthorized', function () {
|
|
Gate::define('create outlet', fn () => false);
|
|
|
|
mountCreateComponent($this->user)
|
|
->call('save')
|
|
->assertForbidden();
|
|
});
|
|
|
|
it('saves outlet successfully when authorized', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$facilities = Facility::factory()->count(5)->raw();
|
|
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [];
|
|
|
|
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($outlet, [
|
|
'opening_hours' => $openingHours,
|
|
'facilities' => collect($facilities)->pluck('name')->toArray(),
|
|
'featured_image' => [$featuredImage],
|
|
'images' => $images,
|
|
]);
|
|
|
|
mountCreateComponent($this->user)
|
|
->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);
|
|
|
|
$outlet = Outlet::first();
|
|
|
|
$this->assertDatabaseHas('outlets', [
|
|
'id' => $outlet->id,
|
|
'name' => $data['name'],
|
|
'phone_number' => $data['phone_number'],
|
|
]);
|
|
|
|
$this->assertCount(1, $outlet->getMedia('featured_image'));
|
|
$this->assertCount(5, $outlet->getMedia('images'));
|
|
|
|
expect($outlet->getFirstMedia('featured_image')->getPath())->toBeFile();
|
|
foreach ($outlet->getMedia('images') as $media) {
|
|
expect($media->getPath())->toBeFile();
|
|
}
|
|
});
|
|
|
|
it('validates required fields', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
mountCreateComponent($this->user)
|
|
->call('save')
|
|
->assertHasErrors([
|
|
'form.name',
|
|
'form.phone_number',
|
|
'form.address',
|
|
'form.landmark',
|
|
'form.opened_date',
|
|
'form.featured_image',
|
|
'form.images',
|
|
]);
|
|
});
|
|
|
|
it('validates name field max length', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', str_repeat('a', 101))
|
|
->call('save')
|
|
->assertHasErrors(['form.name']);
|
|
});
|
|
|
|
it('validates facilities minimum count', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.facilities', [])
|
|
->call('save')
|
|
->assertHasErrors(['form.facilities']);
|
|
});
|
|
|
|
it('validates featured image max count', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$featuredImages = [
|
|
makeLivewireFile('featured1.jpg'),
|
|
makeLivewireFile('featured2.jpg'),
|
|
];
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.featured_image', $featuredImages)
|
|
->call('save')
|
|
->assertHasErrors(['form.featured_image']);
|
|
});
|
|
|
|
it('validates images max count', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$images = [];
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
$images[] = makeLivewireFile("image{$i}.jpg");
|
|
}
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasErrors(['form.images']);
|
|
});
|
|
|
|
it('has default facilities value', function () {
|
|
$component = mountCreateComponent($this->user);
|
|
|
|
expect($component->form->facilities)->toBe(['Parkir']);
|
|
});
|
|
|
|
it('initializes opening hours for all days of week', function () {
|
|
$component = mountCreateComponent($this->user);
|
|
|
|
foreach (Day::cases() as $day) {
|
|
expect(array_key_exists($day->value, $component->form->opening_hours))->toBeTrue();
|
|
expect($component->form->opening_hours[$day->value])->toHaveKeys(['open_time', 'close_time']);
|
|
expect($component->form->opening_hours[$day->value]['open_time'])->toBeNull();
|
|
expect($component->form->opening_hours[$day->value]['close_time'])->toBeNull();
|
|
}
|
|
});
|
|
|
|
it('creates outlet with opening hours for all days', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [makeLivewireFile('image1.jpg')];
|
|
|
|
$openingHours = collect(Day::cases())
|
|
->mapWithKeys(fn ($day) => [
|
|
$day->value => [
|
|
'open_time' => '09:00',
|
|
'close_time' => '21:00',
|
|
],
|
|
])
|
|
->toArray();
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.status', $outlet['status']->value)
|
|
->set('form.opening_hours', $openingHours)
|
|
->set('form.facilities', ['Parkir'])
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$createdOutlet = Outlet::first();
|
|
expect($createdOutlet->openingHours)->toHaveCount(count(Day::cases()));
|
|
|
|
// Verify opening hours data
|
|
foreach ($createdOutlet->openingHours as $openingHour) {
|
|
expect($openingHour->open_time)->toBe('09:00');
|
|
expect($openingHour->close_time)->toBe('21:00');
|
|
}
|
|
});
|
|
|
|
it('creates outlet with facilities', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [makeLivewireFile('image1.jpg')];
|
|
$facilities = ['Parkir', 'WiFi', 'AC'];
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.status', $outlet['status']->value)
|
|
->set('form.facilities', $facilities)
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$createdOutlet = Outlet::first();
|
|
expect($createdOutlet->facilities->pluck('name')->toArray())->toBe($facilities);
|
|
});
|
|
|
|
it('sets closed_date when status is TERMINATED', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [makeLivewireFile('image1.jpg')];
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.status', OutletStatus::TERMINATED->value)
|
|
->set('form.facilities', ['Parkir'])
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$createdOutlet = Outlet::first();
|
|
expect($createdOutlet->status->value)->toBe(OutletStatus::TERMINATED->value);
|
|
expect($createdOutlet->closed_date)->not->toBeNull();
|
|
});
|
|
|
|
it('does not set closed_date for non-terminated status', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [makeLivewireFile('image1.jpg')];
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.status', OutletStatus::OPERATIONAL->value)
|
|
->set('form.facilities', ['Parkir'])
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$createdOutlet = Outlet::first();
|
|
expect($createdOutlet->closed_date)->toBeNull();
|
|
});
|
|
|
|
it('can add and remove facilities dynamically', function () {
|
|
$component = mountCreateComponent($this->user);
|
|
|
|
// Initial state
|
|
expect($component->form->facilities)->toBe(['Parkir']);
|
|
|
|
// Add facility
|
|
$component->call('addFacility');
|
|
expect($component->form->facilities)->toBe(['Parkir', '']);
|
|
|
|
// Add another facility
|
|
$component->call('addFacility');
|
|
expect($component->form->facilities)->toBe(['Parkir', '', '']);
|
|
|
|
// Remove middle facility
|
|
$component->call('removeFacility', 1);
|
|
expect($component->form->facilities)->toBe(['Parkir', '']);
|
|
|
|
// Remove first facility (should keep at least one empty)
|
|
$component->call('removeFacility', 0);
|
|
expect($component->form->facilities)->toBe(['']);
|
|
});
|
|
|
|
it('validates maps_url regex pattern', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [makeLivewireFile('image1.jpg')];
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.maps_url', 'invalid-url')
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.facilities', ['Parkir'])
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasErrors(['form.maps_url']);
|
|
|
|
// Valid Google Maps URL should pass
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.maps_url', 'https://maps.app.goo.gl/example')
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.facilities', ['Parkir'])
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
});
|
|
|
|
it('handles facility removal edge cases', function () {
|
|
$component = mountCreateComponent($this->user);
|
|
|
|
// Set custom facilities
|
|
$component->set('form.facilities', ['Parkir', 'WiFi', 'AC']);
|
|
|
|
// Remove middle facility
|
|
$component->call('removeFacility', 1);
|
|
expect($component->form->facilities)->toBe(['Parkir', 'AC']);
|
|
|
|
// Try to remove non-existent index (should not crash)
|
|
$component->call('removeFacility', 99);
|
|
expect($component->form->facilities)->toBe(['Parkir', 'AC']);
|
|
});
|
|
|
|
it('creates outlet with soft delete capability', function () {
|
|
$permission = Permission::create(['name' => 'create outlet']);
|
|
$this->user->givePermissionTo($permission);
|
|
|
|
$outlet = Outlet::factory()->operational()->raw();
|
|
$featuredImage = makeLivewireFile('featured.jpg');
|
|
$images = [makeLivewireFile('image1.jpg')];
|
|
|
|
mountCreateComponent($this->user)
|
|
->set('form.name', $outlet['name'])
|
|
->set('form.phone_number', $outlet['phone_number'])
|
|
->set('form.address', $outlet['address'])
|
|
->set('form.landmark', $outlet['landmark'])
|
|
->set('form.opened_date', $outlet['opened_date'])
|
|
->set('form.facilities', ['Parkir'])
|
|
->set('form.featured_image', [$featuredImage])
|
|
->set('form.images', $images)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$createdOutlet = Outlet::first();
|
|
expect($createdOutlet)->toBeInstanceOf(Outlet::class);
|
|
|
|
// Verify soft delete trait
|
|
$createdOutlet->delete();
|
|
expect(Outlet::withTrashed()->find($createdOutlet->id))->not->toBeNull();
|
|
expect(Outlet::find($createdOutlet->id))->toBeNull();
|
|
});
|