getTable())->toBe('cms_brands'); expect((new Brand)->getTable())->toBe('brands'); }); it('only returns published brands, in order', function () { CmsBrand::factory()->create(['slug' => 'zwei', 'order' => 2]); CmsBrand::factory()->create(['slug' => 'eins', 'order' => 1]); CmsBrand::factory()->unpublished()->create(['slug' => 'entwurf', 'order' => 3]); $brands = CmsBrand::forFrontend(); expect(array_keys($brands))->toBe(['eins', 'zwei']); }); it('translates the editorial fields', function () { $brand = CmsBrand::factory()->create([ 'slug' => 'cabinet', 'name' => ['de' => 'CABINET', 'en' => 'CABINET'], 'tagline' => ['de' => 'Einbauschränke nach Maß.', 'en' => 'Fitted wardrobes made to measure.'], ]); expect($brand->getTranslation('tagline', 'de'))->toBe('Einbauschränke nach Maß.'); expect($brand->getTranslation('tagline', 'en'))->toBe('Fitted wardrobes made to measure.'); }); it('falls back to the lang section while no brand is maintained', function () { expect(CmsBrand::count())->toBe(0); $brands = CmsBrand::forFrontend(); expect($brands)->not->toBeEmpty(); expect(collect($brands)->pluck('name'))->toContain('CABINET'); }); it('marks fallback brands as having no detail page', function () { // Ohne gepflegte Marke gibt es keine Detailseite – die Kachel darf dann nicht verlinken. foreach (CmsBrand::forFrontend() as $brand) { expect($brand['has_detail_page'])->toBeFalse(); } }); it('marks maintained brands as having a detail page', function () { CmsBrand::factory()->create(['slug' => 'cabinet']); foreach (CmsBrand::forFrontend() as $brand) { expect($brand['has_detail_page'])->toBeTrue(); } }); it('seeds the three core brands without overwriting maintained ones', function () { $this->seed(\Database\Seeders\CmsBrandSeeder::class); expect(CmsBrand::count())->toBe(3); expect(CmsBrand::pluck('slug')->all())->toContain('cabinet', 'rotpunkt', 'februe'); $cabinet = CmsBrand::where('slug', 'cabinet')->firstOrFail(); $cabinet->setTranslation('tagline', 'de', 'Von Hand gepflegt'); $cabinet->save(); $this->seed(\Database\Seeders\CmsBrandSeeder::class); expect(CmsBrand::count())->toBe(3); expect($cabinet->fresh()->getTranslation('tagline', 'de'))->toBe('Von Hand gepflegt'); }); it('puts the home office first for Febrü', function () { $this->seed(\Database\Seeders\CmsBrandSeeder::class); $februe = CmsBrand::where('slug', 'februe')->firstOrFail(); $teaser = $februe->getTranslation('teaser', 'de'); expect(mb_strpos($teaser, 'Home-Office'))->toBeLessThan(mb_strpos($teaser, 'Büroeinrichtung')); }); // ======================================== // Galerie-Normalisierung // ======================================== it('normalises gallery entries into a fixed shape', function () { $items = CmsBrand::normalizeGallery([ ['image' => ' foto.webp ', 'category' => 'project', 'caption' => ' Ankleide '], ]); expect($items)->toBe([ ['image' => 'foto.webp', 'category' => 'project', 'caption' => 'Ankleide'], ]); }); it('treats an unknown or missing category as inspiration', function (mixed $entry) { $items = CmsBrand::normalizeGallery([$entry]); expect($items[0]['category'])->toBe(CmsBrand::GALLERY_INSPIRATION); })->with([ 'ohne Kategorie' => [['image' => 'a.webp']], 'leere Kategorie' => [['image' => 'a.webp', 'category' => '']], 'unbekannte Kategorie' => [['image' => 'a.webp', 'category' => 'referenz']], 'nur ein Dateiname' => ['a.webp'], ]); it('drops gallery entries without an image', function () { $items = CmsBrand::normalizeGallery([ ['image' => '', 'category' => 'project'], ['category' => 'project'], ['image' => 'da.webp', 'category' => 'project'], ]); expect($items)->toHaveCount(1) ->and($items[0]['image'])->toBe('da.webp'); }); it('groups the gallery by category', function () { $brand = CmsBrand::factory()->withGallery(projects: 2, inspirations: 3)->create(); $grouped = CmsBrand::groupGallery($brand->gallery); expect($grouped['projects'])->toHaveCount(2) ->and($grouped['inspirations'])->toHaveCount(3); }); it('returns empty groups for a brand without a gallery', function () { expect(CmsBrand::groupGallery(null))->toBe(['projects' => [], 'inspirations' => []]); });