setupUser(); $role = Role::firstOrCreate(['name' => 'Owner']); Permission::firstOrCreate(['name' => 'view tier']); Permission::firstOrCreate(['name' => 'create tier']); Permission::firstOrCreate(['name' => 'update tier']); Permission::firstOrCreate(['name' => 'delete tier']); $role->givePermissionTo(['view tier', 'create tier', 'update tier', 'delete tier']); $this->user->assignRole($role); }); it('renders the tier index page correctly', function () { $this->actingAs($this->user) ->get(route('studio.loyalty.tier.index')) ->assertOk() ->assertSeeLivewire(Tier::class); }); it('can open create modal', function () { Livewire::actingAs($this->user) ->test(Tier::class) ->dispatch('modal:open', method: 'create', modalTitle: 'Tambah Tier') ->assertSet('method', 'create') ->assertSet('modalTitle', 'Tambah Tier'); }); it('validates required fields on create', function () { Livewire::actingAs($this->user) ->test(Tier::class) ->call('create') ->assertHasErrors(['form.name' => 'required', 'form.min_spending' => 'required']); }); it('can store a new tier', function () { // Ensure no tiers exist first TierModel::query()->delete(); Livewire::actingAs($this->user) ->test(Tier::class) ->set('form.name', 'Bronze') ->set('form.min_spending', '0') ->call('create') ->assertHasNoErrors(); $this->assertDatabaseHas('tiers', [ 'name' => 'Bronze', 'min_spending' => 0, ]); }); it('automatically reorders tier chain on create', function () { TierModel::query()->delete(); // Create first tier manually TierModel::create(['name' => 'Bronze', 'min_spending' => 0]); // Create second tier via Livewire Livewire::actingAs($this->user) ->test(Tier::class) ->set('form.name', 'Silver') ->set('form.min_spending', '10.000') // 10,000 ->call('create') ->assertHasNoErrors(); // First tier should now have max_spending = 9999 $bronze = TierModel::where('name', 'Bronze')->first(); expect($bronze->max_spending)->toBe(9999); // Silver should have null max_spending $silver = TierModel::where('name', 'Silver')->first(); expect($silver->max_spending)->toBeNull(); }); it('can open edit modal and load data', function () { $tier = TierModel::factory()->create([ 'name' => 'Gold', 'min_spending' => 50000, 'max_spending' => null, ]); Livewire::actingAs($this->user) ->test(Tier::class) ->call('openModal', 'update', 'Ubah Tier', $tier->hash_id) ->set('form.tier', $tier) ->set('form.name', 'Gold') ->set('form.min_spending', formatCurrencyNumber(50000)) ->assertSet('method', 'update') ->assertSet('modalTitle', 'Ubah Tier') ->assertSet('form.name', 'Gold') ->assertSet('form.min_spending', formatCurrencyNumber(50000)); }); it('can update a tier', function () { $tier = TierModel::factory()->create(['name' => 'Old Name', 'min_spending' => 0]); Livewire::actingAs($this->user) ->test(Tier::class) ->call('openModal', 'update', 'Ubah Tier', $tier->hash_id) ->set('form.tier', $tier) ->set('form.name', 'New Name') ->set('form.min_spending', '0') ->call('update') ->assertHasNoErrors(); $this->assertDatabaseHas('tiers', [ 'id' => $tier->id, 'name' => 'New Name', ]); }); it('can delete the last tier', function () { TierModel::query()->delete(); $tier1 = TierModel::create(['name' => 'Bronze', 'min_spending' => 0]); $tier2 = TierModel::create(['name' => 'Silver', 'min_spending' => 10000]); TierModel::reorderTierChain(); Livewire::actingAs($this->user) ->test(Tier::class) ->call('delete', $tier2->id); // Deleting highest tier (Silver) $this->assertSoftDeleted('tiers', ['id' => $tier2->id]); // Bronze should now be the last tier with null max_spending $tier1->refresh(); expect($tier1->max_spending)->toBeNull(); }); it('cannot delete a middle tier', function () { TierModel::query()->delete(); $tier1 = TierModel::create(['name' => 'Bronze', 'min_spending' => 0]); $tier2 = TierModel::create(['name' => 'Silver', 'min_spending' => 10000]); $tier3 = TierModel::create(['name' => 'Gold', 'min_spending' => 20000]); TierModel::reorderTierChain(); Livewire::actingAs($this->user) ->test(Tier::class) ->call('delete', $tier2->id); $this->assertDatabaseHas('tiers', ['id' => $tier2->id]); }); it('cannot access tier page without permission', function () { $this->user->roles()->detach(); $this->user->permissions()->detach(); $this->actingAs($this->user) ->get(route('studio.loyalty.tier.index')) ->assertForbidden(); });