b2in/tests/Feature/CmsEditorParagraphsTest.php
Kevin Adametz 451e738c8b CMS: Absatz-Tags aus dem Rich-Text-Editor erscheinen nicht mehr als Text
Der Editor packt eingefügten Text in <p>; Felder wie die FAQ-Antwort gibt die Website als Text
aus, die Tags waren sichtbar. Beim Speichern entfernt unwrapParagraphs() die Absätze (ein
Absatz ohne <p>, mehrere mit <br><br>, Blockinhalte unverändert). cms_inline() gibt die
Felder als bereinigtes Inline-HTML aus – auch schon gespeicherte Texte mit <p> erscheinen
sauber, Fett und Hervorhebung werden dargestellt.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 06:58:48 +00:00

69 lines
3.1 KiB
PHP

<?php
use App\Models\User;
use App\Services\CmsFluxEditorHtmlTransformer;
use Database\Seeders\CmsContentSeeder;
use FluxCms\Core\Models\CmsContent;
use Livewire\Volt\Volt;
/**
* Der Rich-Text-Editor packt eingefügten Text in <p>; auf der Website erschienen die Tags als
* Text, z. B. in der FAQ (12.10.2026).
*/
it('stores pasted text from the editor without paragraph tags', function (string $editor, string $stored) {
expect(CmsFluxEditorHtmlTransformer::unwrapParagraphs($editor))->toBe($stored);
})->with([
'ein Absatz' => ['<p>Eingefügter Text</p>', 'Eingefügter Text'],
'Sonderzeichen' => ['<p>Planung &amp; Montage</p>', 'Planung & Montage'],
'fett' => ['<p>Mit <strong>fett</strong></p>', 'Mit <strong>fett</strong>'],
'zwei Absätze' => ['<p>Eins</p><p>Zwei</p>', 'Eins<br><br>Zwei'],
'leere Absätze' => ['<p>Text</p><p></p><p><br></p>', 'Text'],
'Blockinhalt bleibt' => ['<h2>Titel</h2><p>Text</p>', '<h2>Titel</h2><p>Text</p>'],
'schon Klartext' => ['Ohne Tags', 'Ohne Tags'],
]);
it('renders cms text inline: plain text escaped, editor html without paragraphs, nothing unsafe', function (string $value, string $html) {
expect((string) cms_inline($value))->toBe($html);
})->with([
['Planung & Montage', 'Planung &amp; Montage'],
['<p>Schon gespeichert</p>', 'Schon gespeichert'],
['<p>Mit <mark>Hervorhebung</mark></p>', 'Mit <span class="text-secondary">Hervorhebung</span>'],
['<p>a</p><p>b</p>', 'a<br><br>b'],
['<a href="javascript:alert(1)" onclick="x()">Link</a>', '<a href="#">Link</a>'],
['<p>&lt;script&gt;</p>', ''],
]);
it('saves a pasted faq answer without p tags and shows it cleanly on the page', function () {
$this->actingAs(User::factory()->create());
$this->seed(CmsContentSeeder::class);
$row = CmsContent::query()->where('group', 'faq')->where('key', 'faq')->first();
$component = Volt::test('admin.cms.content-index')
->call('startFieldEdit', $row->id, 'questions');
$component->set('jsonItems.0.answer', '<p>Neue Antwort aus der Zwischenablage</p>')
->call('saveJsonModal');
expect($row->refresh()->getTranslation('value', 'de')['questions'][0]['answer'])->toBe('Neue Antwort aus der Zwischenablage');
$page = $this->get('/faq')->assertSuccessful()->getContent();
expect(substr($page, strpos($page, 'id="faq"')))->toContain('Neue Antwort aus der Zwischenablage')
->not->toContain('&lt;p&gt;');
});
it('shows answers that were already stored with p tags without the tags', function () {
$this->seed(CmsContentSeeder::class);
$row = CmsContent::query()->where('group', 'faq')->where('key', 'faq')->first();
$value = $row->getTranslation('value', 'de');
$value['questions'][0]['answer'] = '<p>Bereits gespeichert mit Absatz</p>';
$row->setTranslation('value', 'de', $value)->save();
app(FluxCms\Core\Services\CmsContentService::class)->clearCache('faq');
$page = $this->get('/faq')->assertSuccessful()->getContent();
$section = substr($page, strpos($page, 'id="faq"'));
expect($section)->toContain('Bereits gespeichert mit Absatz')
->not->toContain('&lt;p&gt;')
->not->toContain('<p>Bereits');
});