test: Add comprehensive feature tests for purchase management, including item cart operations, purchase creation, stock updates, and permission checks.
This commit is contained in:
parent
7873701015
commit
99c83e08f8
285
tests/Feature/Studio/Manage/PurchaseTest.php
Normal file
285
tests/Feature/Studio/Manage/PurchaseTest.php
Normal file
@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\Studio\Manage\Purchase\Create;
|
||||
use App\Livewire\Studio\Manage\Purchase\Index;
|
||||
use App\Models\Bottle;
|
||||
use App\Models\Perfume;
|
||||
use App\Models\Product;
|
||||
use App\Models\Purchase;
|
||||
use App\Models\PurchaseItem;
|
||||
use App\Models\Warehouse;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
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 purchase']);
|
||||
Permission::firstOrCreate(['name' => 'create purchase']);
|
||||
Permission::firstOrCreate(['name' => 'delete purchase']);
|
||||
$role->givePermissionTo(['view purchase', 'create purchase', 'delete purchase']);
|
||||
$this->user->assignRole($role);
|
||||
|
||||
$this->warehouse = Warehouse::factory()->create();
|
||||
});
|
||||
|
||||
it('renders the purchase index page', function () {
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.manage.purchase.index'))
|
||||
->assertOk()
|
||||
->assertSeeLivewire(Index::class);
|
||||
});
|
||||
|
||||
it('renders the purchase create page', function () {
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.manage.purchase.create'))
|
||||
->assertOk()
|
||||
->assertSeeLivewire(Create::class);
|
||||
});
|
||||
|
||||
it('can add a perfume to the cart', function () {
|
||||
$perfume = Perfume::factory()->create(['cost_price' => 50000]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.perfume_id', $perfume->id)
|
||||
->set('form.quantity_perfume', '10')
|
||||
->call('addItem', 'parfum')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('purchase_items', [
|
||||
'user_id' => $this->user->id,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
'quantity' => 10,
|
||||
'unit_price' => 50000,
|
||||
'purchase_id' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can add a product to the cart', function () {
|
||||
$product = Product::factory()->create(['cost_price' => 30000]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.product_id', $product->id)
|
||||
->set('form.quantity_product', '5')
|
||||
->call('addItem', 'produk')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('purchase_items', [
|
||||
'user_id' => $this->user->id,
|
||||
'purchasable_type' => Product::class,
|
||||
'purchasable_id' => $product->id,
|
||||
'quantity' => 5,
|
||||
'unit_price' => 30000,
|
||||
'purchase_id' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can add a bottle to the cart', function () {
|
||||
$bottle = Bottle::factory()->create(['cost_price' => 5000]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.bottle_id', $bottle->id)
|
||||
->set('form.quantity_bottle', '100')
|
||||
->call('addItem', 'botol')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('purchase_items', [
|
||||
'user_id' => $this->user->id,
|
||||
'purchasable_type' => Bottle::class,
|
||||
'purchasable_id' => $bottle->id,
|
||||
'quantity' => 100,
|
||||
'unit_price' => 5000,
|
||||
'purchase_id' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can update item quantity in the cart', function () {
|
||||
$perfume = Perfume::factory()->create(['cost_price' => 50000]);
|
||||
$item = PurchaseItem::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'purchase_id' => null,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
'quantity' => 10,
|
||||
'unit_price' => 50000,
|
||||
'total_price' => 500000,
|
||||
]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.item_id', $item->id)
|
||||
->set('form.quantity_edit', '15')
|
||||
->call('updateItem')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertDatabaseHas('purchase_items', [
|
||||
'id' => $item->id,
|
||||
'quantity' => 15,
|
||||
'total_price' => 750000,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can delete an item from the cart', function () {
|
||||
$perfume = Perfume::factory()->create();
|
||||
$item = PurchaseItem::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'purchase_id' => null,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->call('deleteItem', $item->id)
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertSoftDeleted('purchase_items', ['id' => $item->id]);
|
||||
});
|
||||
|
||||
it('can store a purchase and update warehouse stock', function () {
|
||||
$perfume = Perfume::factory()->create(['cost_price' => 100000]);
|
||||
PurchaseItem::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'purchase_id' => null,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
'quantity' => 10,
|
||||
'unit_price' => 100000,
|
||||
'total_price' => 1000000,
|
||||
]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.warehouse_id', $this->warehouse->id)
|
||||
->set('form.purchase_date', now()->format('Y-m-d'))
|
||||
->set('form.invoice_number', 'INV-001')
|
||||
->call('save')
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect(route('studio.manage.purchase.index', [
|
||||
'notification' => 'Belanja berhasil ditambahkan.',
|
||||
]));
|
||||
|
||||
$this->assertDatabaseHas('purchases', [
|
||||
'warehouse_id' => $this->warehouse->id,
|
||||
'invoice_number' => 'INV-001',
|
||||
'total' => 1000000,
|
||||
]);
|
||||
|
||||
// Check stock update
|
||||
$this->assertDatabaseHas('perfume_warehouse', [
|
||||
'warehouse_id' => $this->warehouse->id,
|
||||
'perfume_id' => $perfume->id,
|
||||
'stock' => 10,
|
||||
]);
|
||||
});
|
||||
|
||||
it('can store a purchase with image', function () {
|
||||
$perfume = Perfume::factory()->create(['cost_price' => 100000]);
|
||||
PurchaseItem::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'purchase_id' => null,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
'quantity' => 10,
|
||||
'unit_price' => 100000,
|
||||
'total_price' => 1000000,
|
||||
]);
|
||||
|
||||
Storage::fake('public');
|
||||
$image = \Illuminate\Http\UploadedFile::fake()->image('invoice.jpg');
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.warehouse_id', $this->warehouse->id)
|
||||
->set('form.purchase_date', now()->format('Y-m-d'))
|
||||
->set('form.image', [[
|
||||
'name' => 'invoice.jpg',
|
||||
'path' => Storage::disk('public')->path($image->store('tmp', 'public')),
|
||||
'size' => $image->getSize(),
|
||||
'type' => $image->getMimeType(),
|
||||
]])
|
||||
->call('save')
|
||||
->assertHasNoErrors();
|
||||
|
||||
$purchase = Purchase::latest()->first();
|
||||
expect($purchase->getFirstMediaUrl('image'))->not->toBeEmpty();
|
||||
});
|
||||
|
||||
it('cannot store a purchase with empty cart', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.warehouse_id', $this->warehouse->id)
|
||||
->set('form.purchase_date', now()->format('Y-m-d'))
|
||||
->call('save')
|
||||
->assertHasNoErrors(); // It shows a toast, doesn't redirect
|
||||
|
||||
$this->assertDatabaseCount('purchases', 0);
|
||||
});
|
||||
|
||||
it('validates required fields', function () {
|
||||
$perfume = Perfume::factory()->create();
|
||||
PurchaseItem::factory()->create([
|
||||
'user_id' => $this->user->id,
|
||||
'purchase_id' => null,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->call('save')
|
||||
->assertHasErrors([
|
||||
'form.warehouse_id' => 'required',
|
||||
'form.purchase_date' => 'required',
|
||||
]);
|
||||
});
|
||||
|
||||
it('can delete a purchase', function () {
|
||||
$perfume = Perfume::factory()->create();
|
||||
$purchase = Purchase::factory()->create([
|
||||
'warehouse_id' => $this->warehouse->id,
|
||||
]);
|
||||
$item = PurchaseItem::factory()->create([
|
||||
'purchase_id' => $purchase->id,
|
||||
'purchasable_type' => Perfume::class,
|
||||
'purchasable_id' => $perfume->id,
|
||||
'quantity' => 10,
|
||||
]);
|
||||
|
||||
// Initial stock (assuming it was added when purchase was created)
|
||||
$this->warehouse->perfumes()->attach($perfume->id, ['stock' => 10]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Index::class)
|
||||
->call('delete', $purchase->id)
|
||||
->assertHasNoErrors();
|
||||
|
||||
$this->assertSoftDeleted('purchases', ['id' => $purchase->id]);
|
||||
|
||||
// Check stock was decreased
|
||||
$this->assertDatabaseMissing('perfume_warehouse', [
|
||||
'warehouse_id' => $this->warehouse->id,
|
||||
'perfume_id' => $perfume->id,
|
||||
'stock' => 10,
|
||||
]);
|
||||
});
|
||||
|
||||
it('cannot access purchase without permission', function () {
|
||||
$this->user->roles()->detach();
|
||||
$this->user->permissions()->detach();
|
||||
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.manage.purchase.index'))
|
||||
->assertForbidden();
|
||||
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.manage.purchase.create'))
|
||||
->assertForbidden();
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user