From 0c4c30ab6b5e82ceff6ecdd88220a389a3f3211f Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 30 Apr 2026 08:35:36 +0700 Subject: [PATCH] test: add feature tests for purchase management module --- tests/Feature/Admin/Manage/PurchaseTest.php | 258 ++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 tests/Feature/Admin/Manage/PurchaseTest.php diff --git a/tests/Feature/Admin/Manage/PurchaseTest.php b/tests/Feature/Admin/Manage/PurchaseTest.php new file mode 100644 index 0000000..2b695fe --- /dev/null +++ b/tests/Feature/Admin/Manage/PurchaseTest.php @@ -0,0 +1,258 @@ +assertRedirect(route('login')); + }); + + it('returns 403 when user has no permission to view purchases', function () { + actingAs(createUnauthorizedUser()) + ->get(route('purchase.index')) + ->assertStatus(403); + }); +}); + +describe('Purchase Module - Authorized Actions', function () { + beforeEach(function () { + $user = createAuthorizedUser([ + 'View:Purchase', + 'Create:Purchase', + 'Edit:Purchase', + 'Delete:Purchase', + 'DeleteAny:Purchase', + ]); + actingAs($user); + }); + + it('can access purchase index page', function () { + get(route('purchase.index')) + ->assertOk() + ->assertInertia(fn ($page) => $page + ->component('admin/manage/purchase/index') + ->has('purchases') + ); + }); + + it('can access purchase create page', function () { + get(route('purchase.create')) + ->assertOk() + ->assertInertia(fn ($page) => $page + ->component('admin/manage/purchase/create') + ->has('products') + ->has('cartItems') + ); + }); + + it('can manage cart items', function () { + $product = Product::factory()->create(); + + // 1. Add to cart + postJson(route('purchase.addToCart'), [ + 'product_id' => $product->id, + 'quantity' => 5, + 'unit_price' => 5000, + ])->assertRedirect(); + + assertDatabaseHas('purchase_items', [ + 'user_id' => auth()->id(), + 'purchase_id' => null, + 'product_id' => $product->id, + 'quantity' => 5, + ]); + + $cartItem = PurchaseItem::where('product_id', $product->id)->whereNull('purchase_id')->first(); + + // 2. Update cart item + patchJson(route('purchase.updateCartItem', $cartItem), [ + 'product_id' => $product->id, + 'quantity' => 10, + 'unit_price' => 5000, + ])->assertRedirect(); + + expect($cartItem->fresh()->quantity)->toBe(10); + + // 3. Remove from cart + deleteJson(route('purchase.removeFromCart', $cartItem))->assertRedirect(); + assertSoftDeleted('purchase_items', ['id' => $cartItem->id]); + }); + + it('can store a new purchase and increase stock', function () { + $product = Product::factory()->create(['stock' => 10]); + + $data = [ + 'purchase_date' => now()->format('Y-m-d'), + 'note' => 'Test Purchase', + 'items' => [ + [ + 'product_id' => $product->id, + 'quantity' => 20, + 'unit_price' => 5000, + ], + ], + ]; + + postJson(route('purchase.store'), $data) + ->assertRedirect(route('purchase.index')) + ->assertSessionHas('success'); + + assertDatabaseHas('purchases', [ + 'note' => 'Test Purchase', + 'total' => 100000, + ]); + + // Check stock increment (10 + 20 = 30) + expect($product->fresh()->stock)->toBe(30); + + // Check purchase items + assertDatabaseHas('purchase_items', [ + 'product_id' => $product->id, + 'quantity' => 20, + 'unit_price' => 5000, + ]); + }); + + it('validates purchase creation', function () { + postJson(route('purchase.store'), []) + ->assertStatus(422) + ->assertJsonValidationErrors(['purchase_date', 'items']); + }); + + it('can access purchase edit page', function () { + $purchase = Purchase::factory()->create(); + + get(route('purchase.edit', $purchase)) + ->assertOk() + ->assertInertia(fn ($page) => $page + ->component('admin/manage/purchase/edit') + ->has('purchase') + ->has('products') + ); + }); + + it('can update a purchase and adjust stock', function () { + $product1 = Product::factory()->create(['stock' => 10]); + $product2 = Product::factory()->create(['stock' => 10]); + + $purchase = Purchase::create([ + 'purchase_date' => now()->format('Y-m-d'), + 'note' => 'Old Note', + 'total' => 5000, + ]); + + $purchase->items()->create([ + 'user_id' => auth()->id(), + 'product_id' => $product1->id, + 'quantity' => 5, + 'unit_price' => 1000, + 'total_price' => 5000, + ]); + + // Manually adjust stock as if it was stored + $product1->increment('stock', 5); + + $newData = [ + 'purchase_date' => now()->format('Y-m-d'), + 'note' => 'Updated Note', + 'items' => [ + [ + 'product_id' => $product2->id, + 'quantity' => 15, + 'unit_price' => 2000, + ], + ], + ]; + + patchJson(route('purchase.update', $purchase), $newData) + ->assertRedirect(route('purchase.index')) + ->assertSessionHas('success'); + + // Check data updated + assertDatabaseHas('purchases', [ + 'id' => $purchase->id, + 'note' => 'Updated Note', + ]); + + // Check stock: product1 should be decremented back (15 - 5 = 10), product2 should be incremented (10 + 15 = 25) + expect($product1->fresh()->stock)->toBe(10); + expect($product2->fresh()->stock)->toBe(25); + }); + + it('can delete a purchase and decrease stock', function () { + $product = Product::factory()->create(['stock' => 20]); + $purchase = Purchase::factory()->create(); + $purchase->items()->create([ + 'user_id' => auth()->id(), + 'product_id' => $product->id, + 'quantity' => 10, + 'unit_price' => 1000, + 'total_price' => 10000, + ]); + + // Initial stock check + // expect($product->fresh()->stock)->toBe(20); + + deleteJson(route('purchase.destroy', $purchase)) + ->assertRedirect() + ->assertSessionHas('success'); + + assertSoftDeleted('purchases', ['id' => $purchase->id]); + + // Stock should be decreased (20 - 10 = 10) + expect($product->fresh()->stock)->toBe(10); + }); + + it('can delete purchases in bulk', function () { + $purchases = Purchase::factory()->count(3)->create(); + $ids = $purchases->pluck('id')->toArray(); + + deleteJson(route('purchase.bulkDestroy'), ['ids' => $ids]) + ->assertRedirect() + ->assertSessionHas('success'); + + foreach ($ids as $id) { + assertSoftDeleted('purchases', ['id' => $id]); + } + }); +}); + +describe('Purchase Module - Unauthorized Actions', function () { + beforeEach(function () { + actingAs(createUnauthorizedUser()); + }); + + it('cannot store a purchase without permission', function () { + postJson(route('purchase.store'), ['purchase_date' => now()->format('Y-m-d')]) + ->assertStatus(403); + }); + + it('cannot update a purchase without permission', function () { + $purchase = Purchase::factory()->create(); + patchJson(route('purchase.update', $purchase), ['purchase_date' => now()->format('Y-m-d')]) + ->assertStatus(403); + }); + + it('cannot delete a purchase without permission', function () { + $purchase = Purchase::factory()->create(); + deleteJson(route('purchase.destroy', $purchase)) + ->assertStatus(403); + }); +});