diff --git a/resources/views/livewire/studio/loyalty/redemption.blade.php b/resources/views/livewire/studio/loyalty/redemption.blade.php index d38727e..330fed8 100644 --- a/resources/views/livewire/studio/loyalty/redemption.blade.php +++ b/resources/views/livewire/studio/loyalty/redemption.blade.php @@ -67,14 +67,15 @@ class="font-bold uppercase">{{ $foundRedemption->code }} - @if ($foundRedemption->status === \App\Enums\RedemptionStatus::VERIFIED) + @if ($foundRedemption->status === \App\Enums\RedemptionStatus::PICKED_UP)
Diverifikasi Oleh
-
{{ $foundRedemption->verifier?->employee?->full_name ?? 'Sistem' }}
+
+ {{ $foundRedemption->verifier?->employee?->full_name ?? 'Sistem' }}
Waktu diff --git a/tests/Feature/Studio/Loyalty/RedemptionVerificationTest.php b/tests/Feature/Studio/Loyalty/RedemptionVerificationTest.php new file mode 100644 index 0000000..ff56ba6 --- /dev/null +++ b/tests/Feature/Studio/Loyalty/RedemptionVerificationTest.php @@ -0,0 +1,100 @@ +setupUser(); + + $role = Role::firstOrCreate(['name' => 'Owner']); + Permission::firstOrCreate(['name' => 'view redemption']); + Permission::firstOrCreate(['name' => 'update redemption']); + $role->givePermissionTo(['view redemption', 'update redemption']); + $this->user->assignRole($role); +}); + +it('renders the redemption verification page correctly', function () { + $this->actingAs($this->user) + ->get(route('studio.loyalty.redemption.index')) + ->assertOk() + ->assertSeeLivewire(RedemptionVerification::class); +}); + +it('can search for a redemption code', function () { + $redemption = Redemption::factory()->create(['code' => 'ABC123XYZ']); + + Livewire::actingAs($this->user) + ->test(RedemptionVerification::class) + ->set('searchCode', 'abc123xyz ') // Testing case insensitivity and trimming + ->call('search') + ->assertSet('foundRedemption.id', $redemption->id); +}); + +it('shows error if redemption code not found', function () { + Livewire::actingAs($this->user) + ->test(RedemptionVerification::class) + ->set('searchCode', 'NONEXISTENT') + ->call('search') + ->assertSet('foundRedemption', null); +}); + +it('can verify a redemption', function () { + $redemption = Redemption::factory()->create([ + 'code' => 'TESTCODE', + 'status' => RedemptionStatus::WAITING_PICKUP, + 'expires_at' => now()->addDay(), + ]); + + Livewire::actingAs($this->user) + ->test(RedemptionVerification::class) + ->set('searchCode', 'TESTCODE') + ->call('search') + ->call('verify'); + + $redemption->refresh(); + expect($redemption->status)->toBe(RedemptionStatus::PICKED_UP); + expect($redemption->verified_by)->toBe($this->user->id); +}); + +it('cannot verify expired redemption', function () { + $redemption = Redemption::factory()->create([ + 'code' => 'EXPIRED', + 'status' => RedemptionStatus::WAITING_PICKUP, + 'expires_at' => now()->subDay(), + ]); + + Livewire::actingAs($this->user) + ->test(RedemptionVerification::class) + ->set('searchCode', 'EXPIRED') + ->call('search') + ->call('verify'); + + $redemption->refresh(); + expect($redemption->status)->toBe(RedemptionStatus::EXPIRED); +}); + +it('cannot verify already processed redemption', function () { + $redemption = Redemption::factory()->verified($this->user)->create(['code' => 'PROCESSED']); + + Livewire::actingAs($this->user) + ->test(RedemptionVerification::class) + ->set('searchCode', 'PROCESSED') + ->call('search') + ->call('verify'); + + $redemption->refresh(); + expect($redemption->status)->toBe(RedemptionStatus::PICKED_UP); // Remains picked up +}); + +it('cannot access redemption verification without permission', function () { + $this->user->roles()->detach(); + $this->user->permissions()->detach(); + + $this->actingAs($this->user) + ->get(route('studio.loyalty.redemption.index')) + ->assertForbidden(); +}); diff --git a/tests/Feature/Studio/Loyalty/RewardTest.php b/tests/Feature/Studio/Loyalty/RewardTest.php new file mode 100644 index 0000000..9a42058 --- /dev/null +++ b/tests/Feature/Studio/Loyalty/RewardTest.php @@ -0,0 +1,150 @@ +setupUser(); + + $role = Role::firstOrCreate(['name' => 'Owner']); + Permission::firstOrCreate(['name' => 'view reward']); + Permission::firstOrCreate(['name' => 'create reward']); + Permission::firstOrCreate(['name' => 'update reward']); + Permission::firstOrCreate(['name' => 'delete reward']); + $role->givePermissionTo(['view reward', 'create reward', 'update reward', 'delete reward']); + $this->user->assignRole($role); +}); + +it('renders the reward page correctly', function () { + $this->actingAs($this->user) + ->get(route('studio.loyalty.reward.index')) + ->assertOk() + ->assertSeeLivewire(Reward::class); +}); + +it('can open create modal', function () { + Livewire::actingAs($this->user) + ->test(Reward::class) + ->call('openModal', 'create', 'Tambah Hadiah') + ->assertSet('method', 'create') + ->assertSet('modalTitle', 'Tambah Hadiah'); +}); + +it('shows validation errors on create', function () { + Livewire::actingAs($this->user) + ->test(Reward::class) + ->call('create') + ->assertHasErrors([ + 'form.name' => 'required', + 'form.points' => 'required', + 'form.start_date' => 'required', + 'form.tier_ids' => 'required', + ]); +}); + +it('can store a new reward', function () { + $tier = Tier::factory()->create(['min_spending' => 0]); + + Livewire::actingAs($this->user) + ->test(Reward::class) + ->set('form.name', 'Hadiah Keren') + ->set('form.points', '100') + ->set('form.category', RewardCategory::REGULAR->value) + ->set('form.is_show', IsShow::SHOW->value) + ->set('form.start_date', now()->format('Y-m-d')) + ->set('form.tier_ids', [$tier->id]) + ->call('create') + ->assertHasNoErrors() + ->assertDispatched('refreshDatatable'); + + $this->assertDatabaseHas('rewards', [ + 'name' => 'Hadiah Keren', + 'points' => 100, + ]); +}); + +it('can open edit modal and load data', function () { + $tier = Tier::factory()->create(['min_spending' => 0]); + $reward = RewardModel::factory()->create(['name' => 'Old Name', 'points' => 50]); + $reward->tiers()->attach($tier); + + Livewire::actingAs($this->user) + ->test(Reward::class) + ->call('openModal', 'update', 'Ubah Hadiah', $reward->hash_id) + ->set('form.reward', $reward) + ->set('form.name', 'Old Name') + ->set('form.points', '50') + ->assertSet('method', 'update') + ->assertSet('form.name', 'Old Name') + ->assertSet('form.points', '50'); +}); + +it('can update a reward', function () { + $tier = Tier::factory()->create(['min_spending' => 0]); + $reward = RewardModel::factory()->create(['name' => 'Old Name', 'points' => 50]); + $reward->tiers()->attach($tier); + + Livewire::actingAs($this->user) + ->test(Reward::class) + ->call('openModal', 'update', 'Ubah Hadiah', $reward->hash_id) + ->set('form.reward', $reward) + ->set('form.name', 'Updated Name') + ->set('form.points', '75') + ->set('form.category', $reward->category->value) + ->set('form.is_show', $reward->is_show->value) + ->set('form.start_date', $reward->start_date) + ->set('form.tier_ids', [$tier->id]) + ->call('update') + ->assertHasNoErrors() + ->assertDispatched('refreshDatatable'); + + $this->assertDatabaseHas('rewards', [ + 'id' => $reward->id, + 'name' => 'Updated Name', + 'points' => 75, + ]); +}); + +it('cannot update a reward if redemptions exist', function () { + $reward = RewardModel::factory()->create(); + Redemption::factory()->create(['reward_id' => $reward->id]); + + Livewire::actingAs($this->user) + ->test(Reward::class) + ->call('openModal', 'update', 'Ubah Hadiah', $reward->hash_id) + ->set('form.reward', $reward) + ->set('form.name', 'Attempt Update') + ->call('update') + ->assertHasNoErrors(); + + // Verify it didn't change in DB + $this->assertDatabaseMissing('rewards', ['id' => $reward->id, 'name' => 'Attempt Update']); +}); + +it('can delete a reward', function () { + $reward = RewardModel::factory()->create(); + + Livewire::actingAs($this->user) + ->test(Reward::class) + ->call('delete', $reward->id) + ->assertHasNoErrors() + ->assertDispatched('refreshDatatable'); + + $this->assertSoftDeleted('rewards', ['id' => $reward->id]); +}); + +it('cannot access reward page without permission', function () { + $this->user->roles()->detach(); + $this->user->permissions()->detach(); + + $this->actingAs($this->user) + ->get(route('studio.loyalty.reward.index')) + ->assertForbidden(); +});