createTenant(); $attribute = Attribute::query()->create([ 'tenant_codigo' => $tenant->codigo, 'codigo' => 'size', 'nombre' => 'Size', 'type' => FieldType::String, ]); $image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; $response = $this->postJson("/api/tenants/{$tenant->codigo}/catalog-items", [ 'slug' => 'shirt', 'nombre' => 'Shirt', 'precio' => 100, 'minimum_use_date' => '2026-08-01 09:00:00', 'maximum_use_date' => '2026-08-31 18:00:00', 'attribute_codes' => [$attribute->codigo], 'images' => [$image, $image], 'variants' => [ [ 'real_stock' => 5, 'maximum_use_date' => '2026-08-15 18:00:00', 'values' => ['size' => 'M'], 'images' => [$image], ], ], ]); $response ->assertCreated() ->assertJsonPath('data.nombre', 'Shirt') ->assertJsonCount(2, 'data.images') ->assertJsonCount(1, 'data.variants') ->assertJsonCount(1, 'data.variants.0.images') ->assertJsonPath('data.variants.0.minimum_use_date', null) ->assertJsonPath( 'data.variants.0.maximum_use_date', fn (string $value): bool => str_starts_with($value, '2026-08-15T18:00:00'), ) ->assertJsonPath( 'data.variants.0.effective_minimum_use_date', fn (string $value): bool => str_starts_with($value, '2026-08-01T09:00:00'), ) ->assertJsonPath( 'data.variants.0.effective_maximum_use_date', fn (string $value): bool => str_starts_with($value, '2026-08-15T18:00:00'), ); $item = CatalogItem::query()->where('slug', 'shirt')->firstOrFail(); $variant = $item->variants()->firstOrFail(); $this->assertSame([0, 1], $item->attachments()->get()->pluck('pivot.orden')->all()); $this->assertSame([0], $variant->attachments()->get()->pluck('pivot.orden')->all()); $this->assertDatabaseHas('catalog_items_attachments', [ 'catalog_item_id' => $item->id, 'variant_id' => $variant->id, 'orden' => 0, ]); } public function test_it_validates_images_before_creating_the_catalog_item(): void { $tenant = $this->createTenant('validation'); $this->postJson("/api/tenants/{$tenant->codigo}/catalog-items", [ 'slug' => 'invalid-image', 'nombre' => 'Invalid image', 'precio' => 100, 'real_stock' => 1, 'images' => ['not-an-image'], ])->assertUnprocessable()->assertJsonValidationErrors('images.0'); $this->assertDatabaseMissing('catalog_items', ['slug' => 'invalid-image']); } private function createTenant(string $code = 'catalog-controller'): Tenant { $headerLogo = $this->createAttachment("{$code}-header"); $footerLogo = $this->createAttachment("{$code}-footer"); return Tenant::query()->create([ 'codigo' => $code, 'nombre' => ucfirst($code), 'dominio' => "{$code}.local", 'primary_color' => '#000000', 'secondary_color' => '#000000', 'danger_color' => '#000000', 'success_color' => '#000000', 'header_bg_color' => '#000000', 'footer_bg_color' => '#000000', 'header_logo_id' => $headerLogo->id, 'footer_logo_id' => $footerLogo->id, ]); } private function createAttachment(string $name): Attachment { return Attachment::query()->create([ 'path' => "test/{$name}.png", 'filename' => "{$name}.png", 'type' => AttachmentType::Image, 'mime_type' => 'image/png', ]); } }