store/tests/Feature/Admin/Master/RawMaterialTest.php

741 lines
29 KiB
PHP

<?php
use App\Enums\OwnerVerificationAction;
use App\Enums\OwnerVerificationStatus;
use App\Enums\Permission as PermissionEnum;
use App\Enums\RawMaterialUnit;
use App\Models\OwnerVerificationRequest;
use App\Models\RawMaterial;
use App\Models\RawMaterialPrice;
use App\Models\User;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->seed(RolePermissionSeeder::class);
Storage::fake('public');
});
// ─── Helper ───────────────────────────────────────────────
function createRawMaterialUserWithPermission(PermissionEnum ...$permissions): User
{
$user = User::factory()->create();
$user->givePermissionTo(
array_merge(
[PermissionEnum::DASHBOARD_VIEW->value],
array_map(fn (PermissionEnum $p) => $p->value, $permissions)
)
);
$user->forgetCachedPermissions();
return $user;
}
function createRawMaterialWithPrices(): RawMaterial
{
$rawMaterial = RawMaterial::factory()->create();
$prices = RawMaterialPrice::factory()->count(2)->create(['raw_material_id' => $rawMaterial->id]);
foreach ($prices as $price) {
$price->addMedia(UploadedFile::fake()->image("{$price->variant}.jpg", 100, 100))
->toMediaCollection('images');
}
return $rawMaterial;
}
function priceWithImage(string $variant = 'Default', int $price = 50000, float $stock = 10): array
{
return [
'variant' => $variant,
'price' => $price,
'stock' => $stock,
'images' => [UploadedFile::fake()->image("{$variant}.jpg", 100, 100)],
];
}
function createRawMaterialVerifierUser(): User
{
$user = User::factory()->create();
$user->givePermissionTo([
PermissionEnum::DASHBOARD_VIEW->value,
PermissionEnum::OWNER_VERIFICATIONS_VIEW->value,
PermissionEnum::OWNER_VERIFICATIONS_VERIFY->value,
PermissionEnum::OWNER_VERIFICATIONS_REJECT->value,
]);
$user->forgetCachedPermissions();
return $user;
}
function approveLatestOwnerVerificationRequest(User $verifier): OwnerVerificationRequest
{
$verificationRequest = OwnerVerificationRequest::query()->pending()->latest()->firstOrFail();
test()->actingAs($verifier)
->post(route('admin.manage.owner_verifications.approve_request', $verificationRequest))
->assertRedirect();
return $verificationRequest->fresh();
}
// ─── Index ────────────────────────────────────────────────
describe('Raw Material Index', function () {
test('authenticated user with permission can view raw material index', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
createRawMaterialWithPrices();
$this->actingAs($user)
->get(route('admin.master.raw_materials.index'))
->assertOk();
});
test('guest is redirected to login', function () {
$this->get(route('admin.master.raw_materials.index'))
->assertRedirect(route('login'));
});
test('user without permission is forbidden', function () {
$user = User::factory()->create();
$this->actingAs($user)
->get(route('admin.master.raw_materials.index'))
->assertForbidden();
});
test('index displays raw materials with prices', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
createRawMaterialWithPrices();
createRawMaterialWithPrices();
$this->actingAs($user)
->get(route('admin.master.raw_materials.index'))
->assertOk();
});
test('index can search raw materials by name', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$rawMaterial = RawMaterial::factory()->create(['name' => 'Kain Batik']);
RawMaterialPrice::factory()->create(['raw_material_id' => $rawMaterial->id]);
$this->actingAs($user)
->get(route('admin.master.raw_materials.index', ['search' => 'Kain']))
->assertOk();
});
test('index can filter by active status', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
createRawMaterialWithPrices();
$this->actingAs($user)
->get(route('admin.master.raw_materials.index', ['is_active' => '1']))
->assertOk();
});
});
// ─── Create ───────────────────────────────────────────────
describe('Raw Material Create', function () {
test('authenticated user with permission can view create form', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->get(route('admin.master.raw_materials.create'))
->assertOk();
});
test('guest is redirected to login', function () {
$this->get(route('admin.master.raw_materials.create'))
->assertRedirect(route('login'));
});
test('user without create permission is forbidden', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$this->actingAs($user)
->get(route('admin.master.raw_materials.create'))
->assertForbidden();
});
});
// ─── Store ────────────────────────────────────────────────
describe('Raw Material Store', function () {
test('authenticated user with permission can submit raw material creation request', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [
priceWithImage('Merah', 75000, 50),
],
])
->assertRedirect(route('admin.master.raw_materials.index'));
$this->assertDatabaseHas('raw_materials', [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'is_active' => false,
]);
$this->assertDatabaseHas('owner_verification_requests', [
'subject_type' => RawMaterial::class,
'action' => OwnerVerificationAction::CREATE->value,
'status' => OwnerVerificationStatus::PENDING->value,
]);
});
test('guest cannot create a raw material', function () {
$this->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [priceWithImage()],
])->assertRedirect(route('login'));
});
test('user without create permission is forbidden', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [priceWithImage()],
])
->assertForbidden();
});
test('name is required', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => '',
'unit' => RawMaterialUnit::METER->value,
'prices' => [priceWithImage()],
])
->assertSessionHasErrors('name');
});
test('name must not exceed 200 characters', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => str_repeat('a', 201),
'unit' => RawMaterialUnit::METER->value,
'prices' => [priceWithImage()],
])
->assertSessionHasErrors('name');
});
test('unit is required', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => '',
'prices' => [priceWithImage()],
])
->assertSessionHasErrors('unit');
});
test('unit must be a valid enum value', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => 'invalid_unit',
'prices' => [priceWithImage()],
])
->assertSessionHasErrors('unit');
});
test('prices is required', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [],
])
->assertSessionHasErrors('prices');
});
test('price variant is required', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [['variant' => '', 'price' => 50000, 'stock' => 10, 'images' => [UploadedFile::fake()->image('test.jpg')]]],
])
->assertSessionHasErrors('prices.0.variant');
});
test('price amount is required and must be greater than 0', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [priceWithImage('Merah', 0, 10)],
])
->assertSessionHasErrors('prices.0.price');
});
test('stock is required', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [['variant' => 'Merah', 'price' => 50000, 'stock' => '', 'images' => [UploadedFile::fake()->image('test.jpg')]]],
])
->assertSessionHasErrors('prices.0.stock');
});
test('stock must be non-negative', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Sutra',
'unit' => RawMaterialUnit::METER->value,
'prices' => [priceWithImage('Merah', 50000, -5)],
])
->assertSessionHasErrors('prices.0.stock');
});
test('creating raw material also creates prices', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_CREATE);
$this->actingAs($user)
->post(route('admin.master.raw_materials.store'), [
'name' => 'Kain Premium',
'unit' => RawMaterialUnit::YARD->value,
'prices' => [
priceWithImage('Merah', 75000, 50),
priceWithImage('Biru', 80000, 30),
],
]);
$rawMaterial = RawMaterial::where('name', 'Kain Premium')->first();
expect($rawMaterial)->not->toBeNull();
expect($rawMaterial->prices)->toHaveCount(2);
});
});
// ─── Edit ─────────────────────────────────────────────────
describe('Raw Material Edit', function () {
test('authenticated user with permission can view edit form', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_UPDATE);
$rawMaterial = createRawMaterialWithPrices();
$this->actingAs($user)
->get(route('admin.master.raw_materials.edit', $rawMaterial))
->assertOk();
});
test('guest is redirected to login', function () {
$rawMaterial = createRawMaterialWithPrices();
$this->get(route('admin.master.raw_materials.edit', $rawMaterial))
->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$rawMaterial = createRawMaterialWithPrices();
$this->actingAs($user)
->get(route('admin.master.raw_materials.edit', $rawMaterial))
->assertForbidden();
});
});
// ─── Update ───────────────────────────────────────────────
describe('Raw Material Update', function () {
test('authenticated user with permission can submit raw material update request', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_UPDATE);
$rawMaterial = createRawMaterialWithPrices();
$price = $rawMaterial->prices->first();
$this->actingAs($user)
->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => 'Nama Diubah',
'unit' => RawMaterialUnit::KILOGRAM->value,
'prices' => [
['id' => $price->id, 'variant' => 'Putih', 'price' => 90000, 'stock' => 25],
],
])
->assertRedirect(route('admin.master.raw_materials.index'));
$this->assertDatabaseHas('owner_verification_requests', [
'subject_id' => $rawMaterial->id,
'subject_type' => RawMaterial::class,
'action' => OwnerVerificationAction::UPDATE->value,
'status' => OwnerVerificationStatus::PENDING->value,
]);
expect($rawMaterial->fresh()->name)->not->toBe('Nama Diubah');
expect($price->fresh()->variant)->not->toBe('Putih');
});
test('approving update request applies raw material changes', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_UPDATE);
$verifier = createRawMaterialVerifierUser();
$rawMaterial = createRawMaterialWithPrices();
$price = $rawMaterial->prices->first();
$this->actingAs($user)
->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => 'Nama Diubah',
'unit' => RawMaterialUnit::KILOGRAM->value,
'prices' => [
['id' => $price->id, 'variant' => 'Putih', 'price' => 90000, 'stock' => 25],
],
]);
approveLatestOwnerVerificationRequest($verifier);
expect($rawMaterial->fresh()->name)->toBe('Nama Diubah');
expect($price->fresh()->variant)->toBe('Putih');
});
test('guest cannot update a raw material', function () {
$rawMaterial = createRawMaterialWithPrices();
$price = $rawMaterial->prices->first();
$this->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => 'Nama Baru',
'unit' => $rawMaterial->unit->value,
'prices' => [['id' => $price->id, 'variant' => $price->variant, 'price' => $price->price, 'stock' => $price->stock]],
])->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$rawMaterial = createRawMaterialWithPrices();
$price = $rawMaterial->prices->first();
$this->actingAs($user)
->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => 'Nama Baru',
'unit' => $rawMaterial->unit->value,
'prices' => [['id' => $price->id, 'variant' => $price->variant, 'price' => $price->price, 'stock' => $price->stock]],
])
->assertForbidden();
});
test('name is required on update', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_UPDATE);
$rawMaterial = createRawMaterialWithPrices();
$price = $rawMaterial->prices->first();
$this->actingAs($user)
->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => '',
'unit' => $rawMaterial->unit->value,
'prices' => [
['id' => $price->id, 'variant' => $price->variant, 'price' => $price->price, 'stock' => $price->stock],
],
])
->assertSessionHasErrors('name');
});
test('prices is required on update', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_UPDATE);
$rawMaterial = createRawMaterialWithPrices();
$this->actingAs($user)
->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => 'Nama Bahan',
'unit' => $rawMaterial->unit->value,
'prices' => [],
])
->assertSessionHasErrors('prices');
});
test('unsubmitted prices are removed after approving update request', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_UPDATE);
$verifier = createRawMaterialVerifierUser();
$rawMaterial = createRawMaterialWithPrices();
$priceToKeep = $rawMaterial->prices->first();
$this->actingAs($user)
->put(route('admin.master.raw_materials.update', $rawMaterial), [
'name' => 'Updated Material',
'unit' => $rawMaterial->unit->value,
'prices' => [
['id' => $priceToKeep->id, 'variant' => 'Kept', 'price' => 60000, 'stock' => 15],
],
]);
approveLatestOwnerVerificationRequest($verifier);
$rawMaterial->refresh();
expect($rawMaterial->prices)->toHaveCount(1);
expect($rawMaterial->prices->first()->variant)->toBe('Kept');
});
});
// ─── Toggle Status ────────────────────────────────────────
describe('Raw Material Toggle Status', function () {
test('authenticated user with permission can submit toggle status request', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_TOGGLE_STATUS);
$rawMaterial = RawMaterial::factory()->create();
$this->actingAs($user)
->patch(route('admin.master.raw_materials.toggle_status', $rawMaterial), [
'is_active' => false,
])
->assertRedirect();
$this->assertDatabaseHas('owner_verification_requests', [
'subject_id' => $rawMaterial->id,
'subject_type' => RawMaterial::class,
'action' => OwnerVerificationAction::TOGGLE_STATUS->value,
'status' => OwnerVerificationStatus::PENDING->value,
]);
expect($rawMaterial->fresh()->is_active)->toBeTrue();
});
test('raw material index exposes display is active for pending toggle status request', function () {
$user = createRawMaterialUserWithPermission(
PermissionEnum::RAW_MATERIALS_VIEW,
PermissionEnum::RAW_MATERIALS_TOGGLE_STATUS,
);
$rawMaterial = RawMaterial::factory()->create(['is_active' => true]);
$this->actingAs($user)
->patch(route('admin.master.raw_materials.toggle_status', $rawMaterial), [
'is_active' => false,
])
->assertRedirect();
$response = $this->actingAs($user)
->get(route('admin.master.raw_materials.index'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->where('rawMaterials.data.0.id', $rawMaterial->id)
->where('rawMaterials.data.0.is_active', true)
->where('rawMaterials.data.0.display_is_active', false)
->where('rawMaterials.data.0.has_pending_request', true)
->where('rawMaterials.data.0.pending_request_action', OwnerVerificationAction::TOGGLE_STATUS->value)
);
});
test('approving toggle status request updates raw material status', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_TOGGLE_STATUS);
$verifier = createRawMaterialVerifierUser();
$rawMaterial = RawMaterial::factory()->create();
$this->actingAs($user)
->patch(route('admin.master.raw_materials.toggle_status', $rawMaterial), [
'is_active' => false,
]);
approveLatestOwnerVerificationRequest($verifier);
expect($rawMaterial->fresh()->is_active)->toBeFalse();
});
test('guest cannot toggle raw material status', function () {
$rawMaterial = RawMaterial::factory()->create();
$this->patch(route('admin.master.raw_materials.toggle_status', $rawMaterial), [
'is_active' => false,
])->assertRedirect(route('login'));
});
test('user without toggle permission is forbidden', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$rawMaterial = RawMaterial::factory()->create();
$this->actingAs($user)
->patch(route('admin.master.raw_materials.toggle_status', $rawMaterial), [
'is_active' => false,
])
->assertForbidden();
});
test('is_active field is required', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_TOGGLE_STATUS);
$rawMaterial = RawMaterial::factory()->create();
$this->actingAs($user)
->patch(route('admin.master.raw_materials.toggle_status', $rawMaterial), [
'is_active' => null,
])
->assertSessionHasErrors('is_active');
});
});
// ─── Destroy ──────────────────────────────────────────────
describe('Raw Material Destroy', function () {
test('authenticated user with permission can submit delete request', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_DELETE);
$rawMaterial = createRawMaterialWithPrices();
$this->actingAs($user)
->delete(route('admin.master.raw_materials.destroy', $rawMaterial))
->assertRedirect(route('admin.master.raw_materials.index'));
$this->assertDatabaseHas('owner_verification_requests', [
'subject_id' => $rawMaterial->id,
'subject_type' => RawMaterial::class,
'action' => OwnerVerificationAction::DELETE->value,
'status' => OwnerVerificationStatus::PENDING->value,
]);
$this->assertNotSoftDeleted('raw_materials', ['id' => $rawMaterial->id]);
});
test('approving delete request soft deletes raw material and prices', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_DELETE);
$verifier = createRawMaterialVerifierUser();
$rawMaterial = createRawMaterialWithPrices();
$priceIds = $rawMaterial->prices->pluck('id')->toArray();
$this->actingAs($user)
->delete(route('admin.master.raw_materials.destroy', $rawMaterial));
approveLatestOwnerVerificationRequest($verifier);
$this->assertSoftDeleted('raw_materials', ['id' => $rawMaterial->id]);
foreach ($priceIds as $priceId) {
$this->assertSoftDeleted('raw_material_prices', ['id' => $priceId]);
}
});
test('guest cannot delete a raw material', function () {
$rawMaterial = createRawMaterialWithPrices();
$this->delete(route('admin.master.raw_materials.destroy', $rawMaterial))
->assertRedirect(route('login'));
$this->assertNotSoftDeleted('raw_materials', ['id' => $rawMaterial->id]);
});
test('user without delete permission is forbidden', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW);
$rawMaterial = createRawMaterialWithPrices();
$this->actingAs($user)
->delete(route('admin.master.raw_materials.destroy', $rawMaterial))
->assertForbidden();
$this->assertNotSoftDeleted('raw_materials', ['id' => $rawMaterial->id]);
});
test('deleting raw material is not applied until owner approves', function () {
$user = createRawMaterialUserWithPermission(PermissionEnum::RAW_MATERIALS_VIEW, PermissionEnum::RAW_MATERIALS_DELETE);
$rawMaterial = createRawMaterialWithPrices();
$priceIds = $rawMaterial->prices->pluck('id')->toArray();
$this->actingAs($user)
->delete(route('admin.master.raw_materials.destroy', $rawMaterial));
$this->assertNotSoftDeleted('raw_materials', ['id' => $rawMaterial->id]);
foreach ($priceIds as $priceId) {
$this->assertNotSoftDeleted('raw_material_prices', ['id' => $priceId]);
}
});
});
// ─── Raw Material Model ───────────────────────────────────
describe('Raw Material Model', function () {
test('raw material uses soft deletes', function () {
$rawMaterial = RawMaterial::factory()->create();
$rawMaterial->delete();
expect($rawMaterial->trashed())->toBeTrue();
});
test('raw material can have prices', function () {
$rawMaterial = RawMaterial::factory()->create();
RawMaterialPrice::factory()->count(3)->create(['raw_material_id' => $rawMaterial->id]);
expect($rawMaterial->fresh()->prices)->toHaveCount(3);
});
test('raw material has is_active cast to boolean', function () {
$rawMaterial = RawMaterial::factory()->create(['is_active' => true]);
expect($rawMaterial->is_active)->toBeTrue();
$rawMaterial->update(['is_active' => false]);
expect($rawMaterial->fresh()->is_active)->toBeFalse();
});
test('raw material has unit cast to enum', function () {
$rawMaterial = RawMaterial::factory()->create(['unit' => RawMaterialUnit::YARD->value]);
expect($rawMaterial->unit)->toBe(RawMaterialUnit::YARD);
});
test('raw material has unit label accessor', function () {
$rawMaterial = RawMaterial::factory()->create(['unit' => RawMaterialUnit::METER->value]);
expect($rawMaterial->unit_label)->toBe('Meter');
});
test('raw material has unit abbreviation accessor', function () {
$rawMaterial = RawMaterial::factory()->create(['unit' => RawMaterialUnit::KILOGRAM->value]);
expect($rawMaterial->unit_abbreviation)->toBe('kg');
});
});