Nachtrag 11: Herkunfts-Sektion liest Ort, Entfernung und Rolle aus der Markenverwaltung (drei neue Felder an cms_brands, BrandOriginSeeder), Kartenpositionen im Code, „Marken“ in der Sidebar. Nachtrag 12: Inhalte-Editor zeigt die Seiten der Website mit ihren Sektionen in Reihenfolge (config/cms_pages.php, CmsPageTree), Felder in Klartext, fehlende Sektionen aus der Sprachdatei anlegbar, Vorschau der echten Seite im iframe mit Sprung zur Sektion; Anker an allen lebenden Sektionen nachgezogen. Nachtrag 13: Referenzen als eigenes Modul (CmsReference, Portal-Seite, /referenzen mit Fallback auf die Markengalerien); Immobilien-Projekte aus Sidebar und CMS-Übersicht genommen, Route bleibt. Dazu .gitignore für _b2in_interior_shop/ und docs/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
144 lines
4.8 KiB
PHP
144 lines
4.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\CmsReference;
|
|
use App\Models\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Volt\Volt;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
/**
|
|
* Referenzen verwalten (Nachtrag 13).
|
|
*/
|
|
beforeEach(function () {
|
|
url()->forceRootUrl('https://'.config('domains.domain_portal'));
|
|
});
|
|
|
|
it('requires authentication', function () {
|
|
$this->get(route('cms.references.index'))->assertRedirect('/login');
|
|
});
|
|
|
|
it('renders for authenticated users', function () {
|
|
$this->actingAs(User::factory()->create())
|
|
->get(route('cms.references.index'))
|
|
->assertSuccessful()
|
|
->assertSee('Referenzen')
|
|
->assertSee('Keine Referenzen');
|
|
});
|
|
|
|
it('creates a reference with brands, cover and gallery', function () {
|
|
$this->seed(\Database\Seeders\CmsBrandSeeder::class);
|
|
$this->actingAs(User::factory()->create());
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('openCreate')
|
|
->set('referenceTitle', 'Ankleide unter der Dachschräge')
|
|
->set('location', 'Bielefeld')
|
|
->set('year', '2025')
|
|
->set('description', 'Maßschrank bis unter den First.')
|
|
->set('image', 'referenzen/ankleide.webp')
|
|
->set('brandSlugs', ['cabinet', 'tischlerei'])
|
|
->call('addGalleryImage')
|
|
->set('gallery.0.image', 'referenzen/ankleide-2.webp')
|
|
->set('gallery.0.caption', 'Innenausbau')
|
|
->call('addGalleryImage')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$reference = CmsReference::firstOrFail();
|
|
|
|
expect($reference->getTranslation('title', 'de'))->toBe('Ankleide unter der Dachschräge')
|
|
->and($reference->location)->toBe('Bielefeld')
|
|
->and($reference->year)->toBe('2025')
|
|
->and($reference->image)->toBe('referenzen/ankleide.webp')
|
|
->and($reference->brand_slugs)->toBe(['cabinet', 'tischlerei'])
|
|
->and($reference->gallery)->toBe([['image' => 'referenzen/ankleide-2.webp', 'caption' => 'Innenausbau']])
|
|
->and($reference->is_published)->toBeTrue();
|
|
});
|
|
|
|
it('requires a title', function () {
|
|
$this->actingAs(User::factory()->create());
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('openCreate')
|
|
->set('referenceTitle', '')
|
|
->call('save')
|
|
->assertHasErrors(['referenceTitle']);
|
|
|
|
expect(CmsReference::count())->toBe(0);
|
|
});
|
|
|
|
it('rejects a brand slug that does not exist', function () {
|
|
$this->actingAs(User::factory()->create());
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('openCreate')
|
|
->set('referenceTitle', 'Test')
|
|
->set('brandSlugs', ['gibt-es-nicht'])
|
|
->call('save')
|
|
->assertHasErrors(['brandSlugs.0']);
|
|
});
|
|
|
|
it('edits an existing reference and keeps both languages', function () {
|
|
$this->actingAs(User::factory()->create());
|
|
$reference = CmsReference::factory()->create(['title' => ['de' => 'Küche', 'en' => 'Kitchen']]);
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('openEdit', $reference->id)
|
|
->assertSet('referenceTitle', 'Küche')
|
|
->set('referenceTitle', 'Küche in Hiddenhausen')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$reference->refresh();
|
|
|
|
expect($reference->getTranslation('title', 'de'))->toBe('Küche in Hiddenhausen')
|
|
->and($reference->getTranslation('title', 'en'))->toBe('Kitchen');
|
|
});
|
|
|
|
it('reorders and removes gallery images', function () {
|
|
$this->actingAs(User::factory()->create());
|
|
$reference = CmsReference::factory()->withGallery(3)->create();
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('openEdit', $reference->id)
|
|
->call('moveGalleryImage', 2, -1)
|
|
->call('moveGalleryImage', 0, -1)
|
|
->call('removeGalleryImage', 2)
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
expect(array_column($reference->fresh()->gallery, 'image'))
|
|
->toBe(['referenzen/bild-1.webp', 'referenzen/bild-3.webp']);
|
|
});
|
|
|
|
it('toggles the published state and deletes', function () {
|
|
$this->actingAs(User::factory()->create());
|
|
$reference = CmsReference::factory()->create();
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('togglePublished', $reference->id);
|
|
|
|
expect($reference->fresh()->is_published)->toBeFalse();
|
|
|
|
Volt::test('admin.cms.references-index')
|
|
->call('deleteReference', $reference->id);
|
|
|
|
expect(CmsReference::count())->toBe(0);
|
|
});
|
|
|
|
it('is linked from the sidebar while the real estate projects are not', function () {
|
|
\Spatie\Permission\Models\Role::firstOrCreate(['name' => 'Admin']);
|
|
$user = User::factory()->create();
|
|
$user->assignRole('Admin');
|
|
|
|
$html = $this->actingAs($user)
|
|
->get(route('cms.references.index'))
|
|
->assertSuccessful()
|
|
->getContent();
|
|
|
|
expect($html)->toMatch('#data-content>\s*Referenzen\s*</div>#')
|
|
->not->toContain(route('cms.projects.index'));
|
|
});
|