Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
138 lines
5.3 KiB
PHP
138 lines
5.3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Design;
|
||
|
||
use LIT\MCP\Integrations\Divi\BlockTree\Block;
|
||
use LIT\MCP\Integrations\Divi\BlockTree\Document;
|
||
use LIT\MCP\Integrations\Divi\BlockTree\GlobalInstance;
|
||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
||
use LIT\MCP\Integrations\Divi\BlockTree\Serializer;
|
||
use LIT\MCP\Integrations\Divi\Design\NodeRewrite;
|
||
use LIT\MCP\Integrations\Divi\Design\TreeRewrite;
|
||
use LIT\MCP\Tests\Unit\TestCase;
|
||
|
||
final class TreeRewriteTest extends TestCase
|
||
{
|
||
private static function document(string $inner): Document
|
||
{
|
||
return (new Parser())->parse(
|
||
'<!-- wp:divi/section --><!-- wp:divi/row --><!-- wp:divi/column -->' . $inner
|
||
. '<!-- /wp:divi/column --><!-- /wp:divi/row --><!-- /wp:divi/section -->'
|
||
);
|
||
}
|
||
|
||
/** Marks every divi/button; refuses opaque blocks, like the real strategies must never be offered one. */
|
||
private static function touchButtons(): NodeRewrite
|
||
{
|
||
return new class implements NodeRewrite {
|
||
public function rewrite(Block $block): ?array
|
||
{
|
||
if ($block->isOpaque()) {
|
||
throw new \LogicException('An opaque block was offered to rewrite().');
|
||
}
|
||
|
||
return $block->name() === 'divi/button' ? $block->attrs() + ['touched' => true] : null;
|
||
}
|
||
|
||
public function notes(Block $block, string $nodeId): array
|
||
{
|
||
return ['Hinweis ' . $nodeId];
|
||
}
|
||
|
||
public function concernsInstance(Block $instance): bool
|
||
{
|
||
return GlobalInstance::effectiveName($instance) === 'divi/button';
|
||
}
|
||
};
|
||
}
|
||
|
||
public function testChangesBlocksAndReportsThem(): void
|
||
{
|
||
$document = self::document(
|
||
'<!-- wp:divi/button {"module":{"meta":{"adminLabel":{"desktop":{"value":"Kaufen"}}}}} /-->'
|
||
. '<!-- wp:divi/text /--><!-- wp:divi/button /-->'
|
||
);
|
||
|
||
$result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document));
|
||
|
||
self::assertSame([
|
||
['id' => 's0.r0.c0.m0', 'module' => 'divi/button', 'label' => 'Kaufen'],
|
||
['id' => 's0.r0.c0.m2', 'module' => 'divi/button', 'label' => ''],
|
||
], $result['changed']);
|
||
self::assertSame(['Hinweis s0.r0.c0.m0', 'Hinweis s0.r0.c0.m2'], $result['warnings']);
|
||
self::assertSame([], $result['skipped']);
|
||
self::assertSame(2, substr_count(Serializer::document($document), '"touched":true'));
|
||
}
|
||
|
||
public function testNothingToDoChangesNothing(): void
|
||
{
|
||
$document = self::document('<!-- wp:divi/text {"a":1} /-->');
|
||
$before = Serializer::document($document);
|
||
|
||
$result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document));
|
||
|
||
self::assertSame(['changed' => [], 'warnings' => [], 'skipped' => []], $result);
|
||
self::assertSame($before, Serializer::document($document));
|
||
}
|
||
|
||
public function testGlobalInstancesAreSkippedWithTheLibraryEntry(): void
|
||
{
|
||
$document = self::document(
|
||
'<!-- wp:divi/global-layout {"globalModule":"1058","blockName":"divi/button"} /-->'
|
||
. '<!-- wp:divi/global-layout {"globalModule":"1059","blockName":"divi/text"} /-->'
|
||
);
|
||
$before = Serializer::document($document);
|
||
|
||
$result = (new TreeRewrite(self::touchButtons(), true))->apply(NodeIndex::build($document));
|
||
|
||
self::assertSame([], $result['changed']);
|
||
self::assertSame(
|
||
[['id' => 's0.r0.c0.g0', 'reason' => 'globales Modul – im Bibliothekseintrag 1058 ändern']],
|
||
$result['skipped']
|
||
);
|
||
self::assertSame($before, Serializer::document($document), 'instances are never rewritten');
|
||
}
|
||
|
||
/** Ruling P13, fail closed: without $revealLibraryIds the reason names no library ID. */
|
||
public function testGlobalInstanceReasonHidesTheLibraryIdByDefault(): void
|
||
{
|
||
$document = self::document(
|
||
'<!-- wp:divi/global-layout {"globalModule":"1058","blockName":"divi/button"} /-->'
|
||
);
|
||
|
||
$result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document));
|
||
|
||
self::assertSame(
|
||
[['id' => 's0.r0.c0.g0', 'reason' => 'globales Modul – im Divi-Builder ändern']],
|
||
$result['skipped']
|
||
);
|
||
}
|
||
|
||
public function testBlocksWithUnreadableAttributesAreSkippedToo(): void
|
||
{
|
||
$document = self::document('<!-- wp:divi/button {"a":1,} /-->');
|
||
|
||
$result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document));
|
||
|
||
self::assertSame(
|
||
[['id' => 's0.r0.c0.m0', 'reason' => 'Attribute nicht lesbar – im Divi-Builder prüfen']],
|
||
$result['skipped']
|
||
);
|
||
}
|
||
|
||
public function testAGlobalLayoutWithoutLibraryEntryHasItsOwnReason(): void
|
||
{
|
||
$document = self::document('<!-- wp:divi/global-layout {"blockName":"divi/button"} /-->');
|
||
|
||
$result = (new TreeRewrite(self::touchButtons()))->apply(NodeIndex::build($document));
|
||
|
||
self::assertSame(
|
||
[['id' => 's0.r0.c0.g0', 'reason' => 'globales Modul ohne Bibliothekseintrag – im Divi-Builder prüfen']],
|
||
$result['skipped']
|
||
);
|
||
}
|
||
}
|