b2in/tests/Feature/TeaserProductCreateTest.php
2026-02-20 17:57:50 +01:00

330 lines
11 KiB
PHP

<?php
declare(strict_types=1);
use App\Enums\PriceType;
use App\Enums\ProductStatus;
use App\Enums\ProductType;
use App\Models\Category;
use App\Models\Hub;
use App\Models\Partner;
use App\Models\Product;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Spatie\Permission\Models\Role;
beforeEach(function () {
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
Role::create(['name' => 'Retailer']);
Role::create(['name' => 'Manufacturer']);
Role::create(['name' => 'Customer']);
});
function makeRetailerWithHub(): array
{
$hub = Hub::factory()->create();
$partner = Partner::factory()->setupCompleted()->create(['hub_id' => $hub->id]);
$user = User::factory()->create(['partner_id' => $partner->id]);
$user->assignRole('Retailer');
return [$user, $partner, $hub];
}
test('retailer can access teaser product creation page', function () {
[$user] = makeRetailerWithHub();
$this->actingAs($user)
->get(route('products.create.teaser'))
->assertSuccessful();
});
test('manufacturer can access teaser product creation page', function () {
$hub = Hub::factory()->create();
$partner = Partner::factory()->setupCompleted()->create(['hub_id' => $hub->id]);
$user = User::factory()->create(['partner_id' => $partner->id]);
$user->assignRole('Manufacturer');
$this->actingAs($user)
->get(route('products.create.teaser'))
->assertSuccessful();
});
test('customer cannot access teaser product creation page', function () {
$customer = User::factory()->create();
$customer->assignRole('Customer');
$this->actingAs($customer)
->get(route('products.create.teaser'))
->assertForbidden();
});
test('retailer can create teaser product with from_price', function () {
Storage::fake('public');
[$user, $partner, $hub] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Sideboard Eiche')
->set('descriptionShort', 'Schönes Massivholz-Sideboard aus regionaler Fertigung.')
->set('priceType', 'from_price')
->set('priceDisplayText', 'Ab 1.800 €')
->set('categoryId', $category->id)
->set('status', 'active')
->set('mainImages', [UploadedFile::fake()->image('product.jpg', 800, 600)])
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Sideboard Eiche')->first();
expect($product)->not->toBeNull();
expect($product->product_type)->toBe(ProductType::LocalStock);
expect($product->price_type)->toBe(PriceType::FromPrice);
expect($product->price_display_text)->toBe('Ab 1.800 €');
expect($product->partner_id)->toBe($partner->id);
expect($product->hub_id)->toBe($hub->id);
expect($product->is_curated)->toBeFalse();
});
test('retailer can create teaser product with on_request price', function () {
Storage::fake('public');
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Küche Massivholz')
->set('descriptionShort', 'Individuelle Küche auf Maß.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->set('status', 'draft')
->set('mainImages', [UploadedFile::fake()->image('kitchen.jpg', 800, 600)])
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Küche Massivholz')->first();
expect($product->price_type)->toBe(PriceType::OnRequest);
});
test('teaser product rejects fixed price type', function () {
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Produkt mit Festpreis')
->set('descriptionShort', 'Beschreibung.')
->set('priceType', 'fixed')
->set('categoryId', $category->id)
->set('status', 'active')
->call('save')
->assertHasErrors(['priceType']);
});
test('teaser product requires price display text when from_price', function () {
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Produkt')
->set('descriptionShort', 'Beschreibung.')
->set('priceType', 'from_price')
->set('priceDisplayText', '')
->set('categoryId', $category->id)
->set('status', 'active')
->call('save')
->assertHasErrors(['priceDisplayText']);
});
test('teaser product requires name', function () {
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', '')
->set('descriptionShort', 'Beschreibung.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->call('save')
->assertHasErrors(['name' => 'required']);
});
test('teaser product description short max 180 characters', function () {
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Test')
->set('descriptionShort', str_repeat('x', 181))
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->call('save')
->assertHasErrors(['descriptionShort' => 'max']);
});
test('teaser product requires category', function () {
[$user] = makeRetailerWithHub();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Test Produkt')
->set('descriptionShort', 'Beschreibung.')
->set('priceType', 'on_request')
->set('categoryId', null)
->call('save')
->assertHasErrors(['categoryId' => 'required']);
});
test('manufacturer can create teaser product', function () {
Storage::fake('public');
$hub = Hub::factory()->create();
$partner = Partner::factory()->setupCompleted()->create(['hub_id' => $hub->id]);
$user = User::factory()->create(['partner_id' => $partner->id]);
$user->assignRole('Manufacturer');
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Hersteller Teaser-Produkt')
->set('descriptionShort', 'Ein Teaser-Produkt vom Hersteller.')
->set('priceType', 'from_price')
->set('priceDisplayText', 'Ab 3.200 €')
->set('categoryId', $category->id)
->set('status', 'active')
->set('mainImages', [UploadedFile::fake()->image('product.jpg', 800, 600)])
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Hersteller Teaser-Produkt')->first();
expect($product)->not->toBeNull();
expect($product->product_type)->toBe(ProductType::LocalStock);
expect($product->partner_id)->toBe($partner->id);
expect($product->hub_id)->toBe($hub->id);
});
test('created teaser product is automatically not curated', function () {
Storage::fake('public');
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Nicht kuratiertes Produkt')
->set('descriptionShort', 'Test.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->set('status', 'active')
->set('mainImages', [UploadedFile::fake()->image('test.jpg', 800, 600)])
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Nicht kuratiertes Produkt')->first();
expect($product->is_curated)->toBeFalse();
expect($product->product_type)->toBe(ProductType::LocalStock);
});
test('submitting teaser product as active sets status to pending', function () {
Storage::fake('public');
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Pending Teaser')
->set('descriptionShort', 'Test zur Freigabe.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->set('status', 'active')
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Pending Teaser')->first();
expect($product->status)->toBe(ProductStatus::Pending);
});
test('saving teaser product as draft keeps status as draft', function () {
Storage::fake('public');
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Draft Teaser')
->set('descriptionShort', 'Test Entwurf.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->set('status', 'draft')
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Draft Teaser')->first();
expect($product->status)->toBe(ProductStatus::Draft);
});
test('teaser product generates b2in article number on create', function () {
Storage::fake('public');
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Teaser mit Nummer')
->set('descriptionShort', 'Test Artikelnummer.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->set('status', 'active')
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Teaser mit Nummer')->first();
expect($product->b2in_article_number)->toStartWith('B2IN-');
expect($product->b2in_article_number)->toBe('B2IN-000001');
});
test('teaser product saves partner product number', function () {
Storage::fake('public');
[$user] = makeRetailerWithHub();
$category = Category::factory()->create();
$this->actingAs($user);
Livewire\Volt\Volt::test('products.form-teaser')
->set('name', 'Teaser mit Partnernummer')
->set('descriptionShort', 'Test Partnernummer.')
->set('priceType', 'on_request')
->set('categoryId', $category->id)
->set('partnerProductNumber', 'MY-CUSTOM-001')
->set('status', 'active')
->call('save')
->assertHasNoErrors();
$product = Product::where('name', 'Teaser mit Partnernummer')->first();
expect($product->partner_product_number)->toBe('MY-CUSTOM-001');
});
test('teaser product auto-generates partner product number on mount', function () {
[$user, $partner] = makeRetailerWithHub();
$this->actingAs($user);
$expectedNumber = sprintf('P%03d-%04d', $partner->id, 1);
Livewire\Volt\Volt::test('products.form-teaser')
->assertSet('partnerProductNumber', $expectedNumber);
});