b2in/tests/Feature/FaqCategoriesTest.php
Kevin Adametz dc31cdb401 FAQ im Inhalte-Editor vollständig bearbeitbar: Bereich je Frage statt verschachtelter sections
Die Bereiche der FAQ-Seite lagen als verschachtelte Listen in sections, der Editor zeigte
davon nur JSON-Text. Jetzt stehen alle Fragen in questions mit dem Feld category, Überschrift
und Symbol der Bereiche in categories. FAQ::groups baut daraus die Seite (allgemeine Fragen
zuerst), alte Einträge werden weiter dargestellt. FaqCategoriesSeeder stellt gespeicherte
Einträge um (FAQ und Immobilien-FAQ), Texte bleiben.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:50:44 +00:00

103 lines
4.8 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
use App\Livewire\Web\Components\Sections\FAQ;
use Database\Seeders\FaqCategoriesSeeder;
use FluxCms\Core\Models\CmsContent;
/**
* FAQ mit Bereich je Frage statt verschachtelter `sections` (09.10.2026) – so kann der
* Inhalte-Editor alle Fragen als Liste zeigen.
*/
function legacyFaq(): array
{
return [
'title' => 'FAQ',
'questions' => [['question' => 'Allgemein?', 'answer' => 'A']],
'sections' => [
['title' => 'Für Ihr Zuhause', 'icon' => 'home-modern', 'questions' => [['question' => 'Zuhause?', 'answer' => 'B']]],
['title' => 'Für Projekte', 'icon' => 'briefcase', 'questions' => [['question' => 'Projekt?', 'answer' => 'C']]],
],
];
}
it('flattens the nested sections into one list with a category per question', function () {
expect(FAQ::flatten(legacyFaq()))->toBe([
'title' => 'FAQ',
'questions' => [
['question' => 'Allgemein?', 'answer' => 'A', 'category' => ''],
['question' => 'Zuhause?', 'answer' => 'B', 'category' => 'Für Ihr Zuhause'],
['question' => 'Projekt?', 'answer' => 'C', 'category' => 'Für Projekte'],
],
'categories' => [
['title' => 'Für Ihr Zuhause', 'icon' => 'home-modern'],
['title' => 'Für Projekte', 'icon' => 'briefcase'],
],
]);
});
it('groups the questions: general first, then the categories in their order, unknown ones last', function () {
$groups = FAQ::groups([
'questions' => [
['question' => 'Neu?', 'answer' => 'x', 'category' => 'Sonstiges'],
['question' => 'Projekt?', 'answer' => 'x', 'category' => 'Für Projekte'],
['question' => 'Allgemein?', 'answer' => 'x', 'category' => ''],
['question' => '', 'answer' => 'leer'],
],
'categories' => [
['title' => 'Für Ihr Zuhause', 'icon' => 'home-modern'],
['title' => 'Für Projekte', 'icon' => 'briefcase'],
],
]);
expect(array_column($groups, 'title'))->toBe([null, 'Für Projekte', 'Sonstiges'])
->and(array_column($groups, 'icon'))->toBe([null, 'briefcase', 'question-mark-circle']);
});
it('shows all thirteen questions with both headings on the faq page', function () {
$page = $this->get('/faq')->assertSuccessful()->getContent();
$html = substr($page, strpos($page, 'id="faq"'));
expect(substr_count($html, 'card-elevated rounded-xl overflow-hidden'))->toBe(13)
->and(strpos($html, 'Was ist B2in und welche Services'))->toBeLessThan(strpos($html, 'Für Ihr Zuhause'))
->and(strpos($html, 'Für Ihr Zuhause'))->toBeLessThan(strpos($html, 'Muss ich gleich die ganze Wohnung'))
->and(strpos($html, 'Muss ich gleich die ganze Wohnung'))->toBeLessThan(strpos($html, 'Für Projekte und Objekte'))
->and(strpos($html, 'Für Projekte und Objekte'))->toBeLessThan(strpos($html, 'Ab welcher Größe'));
});
it('converts stored faq entries once and keeps maintained texts', function () {
$legacy = legacyFaq();
$legacy['sections'][0]['questions'][0]['answer'] = 'Im CMS gepflegt';
$row = CmsContent::create(['group' => 'faq', 'key' => 'faq', 'type' => 'json', 'order' => 0, 'value' => ['de' => $legacy, 'en' => legacyFaq()]]);
$this->seed(FaqCategoriesSeeder::class);
$first = $row->refresh()->getTranslations('value');
$this->seed(FaqCategoriesSeeder::class);
expect($row->refresh()->getTranslations('value'))->toBe($first)
->and($first['de'])->not->toHaveKey('sections')
->and($first['de']['questions'][1])->toBe(['question' => 'Zuhause?', 'answer' => 'Im CMS gepflegt', 'category' => 'Für Ihr Zuhause']);
$this->get('/faq')->assertSuccessful()->assertSee('Im CMS gepflegt')->assertSee('Für Projekte');
});
it('still renders entries in the old form until the seeder ran', function () {
CmsContent::create(['group' => 'faq', 'key' => 'faq', 'type' => 'json', 'order' => 0, 'value' => ['de' => legacyFaq()]]);
$this->get('/faq')->assertSuccessful()->assertSee('Zuhause?')->assertSee('Für Ihr Zuhause');
});
it('opens every faq question as plain fields in the content editor', function () {
$this->actingAs(App\Models\User::factory()->create());
$this->seed(Database\Seeders\CmsContentSeeder::class);
$row = CmsContent::query()->where('group', 'faq')->where('key', 'faq')->first();
$component = Livewire\Volt\Volt::test('admin.cms.content-index')
->call('startFieldEdit', $row->id, 'questions');
$items = $component->get('jsonItems');
expect($items)->toHaveCount(13)
->and(array_keys($items[5]))->toBe(['question', 'answer', 'category'])
->and($items[5]['category'])->toBe('Für Ihr Zuhause')
->and(collect($items)->flatten()->filter(fn ($value) => str_starts_with((string) $value, '[{')))->toBeEmpty();
});