Umsetzung von AP0-AP6 aus dev/2026-08-28/entwicklungsplan.md sowie der vorab gefundenen Befunde T1 und B1-B13. Befunde - CmsContentSeeder überschrieb bei jedem Lauf alle redaktionellen Inhalte; jetzt Redaktionsschutz plus gezielter Relaunch-Seeder (B1) - Magazin-CMS war nicht ans Frontend angebunden, Artikel jetzt über Slugs mit 301 von den alten numerischen URLs (B2) - Vier veröffentlichte Display-Playlists zeigten auf b2in.test und wären live nicht ladbar gewesen (B13) - Info-Tablet speicherte geleerte Öffnungszeiten nicht (T1) - /service und /portfolio lieferten seit Februar 500 (B12) Website - Startseite neu strukturiert und umgetextet, eigene Seite /marken mit Detailseite je Kernmarke, /netzwerk und Altrouten leiten dorthin - Galerie je Marke, getrennt nach realisierten Projekten und Visualisierungen; ohne gesetzte Kategorie gilt ein Bild als Entwurf - Seite /referenzen, gespeist aus den Markengalerien - Showroom-Display im 9:16-Rahmen über eine schreibgeschützte Embed-Route ohne Preview-Token - Terminanfrage-Widget auf allen Seiten, Markenauswahl aus dem CMS, WhatsApp per Klick-zum-Chat-Link mit vorbereitetem Text - FAQ, Über-uns, Kontakt und Magazin inhaltlich auf Interior umgestellt Sonstiges - Vorschau-Instanzen liefern noindex und verlinken sich bei unbekanntem Host auf sich selbst statt auf eine fremde Domain - Seeder-Zugangsdaten aus dem Code in die Konfiguration (B8) - Ablauf für die Vorschau: dev/2026-08-28/preview-deployment.md 833 Tests grün (3084 Assertions), Pint sauber. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
146 lines
6 KiB
PHP
146 lines
6 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
// ========================================
|
||
// Live-Seiten: HTTP Status
|
||
// ========================================
|
||
|
||
it('homepage loads', fn () => $this->get('/')->assertSuccessful());
|
||
it('immobilien page loads', fn () => $this->get('/immobilien')->assertSuccessful());
|
||
it('immobilien expose loads', fn () => $this->get('/immobilien/azizi-creek-views-4')->assertSuccessful());
|
||
it('marken page loads', fn () => $this->get('/marken')->assertSuccessful());
|
||
it('magazin list loads', fn () => $this->get('/magazin')->assertSuccessful());
|
||
|
||
it('every magazin article loads under its slug', function (string $slug) {
|
||
$this->get('/magazin/'.$slug)->assertSuccessful();
|
||
})->with(array_values(App\Models\CmsArticle::LEGACY_ID_TO_SLUG));
|
||
|
||
// Die alten numerischen URLs bleiben erreichbar – jetzt ueber eine 301 auf den Slug.
|
||
it('every old numeric magazin URL still reaches its article', function (int $id) {
|
||
$slug = App\Models\CmsArticle::slugForLegacyId($id);
|
||
|
||
$this->get('/magazin/'.$id)->assertRedirect('/magazin/'.$slug);
|
||
$this->get('/magazin/'.$slug)->assertSuccessful();
|
||
})->with(array_keys(App\Models\CmsArticle::LEGACY_ID_TO_SLUG));
|
||
it('about page loads', fn () => $this->get('/about')->assertSuccessful());
|
||
it('contact page loads', fn () => $this->get('/contact')->assertSuccessful());
|
||
it('faq page loads', fn () => $this->get('/faq')->assertSuccessful());
|
||
|
||
// ========================================
|
||
// Redirects
|
||
// ========================================
|
||
|
||
it('interior redirects to marken', fn () => $this->get('/interior')->assertRedirect('/marken'));
|
||
it('partner redirects to marken', fn () => $this->get('/partner')->assertRedirect('/marken'));
|
||
it('netzwerk redirects to marken', fn () => $this->get('/netzwerk')->assertRedirect('/marken'));
|
||
it('ecosystem redirects to partner', fn () => $this->get('/ecosystem')->assertRedirect('/partner'));
|
||
|
||
// ========================================
|
||
// Dev/Archiv-Seiten
|
||
// ========================================
|
||
|
||
it('dev sitemap loads', fn () => $this->get('/dev/sitemap')->assertSuccessful());
|
||
it('dev immobilien v1 loads', fn () => $this->get('/dev/immobilien-v1')->assertSuccessful());
|
||
it('dev interior v1 loads', fn () => $this->get('/dev/interior-v1')->assertSuccessful());
|
||
it('dev partner v1 loads', fn () => $this->get('/dev/partner-v1')->assertSuccessful());
|
||
|
||
// ========================================
|
||
// 404 für ungültige Routen
|
||
// ========================================
|
||
|
||
it('invalid immobilien slug returns 404', fn () => $this->get('/immobilien/nonexistent')->assertNotFound());
|
||
|
||
// ========================================
|
||
// Announcement Bar auf allen Seiten
|
||
// ========================================
|
||
|
||
it('announcement bar visible on homepage', fn () => $this->get('/')->assertSee('B2in Interior'));
|
||
it('announcement bar visible on about', fn () => $this->get('/about')->assertSee('B2in Interior'));
|
||
|
||
// ========================================
|
||
// Kritische Inhalte vorhanden
|
||
// ========================================
|
||
|
||
it('homepage has navigation', fn () => $this->get('/')->assertSee('Immobilien')->assertSee('Netzwerk')->assertSee('Magazin'));
|
||
it('immobilien has all five sections', function () {
|
||
$this->get('/immobilien')
|
||
->assertSee('Warum Dubai für Investoren relevant bleibt')
|
||
->assertSee('Der Kaufprozess mit B2in')
|
||
->assertSee('Passt Dubai zu Ihrer Investmentstrategie?')
|
||
->assertSee('Einrichtung mitdenken')
|
||
->assertSee('Investoren');
|
||
});
|
||
it('marken page lists the core brands', fn () => $this->get('/marken')->assertSee('CABINET')->assertSee('Febrü', false));
|
||
it('magazin has all five articles', function () {
|
||
$this->get('/magazin')
|
||
->assertSee('Escrow-System')
|
||
->assertSee('Al Jaddaf')
|
||
->assertSee('Turnkey')
|
||
->assertSee('Supply-Chain')
|
||
->assertSee('Local for Local');
|
||
});
|
||
|
||
// ========================================
|
||
// Verwaiste Seiten
|
||
// ========================================
|
||
//
|
||
// /service und /portfolio lieferten Status 500, weil ihre Content-Sektionen nicht mehr
|
||
// existieren. Sie sind oeffentlich erreichbar und damit auch fuer Crawler sichtbar.
|
||
|
||
it('service page no longer errors', fn () => $this->get('/service')->assertRedirect('/marken'));
|
||
it('portfolio page no longer errors', fn () => $this->get('/portfolio')->assertRedirect('/immobilien'));
|
||
|
||
// ========================================
|
||
// Inhalte auf den Interior-Auftritt umgestellt
|
||
// ========================================
|
||
|
||
it('no longer sells dubai investments in the faq', function () {
|
||
$response = $this->get('/faq')->assertSuccessful();
|
||
|
||
$response->assertDontSee('Dubai')
|
||
->assertSee('Für Ihr Zuhause', false)
|
||
->assertSee('Für Projekte und Objekte');
|
||
});
|
||
|
||
it('tells the interior story on the about page', function () {
|
||
$this->get('/about')
|
||
->assertSuccessful()
|
||
->assertDontSee('Dubai')
|
||
->assertDontSee('digitale Werkzeuge')
|
||
->assertSee('Beratung statt Verkauf')
|
||
->assertSee('Regional verwurzelt');
|
||
});
|
||
|
||
it('offers interior subjects in the contact form', function () {
|
||
$this->get('/contact')
|
||
->assertSuccessful()
|
||
->assertSee('Beratungstermin')
|
||
->assertSee('Maßanfertigung für mein Zuhause', false)
|
||
->assertSee('Küchenplanung', false);
|
||
});
|
||
|
||
// ========================================
|
||
// Vorschau-Instanzen dürfen nicht indexiert werden
|
||
// ========================================
|
||
|
||
it('allows indexing in production', function () {
|
||
config()->set('app.indexable', true);
|
||
|
||
$this->get('/')
|
||
->assertSuccessful()
|
||
->assertDontSee('noindex', false);
|
||
});
|
||
|
||
it('blocks indexing on a preview instance', function () {
|
||
config()->set('app.indexable', false);
|
||
|
||
$this->get('/')
|
||
->assertSuccessful()
|
||
->assertSee('<meta name="robots" content="noindex, nofollow">', false);
|
||
});
|
||
|
||
it('defaults to noindex outside production', function () {
|
||
// Gegenprobe zur Konfiguration selbst: ohne expliziten Schalter entscheidet APP_ENV.
|
||
expect((bool) (env('SITE_INDEXABLE', env('APP_ENV', 'production') === 'production')))->toBeFalse();
|
||
});
|