setupUser(); $role = Role::firstOrCreate(['name' => 'Owner']); Permission::firstOrCreate(['name' => 'view expense']); Permission::firstOrCreate(['name' => 'create expense']); Permission::firstOrCreate(['name' => 'update expense']); Permission::firstOrCreate(['name' => 'delete expense']); $role->givePermissionTo(['view expense', 'create expense', 'update expense', 'delete expense']); $this->user->assignRole($role); }); it('renders the expense page correctly', function () { $this->actingAs($this->user) ->get(route('studio.finance.expense.index')) ->assertOk() ->assertSeeLivewire(Expense::class); }); it('can open create modal', function () { Livewire::actingAs($this->user) ->test(Expense::class) ->call('openModal', 'create', 'Tambah Pengeluaran') ->assertSet('method', 'create') ->assertSet('modalTitle', 'Tambah Pengeluaran'); }); it('shows validation errors on create', function () { Livewire::actingAs($this->user) ->test(Expense::class) ->call('create') ->assertHasErrors([ 'form.description' => 'required', 'form.amount' => 'required', ]); }); it('can store a new expense with single outlet', function () { // User has 1 outlet from setupUser() expect($this->user->outlets()->count())->toBe(1); Livewire::actingAs($this->user) ->test(Expense::class) ->set('form.description', 'Beli Sabun') ->set('form.amount', '15000') ->call('create') ->assertHasNoErrors() ->assertDispatched('refreshDatatable'); $this->assertDatabaseHas('expenses', [ 'description' => 'Beli Sabun', 'amount' => 15000, 'outlet_id' => $this->outlet->id, 'user_id' => $this->user->id, 'type' => ExpenseType::OPERATIONAL->value, ]); }); it('requires outlet_id if user has multiple outlets', function () { $anotherOutlet = Outlet::factory()->create(); $this->user->outlets()->attach($anotherOutlet); Livewire::actingAs($this->user) ->test(Expense::class) ->set('form.description', 'Beli Tissue') ->set('form.amount', '10000') // form.outlet_id is empty ->call('create') ->assertHasErrors(['form.outlet_id' => 'required']); }); it('can store a new expense with multiple outlets', function () { $anotherOutlet = Outlet::factory()->create(); $this->user->outlets()->attach($anotherOutlet); Livewire::actingAs($this->user) ->test(Expense::class) ->set('form.description', 'Beli Tissue') ->set('form.amount', '10000') ->set('form.outlet_id', $anotherOutlet->id) ->call('create') ->assertHasNoErrors() ->assertDispatched('refreshDatatable'); $this->assertDatabaseHas('expenses', [ 'description' => 'Beli Tissue', 'amount' => 10000, 'outlet_id' => $anotherOutlet->id, ]); }); it('can open edit modal and load data', function () { $expense = ExpenseModel::factory()->operational()->create([ 'description' => 'Old Description', 'amount' => 50000, 'outlet_id' => $this->outlet->id, 'user_id' => $this->user->id, ]); Livewire::actingAs($this->user) ->test(Expense::class) ->call('openModal', 'update', 'Ubah Pengeluaran', $expense->hash_id) ->set('form.expense', $expense) ->set('form.description', 'Old Description') ->set('form.amount', '50.000') ->assertSet('method', 'update') ->assertSet('form.description', 'Old Description') ->assertSet('form.amount', '50.000'); }); it('can update an expense', function () { $expense = ExpenseModel::factory()->operational()->create([ 'outlet_id' => $this->outlet->id, 'user_id' => $this->user->id, ]); Livewire::actingAs($this->user) ->test(Expense::class) ->call('openModal', 'update', 'Ubah Pengeluaran', $expense->hash_id) ->set('form.expense', $expense) ->set('form.description', 'Updated Description') ->set('form.amount', '75000') ->call('update') ->assertHasNoErrors() ->assertDispatched('refreshDatatable'); $this->assertDatabaseHas('expenses', [ 'id' => $expense->id, 'description' => 'Updated Description', 'amount' => 75000, ]); }); it('can delete an expense', function () { $expense = ExpenseModel::factory()->operational()->create([ 'outlet_id' => $this->outlet->id, 'user_id' => $this->user->id, ]); Livewire::actingAs($this->user) ->test(Expense::class) ->call('delete', $expense->id) ->assertHasNoErrors() ->assertDispatched('refreshDatatable'); $this->assertSoftDeleted('expenses', ['id' => $expense->id]); }); it('cannot access expense page without permission', function () { $this->user->roles()->detach(); $this->user->permissions()->detach(); $this->actingAs($this->user) ->get(route('studio.finance.expense.index')) ->assertForbidden(); });