feat: Add feature tests for Studio Finance Expense management.

This commit is contained in:
Yoga Pangestu 2026-01-02 19:43:52 +07:00
parent 32eef4acfe
commit 967a1633ec

View File

@ -0,0 +1,166 @@
<?php
use App\Enums\ExpenseType;
use App\Livewire\Studio\Finance\Expense;
use App\Models\Expense as ExpenseModel;
use App\Models\Outlet;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
beforeEach(function () {
$this->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();
});