From 5c2cb53887b927030dbd6f94f343b8f1009ef499 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Fri, 2 Jan 2026 19:14:20 +0700 Subject: [PATCH] test: add feature tests for voucher create, edit, and index pages, and fix `canOrAbort` typo in voucher deletion. --- app/Livewire/Studio/Loyalty/Voucher/Index.php | 2 +- .../Studio/Loyalty/Voucher/CreateTest.php | 89 +++++++++++++++++++ .../Studio/Loyalty/Voucher/EditTest.php | 82 +++++++++++++++++ .../Studio/Loyalty/Voucher/IndexTest.php | 69 ++++++++++++++ 4 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/Studio/Loyalty/Voucher/CreateTest.php create mode 100644 tests/Feature/Studio/Loyalty/Voucher/EditTest.php create mode 100644 tests/Feature/Studio/Loyalty/Voucher/IndexTest.php diff --git a/app/Livewire/Studio/Loyalty/Voucher/Index.php b/app/Livewire/Studio/Loyalty/Voucher/Index.php index dab8cfb..7b6f196 100644 --- a/app/Livewire/Studio/Loyalty/Voucher/Index.php +++ b/app/Livewire/Studio/Loyalty/Voucher/Index.php @@ -55,7 +55,7 @@ public function mount(): void public function delete(Voucher $voucher): void { - $this->canOrAbbort('delete voucher'); + $this->canOrAbort('delete voucher'); $voucher->delete(); diff --git a/tests/Feature/Studio/Loyalty/Voucher/CreateTest.php b/tests/Feature/Studio/Loyalty/Voucher/CreateTest.php new file mode 100644 index 0000000..256fc2d --- /dev/null +++ b/tests/Feature/Studio/Loyalty/Voucher/CreateTest.php @@ -0,0 +1,89 @@ +setupUser(); + + $role = Role::firstOrCreate(['name' => 'Owner']); + Permission::firstOrCreate(['name' => 'create voucher']); + $role->givePermissionTo(['create voucher']); + $this->user->assignRole($role); +}); + +it('renders the voucher create page correctly', function () { + $this->actingAs($this->user) + ->get(route('studio.loyalty.voucher.create')) + ->assertOk() + ->assertSeeLivewire(Create::class); +}); + +it('shows validation error when fields are empty', function () { + Livewire::actingAs($this->user) + ->test(Create::class) + ->set('form.type', '') // Set to empty to trigger required validation + ->call('save') + ->assertHasErrors([ + 'form.name' => 'required', + 'form.code' => 'required', + 'form.type' => 'required', + 'form.discount_amount' => 'required', + 'form.tier_ids' => 'required', + 'form.outlet_ids' => 'required', + ]); +}); + +it('validates unique voucher code', function () { + Voucher::factory()->create(['code' => 'EXISTING']); + + Livewire::actingAs($this->user) + ->test(Create::class) + ->set('form.code', 'EXISTING') + ->call('save') + ->assertHasErrors(['form.code' => 'unique']); +}); + +it('can store a new voucher', function () { + $outlet = Outlet::factory()->create(); + $tier = Tier::factory()->create(['min_spending' => 0]); + + Livewire::actingAs($this->user) + ->test(Create::class) + ->set('form.name', 'Promo Baru') + ->set('form.code', 'PROMOBARU') + ->set('form.tags', 'Promo') + ->set('form.type', VoucherType::FIXED->value) + ->set('form.discount_amount', '20.000') + ->set('form.limit_per_user', '1') + ->set('form.summary', 'Potongan harga 20rb') + ->set('form.start_date', now()->addDay()->format('Y-m-d')) + ->set('form.outlet_ids', [$outlet->id]) + ->set('form.tier_ids', [$tier->id]) + ->call('save') + ->assertHasNoErrors() + ->assertRedirect(route('studio.loyalty.voucher.index', [ + 'notification' => 'Voucher berhasil ditambahkan.', + ])); + + $this->assertDatabaseHas('vouchers', [ + 'name' => 'Promo Baru', + 'code' => 'PROMOBARU', + 'discount_amount' => 20000, + ]); +}); + +it('cannot access voucher create without permission', function () { + $this->user->roles()->detach(); + $this->user->permissions()->detach(); + + $this->actingAs($this->user) + ->get(route('studio.loyalty.voucher.create')) + ->assertForbidden(); +}); diff --git a/tests/Feature/Studio/Loyalty/Voucher/EditTest.php b/tests/Feature/Studio/Loyalty/Voucher/EditTest.php new file mode 100644 index 0000000..5fc93bf --- /dev/null +++ b/tests/Feature/Studio/Loyalty/Voucher/EditTest.php @@ -0,0 +1,82 @@ +setupUser(); + + $role = Role::firstOrCreate(['name' => 'Owner']); + Permission::firstOrCreate(['name' => 'update voucher']); + $role->givePermissionTo(['update voucher']); + $this->user->assignRole($role); +}); + +it('renders the voucher edit page correctly', function () { + $voucher = Voucher::factory()->create(); + + $this->actingAs($this->user) + ->get(route('studio.loyalty.voucher.edit', ['voucher' => $voucher])) + ->assertOk() + ->assertSeeLivewire(Edit::class); +}); + +it('loads existing voucher data correctly', function () { + $voucher = Voucher::factory()->create([ + 'name' => 'Original Name', + 'code' => 'ORIGINAL', + 'type' => VoucherType::FIXED, + 'discount_amount' => 50000, + ]); + + Livewire::actingAs($this->user) + ->test(Edit::class, ['voucher' => $voucher]) + ->assertSet('form.name', 'Original Name') + ->assertSet('form.code', 'ORIGINAL') + ->assertSet('form.discount_amount', 50000); +}); + +it('can update a voucher', function () { + $voucher = Voucher::factory()->create([ + 'type' => VoucherType::FIXED, + 'start_date' => now()->addDays(2)->format('Y-m-d'), + ]); + $outlet = Outlet::factory()->create(); + $tier = Tier::factory()->create(['min_spending' => 0]); + + $voucher->outlets()->attach($outlet); + $voucher->tiers()->attach($tier); + + Livewire::actingAs($this->user) + ->test(Edit::class, ['voucher' => $voucher]) + ->set('form.name', 'Updated Name') + ->set('form.discount_amount', '60.000') + ->call('save') + ->assertHasNoErrors() + ->assertRedirect(route('studio.loyalty.voucher.index', [ + 'notification' => 'Voucher berhasil diperbarui.', + ])); + + $this->assertDatabaseHas('vouchers', [ + 'id' => $voucher->id, + 'name' => 'Updated Name', + 'discount_amount' => 60000, + ]); +}); + +it('cannot access voucher edit without permission', function () { + $this->user->roles()->detach(); + $this->user->permissions()->detach(); + + $voucher = Voucher::factory()->create(); + + $this->actingAs($this->user) + ->get(route('studio.loyalty.voucher.edit', ['voucher' => $voucher])) + ->assertForbidden(); +}); diff --git a/tests/Feature/Studio/Loyalty/Voucher/IndexTest.php b/tests/Feature/Studio/Loyalty/Voucher/IndexTest.php new file mode 100644 index 0000000..81fffce --- /dev/null +++ b/tests/Feature/Studio/Loyalty/Voucher/IndexTest.php @@ -0,0 +1,69 @@ +setupUser(); + + $role = Role::firstOrCreate(['name' => 'Owner']); + Permission::firstOrCreate(['name' => 'view voucher']); + Permission::firstOrCreate(['name' => 'delete voucher']); + $role->givePermissionTo(['view voucher', 'delete voucher']); + $this->user->assignRole($role); +}); + +it('renders the voucher index page correctly', function () { + $this->actingAs($this->user) + ->get(route('studio.loyalty.voucher.index')) + ->assertOk() + ->assertSeeLivewire(Index::class); +}); + +it('displays voucher statistics correctly', function () { + Voucher::factory()->count(2)->create(['start_date' => now()->subDays(5)]); + Voucher::factory()->create(['start_date' => now()->addDays(5)]); + + Livewire::actingAs($this->user) + ->test(Index::class) + ->assertSet('stats.0.value', 3) // Total + ->assertSet('stats.1.value', 2) // Active (depends on implementation, assuming today is active) + ->assertSet('stats.3.value', 1); // Upcoming +}); + +it('can delete a voucher', function () { + $voucher = Voucher::factory()->create(); + + Livewire::actingAs($this->user) + ->test(Index::class) + ->call('delete', $voucher->id) + ->assertDispatched('refreshDatatable'); + + $this->assertSoftDeleted('vouchers', [ + 'id' => $voucher->id, + ]); +}); + +it('cannot access voucher index without permission', function () { + $this->user->roles()->detach(); + $this->user->permissions()->detach(); + + $this->actingAs($this->user) + ->get(route('studio.loyalty.voucher.index')) + ->assertForbidden(); +}); + +it('cannot delete voucher without permission', function () { + $this->user->roles()->detach(); + $this->user->permissions()->detach(); + + $voucher = Voucher::factory()->create(); + + Livewire::actingAs($this->user) + ->test(Index::class) + ->call('delete', $voucher->id) + ->assertForbidden(); +});