assertRedirect(route('login')); }); it('returns 403 when user has no permission to view expenses', function () { actingAs(createUnauthorizedUser()) ->get(route('expense.index')) ->assertStatus(403); }); }); describe('Expense Module - Authorized Actions', function () { beforeEach(function () { $user = createAuthorizedUser([ 'View:Expense', 'Create:Expense', 'Edit:Expense', 'Delete:Expense', 'DeleteAny:Expense', ]); actingAs($user); }); it('can access expense index page', function () { Expense::factory()->create(); get(route('expense.index')) ->assertOk() ->assertInertia(fn ($page) => $page ->component('admin/finance/expense/index') ->has('expenses', fn ($page) => $page ->has('data.0.user') ->etc() ) ); }); it('can store a new expense with proof image', function () { Storage::fake('public'); $data = [ 'name' => 'Beli Alat Tulis', 'amount' => 50000, 'image' => UploadedFile::fake()->image('receipt.jpg'), ]; postJson(route('expense.store'), $data) ->assertRedirect() ->assertSessionHas('success'); assertDatabaseHas('expenses', [ 'name' => 'Beli Alat Tulis', 'amount' => 50000, 'user_id' => auth()->id(), ]); $expense = Expense::where('name', 'Beli Alat Tulis')->first(); expect($expense->getFirstMediaUrl('proof'))->not->toBeEmpty(); }); it('validates expense creation', function () { postJson(route('expense.store'), []) ->assertStatus(422) ->assertJsonValidationErrors(['name', 'amount']); }); it('can update an expense', function () { $expense = Expense::factory()->create(['name' => 'Old Expense', 'amount' => 10000]); $newData = [ 'name' => 'Updated Expense', 'amount' => 20000, ]; patchJson(route('expense.update', $expense), $newData) ->assertRedirect() ->assertSessionHas('success'); assertDatabaseHas('expenses', [ 'id' => $expense->id, 'name' => 'Updated Expense', 'amount' => 20000, ]); }); it('can delete an expense', function () { $expense = Expense::factory()->create(); deleteJson(route('expense.destroy', $expense)) ->assertRedirect() ->assertSessionHas('success'); assertSoftDeleted('expenses', ['id' => $expense->id]); }); it('can delete expenses in bulk', function () { $expenses = Expense::factory()->count(3)->create(); $ids = $expenses->pluck('id')->toArray(); deleteJson(route('expense.bulkDestroy'), ['ids' => $ids]) ->assertRedirect() ->assertSessionHas('success'); foreach ($ids as $id) { assertSoftDeleted('expenses', ['id' => $id]); } }); }); describe('Expense Module - Unauthorized Actions', function () { beforeEach(function () { actingAs(createUnauthorizedUser()); }); it('cannot store an expense without permission', function () { postJson(route('expense.store'), ['name' => 'Unauthorized']) ->assertStatus(403); }); it('cannot update an expense without permission', function () { $expense = Expense::factory()->create(); patchJson(route('expense.update', $expense), ['name' => 'Unauthorized']) ->assertStatus(403); }); it('cannot delete an expense without permission', function () { $expense = Expense::factory()->create(); deleteJson(route('expense.destroy', $expense)) ->assertStatus(403); }); });