Files
WP-LIT-MCP/tests/Unit/Integrations/Divi/Pages/DiviLoopWriteTest.php
T

176 lines
7.7 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\Pages;
use LIT\MCP\Abilities\Rev;
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
use LIT\MCP\Tests\Support\DiviFixtures;
use LIT\MCP\Tests\Support\DiviWriterFixture;
use WP_Error;
/**
* Ruling X3: lit/divi-insert, lit/divi-update and lit/divi-move use the loop scope of the node in the tree
* (LoopContext). The page: s0.r0.c0 runs a post loop (m0 shows loop_post_title, m1 is plain text, m2 runs its own
* term loop and shows loop_term_name), s0.r0.c1 a term loop, s0.r0.c2 no loop.
*/
final class DiviLoopWriteTest extends DiviWriteAbilityTestCase
{
private const POST_LOOP = ['enable' => 'on', 'queryType' => 'post_types'];
private const TERM_LOOP = ['enable' => 'on', 'queryType' => 'post_taxonomies'];
protected function setUp(): void
{
parent::setUp();
$this->original = self::page();
$this->post->post_content = $this->original;
$registry = self::registry();
$this->writer = DiviWriterFixture::writer(
$this->saved,
registry: new DynamicContentMap(static fn (int $postId): array => $registry)
);
}
/** DiviFixtures' registry plus the loop options these tests name (Divi 5.15.1 groups and fields). */
private static function registry(): array
{
$field = static fn (string $type): array => ['label' => 'x', 'type' => $type, 'default' => ''];
$common = ['before' => $field('text'), 'after' => $field('text'), 'loop_position' => $field('text')];
$option = static fn (string $id, string $group, array $fields): array => [
'id' => $id, 'label' => $id, 'type' => 'text', 'custom' => false, 'group' => $group, 'fields' => $fields,
];
return DiviFixtures::dynamicContentRegistry() + [
'loop_post_date' => $option('loop_post_date', 'Loop', $common + [
'date_format' => $field('select'), 'custom_date_format' => $field('text'),
]),
'loop_term_name' => $option('loop_term_name', 'Loop Terms', $common),
];
}
/** @param array<string, mixed> $attrs */
private static function block(string $name, array $attrs, string $inner = ''): string
{
$json = (string) json_encode($attrs + ['builderVersion' => '5.2.1'], JSON_UNESCAPED_UNICODE);
return sprintf('<!-- wp:divi/%s %s -->%s<!-- /wp:divi/%s -->', $name, $json, $inner, $name);
}
/** @param array<string, string> $loop */
private static function loop(array $loop): array
{
return ['module' => ['advanced' => ['loop' => ['desktop' => ['value' => $loop]]]]];
}
private static function text(string $value): string
{
return self::block('text', ['content' => ['innerContent' => ['desktop' => ['value' => $value]]]]);
}
private static function page(): string
{
$title = VariableRef::serialize('content', 'loop_post_title', ['before' => '', 'after' => '']);
$term = VariableRef::serialize('content', 'loop_term_name', ['before' => '', 'after' => '']);
$own = self::block('text', self::loop(self::TERM_LOOP) + [
'content' => ['innerContent' => ['desktop' => ['value' => $term]]],
]);
return '<!-- wp:divi/placeholder -->' . self::block('section', [], self::block('row', [], implode('', [
self::block('column', self::loop(self::POST_LOOP), self::text($title) . self::text('<p>Fest</p>') . $own),
self::block('column', self::loop(self::TERM_LOOP), self::text('<p>Term</p>')),
self::block('column', [], self::text('<p>Ohne</p>')),
]))) . '<!-- /wp:divi/placeholder -->';
}
/** @param array<string, mixed> $input */
private function insertInto(string $parent, array $input): mixed
{
return $this->insert()->execute(
['post_id' => 7, 'tree_rev' => $this->currentRev(), 'parent' => $parent] + $input
);
}
/** @param list<array<string, mixed>> $changes */
private function changeAll(array $changes): mixed
{
return $this->update()->execute(['post_id' => 7, 'tree_rev' => $this->currentRev(), 'changes' => $changes]);
}
/** @param array<string, mixed> $input */
private function moveNode(array $input): mixed
{
return $this->move()->execute(['post_id' => 7, 'tree_rev' => $this->currentRev()] + $input);
}
/** tree_rev of what the page holds now (the saver puts every saved content on the post). */
private function currentRev(): string
{
return Rev::of((string) $this->post->post_content);
}
private static function problems(mixed $error): string
{
self::assertInstanceOf(WP_Error::class, $error);
return implode(' | ', self::errorFields($error));
}
public function testInsertUsesTheLoopOfTheTargetParent(): void
{
$result = $this->insertInto('s0.r0.c0', ['nodes' => [
['type' => 'text', 'content' => '{{loop:post_date}}'],
['type' => 'text', 'content' => '{{loop:post_title}}'],
]]);
self::assertTrue($result['ok'], (string) json_encode($result));
$date = VariableRef::serialize('content', 'loop_post_date', ['before' => '', 'after' => '']);
self::assertStringContainsString(str_replace('"', '\\' . 'u0022', $date), $this->saved[0]);
$term = $this->insertInto('s0.r0.c1', ['nodes' => [['type' => 'text', 'content' => '{{loop:term_name}}']]]);
self::assertTrue($term['ok'], (string) json_encode($term));
}
public function testInsertRefusesLoopContentOutsideALoopOrOfAnotherKind(): void
{
$outside = $this->insertInto('s0.r0.c2', ['nodes' => [['type' => 'text', 'content' => '{{loop:post_date}}']]]);
self::assertStringContainsString('braucht eine Divi-Schleife', self::problems($outside));
$term = $this->insertInto('s0.r0.c1', ['nodes' => [['type' => 'text', 'content' => '{{loop:post_date}}']]]);
$wrongKind = self::problems($term);
self::assertStringContainsString('passt nicht zur Schleife dieses Elements (Typ: Terme)', $wrongKind);
$topLevel = $this->insert()->execute([
'post_id' => 7,
'tree_rev' => $this->currentRev(),
'nodes' => [['type' => 'section', 'modules' => [['type' => 'text', 'content' => '{{loop:post_date}}']]]],
]);
self::assertStringContainsString('braucht eine Divi-Schleife', self::problems($topLevel));
self::assertSame([], $this->saved);
}
/**
* Ruling X3, fail closed: a loop a new node of this call switches on counts only once it is saved – loop
* content in the same call is refused even where the parent's loop would let it pass (a term loop inside the
* post loop c0 would otherwise get post content: Divi reads the post with the term's ID).
*/
public function testANewLoopInTheSameCallIsRefusedWithLoopContent(): void
{
$ownLoop = ['module.advanced.loop' => ['desktop' => self::TERM_LOOP]];
foreach (['s0.r0.c0' => '{{loop:post_title}}', 's0.r0.c2' => '{{loop:term_name}}'] as $parent => $content) {
$refused = $this->insertInto($parent, ['nodes' => [
['type' => 'text', 'attrs' => $ownLoop, 'content' => $content],
]]);
self::assertStringContainsString('erst nach dem Speichern', self::problems($refused), $parent);
}
self::assertSame([], $this->saved);
$withoutLoopContent = $this->insertInto('s0.r0.c2', ['nodes' => [
['type' => 'text', 'attrs' => $ownLoop, 'content' => '<p>Liste</p>'],
]]);
self::assertTrue($withoutLoopContent['ok'], (string) json_encode($withoutLoopContent));
}
}