b2in/tests/Feature/AppointmentTriggerTest.php
Kevin Adametz 7953a8c9a1 Interior-Farbwelt, Welten-Trennung, Tischlerei und Herkunfts-Sektion
Arbeitsplan 14.09.2026, Punkte 1.1 bis 1.4 (Nachträge 6 bis 10 im Entwicklungsplan):

- Farbwelt Interior (Tanne, Creme, Sand, Ocker, Clay) als Standard, Immobilien-Welt
  behält das bisherige Blau über body.world-immobilien; Logo je Welt, Favicons neu,
  Welten-Wechsler in Kopf- und Fußzeile.
- Saubere Trennung der Welten: eigene Navigation, Ankündigungsleiste, Magazinliste,
  Über-uns-Seite, FAQ, Kontaktseite und Abschluss-CTA für Immobilien; Beiträge tragen
  eine Welt (Migration + Admin-Feld). Abschluss-CTA Ton in Ton statt Grün-zu-Ocker.
- Kontakt: Betreffe in Gruppen Interior / Immobilien / B2in, Marken darin.
  Terminanfrage-Buttons öffnen das Widget mit vorgewähltem Anliegen; Select-Felder
  einheitlich gestaltet.
- Tischlerei als vierte Kernmarke (Platzhalter), Kachelraster 2×2.
- Herkunfts-Sektion „Aus der Region gefertigt“ mit schematischer Standortkarte und
  Ablauf CABINET (Beratung Bielefeld, Fertigung Köln, Aufbau mit Tischlerei).

Deployment: migrate, WorldSplitCmsSeeder, CmsBrandSeeder, OriginSectionCmsSeeder
(Abschnitt 8 im Entwicklungsplan).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-15 12:46:41 +00:00

87 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Blade;
uses(RefreshDatabase::class);
// ========================================
// <x-appointment-link>: Kontakt-Links oeffnen das Widget
// ========================================
it('marks links to the contact pages as widget triggers', function (string $href) {
$html = Blade::render('<x-appointment-link :href="$href" class="btn">Termin</x-appointment-link>', ['href' => $href]);
expect($html)->toContain('data-open-appointment')
->toContain('href="'.$href.'"')
->toContain('class="btn"');
})->with([
'interior' => '/contact',
'immobilien' => '/immobilien/kontakt',
'absolute' => 'https://b2in.test/contact',
]);
it('leaves links to other pages as plain links', function () {
$html = Blade::render('<x-appointment-link href="/marken" class="btn">Marken</x-appointment-link>');
expect($html)->not->toContain('data-open-appointment')
->toContain('href="/marken"');
});
it('hands over the topic that should be preselected', function () {
$html = Blade::render('<x-appointment-link href="/contact" topic="cabinet">Termin</x-appointment-link>');
expect($html)->toContain('data-appointment-topic="cabinet"');
});
// ========================================
// Sektionen auf der Seite
// ========================================
it('opens the widget from the appointment buttons of the homepage', function () {
$html = $this->get('/')->assertSuccessful()->getContent();
// Hero (zweiter Button), Weiche (beide Karten) und Abschluss-CTA
expect(substr_count($html, 'data-open-appointment'))->toBeGreaterThanOrEqual(4);
});
it('preselects the brand when the widget is opened from a brand page', function () {
$html = $this->get('/marken/cabinet')->assertSuccessful()->getContent();
expect($html)->toContain('data-appointment-topic="cabinet"');
});
it('opens the widget from the real estate calls to action too', function () {
$html = $this->get('/immobilien')->assertSuccessful()->getContent();
expect($html)->toContain('data-open-appointment');
});
it('keeps the contact button in the header as a link to the contact page', function () {
$html = $this->get('/')->assertSuccessful()->getContent();
$header = substr($html, (int) strpos($html, '<header'), (int) strpos($html, '</header>') - (int) strpos($html, '<header'));
expect($header)->toContain('href="'.route('contact').'"')
->not->toContain('data-open-appointment');
});
it('listens for the open event in the widget and intercepts the links in the frontend script', function () {
expect($this->get('/')->assertSuccessful()->getContent())->toContain('open-appointment.window');
expect(file_get_contents(resource_path('js/app.js')))->toContain('a[data-open-appointment]')
->toContain("new CustomEvent('open-appointment'");
});
// ========================================
// Formularfelder
// ========================================
it('styles the selects of the widget and the contact page with the shared field classes', function () {
expect($this->get('/')->assertSuccessful()->getContent())->toMatch('/<select[^>]*id="appointment-topic"[^>]*class="form-field form-select"/');
expect($this->get('/contact')->assertSuccessful()->getContent())->toMatch('/<select[^>]*id="subject"[^>]*class="form-field form-select"/');
$css = file_get_contents(resource_path('css/web/shared-styles.css'));
expect($css)->toContain('.form-field')->toContain('.form-select');
});