Files
WP-LIT-MCP/tests/Unit/Integrations/Divi/Compose/WarningsTest.php
T

200 lines
7.9 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
declare(strict_types=1);
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Compose;
use LIT\MCP\Integrations\Divi\BlockTree\Block;
use LIT\MCP\Integrations\Divi\BlockTree\Document;
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
use LIT\MCP\Integrations\Divi\Compose\Warnings;
use LIT\MCP\Integrations\Divi\Design\PresetAssignment;
use LIT\MCP\Integrations\Divi\Design\PresetBook;
use LIT\MCP\Tests\Support\ComposeFixture;
use LIT\MCP\Tests\Support\DiviFixtures;
use PHPUnit\Framework\TestCase;
final class WarningsTest extends TestCase
{
public function testWarnsAboutTheTouchedNodesOnly(): void
{
$composed = ComposeFixture::composer()->compose([
['type' => 'section', 'label' => 'Test', 'modules' => [
['type' => 'heading', 'text' => 'Titel', 'level' => 'h1'],
['type' => 'heading', 'text' => 'Zu tief', 'level' => 'h4'],
['type' => 'image', 'src' => 'https://kunde.test/a.jpg'],
['type' => 'text', 'content' => ''],
['type' => 'code', 'content' => '<div>x</div>'],
['type' => 'accordion'],
['type' => 'button', 'text' => 'Los', 'attrs' => [
'button.decoration.background' => ['desktop' => ['color' => '#2ea3f3']],
'button.decoration.font.font' => ['desktop' => ['family' => 'Open Sans', 'color' => '#abcdef']],
]],
]],
], null, 'nodes');
self::assertSame([], $composed['errors']);
$document = new Document();
foreach ($composed['blocks'] as $block) {
$document->append($block);
}
$warnings = (new Warnings(DiviFixtures::designSystem()))->collect(NodeIndex::build($document), $composed['blocks']);
self::assertSame(
[
's0.r0.c0.m2: Bild ohne Alt-Text.',
's0.r0.c0.m3: text ist leer (content fehlt).',
's0.r0.c0.m4: Code-Modul verwendet – im Divi-Builder nicht visuell bearbeitbar; nur nutzen, wenn kein '
. 'natives Modul passt.',
's0.r0.c0.m5: accordion ohne Einträge.',
's0.r0.c0.m6: feste Farbe #2ea3f3 – globale Farbe "Primärfarbe" ({{color:primary}}) passt.',
's0.r0.c0.m6: feste Schrift Open Sans – {{font:heading}} verwenden.',
's0.r0.c0.m1: Sprung in der Überschriftenhierarchie (h4 nach h1).',
],
$warnings
);
self::assertSame([], (new Warnings(DiviFixtures::designSystem()))->collect(NodeIndex::build($document), []));
}
/** @return array<string, mixed> Button attrs with a preset and a local font color. */
private static function button(string $color, string $preset = 'p-2'): array
{
return [
'modulePreset' => [$preset],
'button' => ['decoration' => ['font' => ['font' => ['desktop' => ['value' => ['color' => $color]]]]]],
];
}
/** Preset p-2 "CTA primär" sets the font color #ffffff; g-1 is a group preset without values. */
private static function book(): PresetBook
{
return PresetBook::fromDivi([
'module' => ['divi/button' => ['default' => '', 'items' => [
'p-2' => [
'id' => 'p-2',
'name' => 'CTA primär',
'moduleName' => 'divi/button',
'attrs' => ['button' => ['decoration' => ['font' => ['font' => [
'desktop' => ['value' => ['color' => '#ffffff']],
]]]]],
],
]]],
'group' => ['divi/font' => ['default' => '', 'items' => [
'g-1' => ['id' => 'g-1', 'name' => 'Fließtext groß', 'groupName' => 'divi/font'],
]]],
]);
}
/** @param int $loads Counts how often the preset book is read. */
private static function presets(int &$loads): PresetAssignment
{
return ComposeFixture::presetAssignment(null, null, null, null, static function () use (&$loads): PresetBook {
++$loads;
return self::book();
});
}
/**
* @param list<Block> $blocks top-level blocks of the page
* @param list<Block> $touched
* @return array{0: list<string>, 1: NodeIndex}
*/
private static function collect(array $blocks, array $touched, PresetAssignment $presets): array
{
$document = new Document();
foreach ($blocks as $block) {
$document->append($block);
}
$index = NodeIndex::build($document);
$warnings = (new Warnings(DiviFixtures::designSystem(), $presets))->collect($index, $touched);
return [
array_values(array_filter($warnings, static fn (string $w): bool => str_contains($w, 'überdecken'))),
$index,
];
}
public function testWarnsWhenLocalValuesCoverAnAssignedPreset(): void
{
$loads = 0;
$button = Block::create('divi/button', self::button('#000000'));
[$covering, $index] = self::collect([$button], [$button], self::presets($loads));
self::assertCount(1, $covering);
self::assertStringStartsWith(
$index->idOf($button) . ': lokale Werte überdecken „CTA primär“: ',
$covering[0]
);
self::assertStringContainsString('button.decoration.font.font', $covering[0]);
self::assertStringEndsWith('clear_overrides: true entfernt sie.', $covering[0]);
}
public function testEqualValuesAndUntouchedBlocksDoNotWarn(): void
{
$loads = 0;
$same = Block::create('divi/button', self::button('#ffffff'));
$other = Block::create('divi/button', self::button('#000000'));
[$covering] = self::collect([$same, $other], [$same], self::presets($loads));
self::assertSame([], $covering, 'the same value covers nothing; $other was not touched');
}
public function testChildrenOfATouchedBlockAreChecked(): void
{
$loads = 0;
$button = Block::create('divi/button', self::button('#000000'));
$section = Block::create('divi/section', [], [
Block::create('divi/row', [], [Block::create('divi/column', [], [$button])]),
]);
[$covering, $index] = self::collect([$section], [$section], self::presets($loads));
self::assertCount(1, $covering);
self::assertStringStartsWith($index->idOf($button) . ': lokale Werte', $covering[0]);
}
public function testThePresetBookIsOnlyReadForBlocksThatHavePresets(): void
{
$loads = 0;
$plain = Block::create('divi/button', [
'button' => ['decoration' => ['font' => ['font' => ['desktop' => ['value' => ['color' => '#000000']]]]]],
]);
$presets = self::presets($loads);
self::collect([$plain], [$plain], $presets);
self::assertSame(0, $loads, 'no touched block names a preset');
$grouped = Block::create('divi/button', [
'groupPreset' => ['button.decoration.font.font' => ['groupName' => 'divi/font', 'presetId' => ['g-1']]],
]);
$stacked = Block::create('divi/button', self::button('#000000'));
[$covering] = self::collect([$plain, $grouped, $stacked], [$plain, $grouped, $stacked], $presets);
self::assertSame(1, $loads, 'read once, for the first block that has a preset');
self::assertCount(1, $covering);
}
public function testOpaqueAndForeignBlocksAreSkipped(): void
{
$loads = 0;
$attrs = self::button('#000000');
$opaque = Block::parsed(
'divi/button',
$attrs + ['globalModule' => '9'],
'<!-- wp:divi/button {"globalModule":"9"} /-->',
true,
true
);
$foreign = Block::create('core/paragraph', $attrs);
[$covering] = self::collect([$opaque, $foreign], [$opaque, $foreign], self::presets($loads));
self::assertSame([], $covering);
self::assertSame(0, $loads);
}
}