test: shared Divi fixtures in tests/Support (T1)
- DiviFixtures: markup(), givenPost(), schema(), designSystem(), catalog(), dynamicContentRegistry(), maliciousRefs() - moved verbatim out of DiviPageLoaderTest, DesignSystemTest, ModuleCatalogTest, DynamicContentMapTest and VariableRefTest (its malicious() provider now returns maliciousRefs()). - ComposeFixture moves to tests/Support. - DiviWriterFixture: modules(), designReader(), composition(), a recording saver(), log() and writer(&$saved, &$failures, unfiltered, loader) for the five tests that wired the Divi write stack by hand. No test cases or assertions changed (1397 / 5834). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,9 +14,8 @@ use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviComposition;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Compose\ComposeFixture;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Schema\ModuleCatalogTest;
|
||||
use LIT\MCP\Tests\Support\ComposeFixture;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
|
||||
@@ -28,14 +27,14 @@ final class DiviCompositionTest extends TestCase
|
||||
private function composition(): DiviComposition
|
||||
{
|
||||
$modules = Mockery::mock(DiviModules::class);
|
||||
$modules->allows('catalog')->andReturn(ModuleCatalogTest::sampleCatalog());
|
||||
$modules->allows('catalog')->andReturn(DiviFixtures::catalog());
|
||||
$modules->allows('builderVersion')->andReturn('5.2.1');
|
||||
$design = Mockery::mock(DesignSystemReader::class);
|
||||
$design->allows('read')->andReturn(DesignSystemTest::sample());
|
||||
$design->allows('read')->andReturn(DiviFixtures::designSystem());
|
||||
$registry = new DynamicContentMap(function (int $postId): array {
|
||||
$this->registryCalls[] = $postId;
|
||||
|
||||
return DynamicContentMapTest::registry();
|
||||
return DiviFixtures::dynamicContentRegistry();
|
||||
});
|
||||
|
||||
return new DiviComposition($modules, $design, ComposeFixture::sanitizer(), ComposeFixture::media(), $registry);
|
||||
|
||||
@@ -6,15 +6,11 @@ namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
|
||||
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
||||
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviComposition;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviContentComposer;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Compose\ComposeFixture;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Schema\ModuleCatalogTest;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
@@ -48,20 +44,16 @@ final class DiviContentComposerTest extends TestCase
|
||||
*/
|
||||
private function composer(bool $diviEnabled = true, ?callable $registry = null): DiviContentComposer
|
||||
{
|
||||
$modules = Mockery::mock(DiviModules::class);
|
||||
$modules->allows('catalog')->andReturn(ModuleCatalogTest::sampleCatalog());
|
||||
$modules->allows('builderVersion')->andReturn('5.2.1');
|
||||
$design = Mockery::mock(DesignSystemReader::class);
|
||||
$design->allows('read')->andReturn(DesignSystemTest::sample());
|
||||
$design = DiviWriterFixture::designReader();
|
||||
$map = new DynamicContentMap(function (int $postId) use ($registry): array {
|
||||
$this->registryCalls[] = $postId;
|
||||
|
||||
return $registry !== null ? $registry($postId) : DynamicContentMapTest::registry();
|
||||
return $registry !== null ? $registry($postId) : DiviFixtures::dynamicContentRegistry();
|
||||
});
|
||||
|
||||
return new DiviContentComposer(
|
||||
DiviPageLoaderTest::schema($diviEnabled),
|
||||
new DiviComposition($modules, $design, ComposeFixture::sanitizer(), ComposeFixture::media(), $map),
|
||||
DiviFixtures::schema($diviEnabled),
|
||||
DiviWriterFixture::composition($design, false, $map),
|
||||
$this->saver,
|
||||
$design
|
||||
);
|
||||
@@ -124,7 +116,7 @@ final class DiviContentComposerTest extends TestCase
|
||||
public function testWriteRefusesWhatTheNewEntrysMapDoesNotOffer(): void
|
||||
{
|
||||
$registry = static function (int $postId): array {
|
||||
$options = DynamicContentMapTest::registry();
|
||||
$options = DiviFixtures::dynamicContentRegistry();
|
||||
if ($postId !== 0) {
|
||||
unset($options['site_title']);
|
||||
}
|
||||
|
||||
@@ -4,66 +4,34 @@ declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPage;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPageLoader;
|
||||
use LIT\MCP\Integrations\WordPress\Schema\ContentSchema;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Error;
|
||||
use WP_Post;
|
||||
|
||||
final class DiviPageLoaderTest extends TestCase
|
||||
{
|
||||
public static function fixture(string $name): string
|
||||
{
|
||||
return (string) file_get_contents(dirname(__DIR__, 4) . '/Fixtures/divi/' . $name);
|
||||
}
|
||||
|
||||
/** Stubs everything PostGuard::editable() needs for a post with $content. */
|
||||
public static function givenPost(string $content, array $fields = []): WP_Post
|
||||
{
|
||||
$post = new WP_Post(array_merge(
|
||||
['ID' => 7, 'post_type' => 'page', 'post_status' => 'draft', 'post_title' => 'Start', 'post_content' => $content],
|
||||
$fields
|
||||
));
|
||||
Functions\when('get_post')->justReturn($post);
|
||||
Functions\when('current_user_can')->justReturn(true);
|
||||
Functions\when('get_permalink')->justReturn('https://kunde.test/?page_id=7');
|
||||
Functions\when('add_query_arg')->alias(static fn (string $key, string $value, string $url): string => $url . '&' . $key . '=' . $value);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public static function schema(bool $diviEnabled = true): ContentSchema
|
||||
{
|
||||
$schema = Mockery::mock(ContentSchema::class);
|
||||
$schema->allows('isManaged')->andReturn(true);
|
||||
$schema->allows('diviEnabled')->andReturn($diviEnabled);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
public function testLoadsTreeIndexAndTreeRev(): void
|
||||
{
|
||||
$content = self::fixture('synthetic-basic.html');
|
||||
self::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
|
||||
$page = (new DiviPageLoader(self::schema()))->load(7, true);
|
||||
$page = (new DiviPageLoader(DiviFixtures::schema()))->load(7, true);
|
||||
|
||||
self::assertInstanceOf(DiviPage::class, $page);
|
||||
self::assertSame(substr(hash('sha256', $content), 0, 12), $page->treeRev());
|
||||
self::assertSame('divi/button', $page->index->find('s0.r0.c1.m2')?->name());
|
||||
self::assertTrue($page->isDiviLayout());
|
||||
self::assertSame('https://kunde.test/?page_id=7&et_fb=1', $page->editUrl());
|
||||
self::assertNull((new DiviPageLoader(self::schema()))->writable($page));
|
||||
self::assertNull((new DiviPageLoader(DiviFixtures::schema()))->writable($page));
|
||||
}
|
||||
|
||||
public function testRefusesDivi4Content(): void
|
||||
{
|
||||
self::givenPost(self::fixture('divi4-shortcodes.html'));
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('divi4-shortcodes.html'));
|
||||
|
||||
$result = (new DiviPageLoader(self::schema()))->load(7, false);
|
||||
$result = (new DiviPageLoader(DiviFixtures::schema()))->load(7, false);
|
||||
|
||||
self::assertInstanceOf(WP_Error::class, $result);
|
||||
self::assertSame('lit_unsupported', $result->get_error_code());
|
||||
@@ -72,12 +40,12 @@ final class DiviPageLoaderTest extends TestCase
|
||||
|
||||
public function testRefusesMalformedMarkupAndLogsIt(): void
|
||||
{
|
||||
self::givenPost('<!-- wp:divi/section --><!-- wp:divi/row -->');
|
||||
DiviFixtures::givenPost('<!-- wp:divi/section --><!-- wp:divi/row -->');
|
||||
// error_log() is a PHP internal and cannot be stubbed; redirect it to a temp file instead.
|
||||
$log = (string) tempnam(sys_get_temp_dir(), 'lit-log');
|
||||
$previous = ini_set('error_log', $log);
|
||||
try {
|
||||
$result = (new DiviPageLoader(self::schema()))->load(7, false);
|
||||
$result = (new DiviPageLoader(DiviFixtures::schema()))->load(7, false);
|
||||
} finally {
|
||||
ini_set('error_log', (string) $previous);
|
||||
}
|
||||
@@ -90,8 +58,8 @@ final class DiviPageLoaderTest extends TestCase
|
||||
|
||||
public function testTrashedEntriesCanBeReadButNotWritten(): void
|
||||
{
|
||||
self::givenPost(self::fixture('synthetic-basic.html'), ['post_status' => 'trash']);
|
||||
$loader = new DiviPageLoader(self::schema());
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'), ['post_status' => 'trash']);
|
||||
$loader = new DiviPageLoader(DiviFixtures::schema());
|
||||
|
||||
self::assertInstanceOf(DiviPage::class, $loader->load(7, false));
|
||||
self::assertSame('lit_validation_failed', $loader->load(7, true)->get_error_code());
|
||||
@@ -99,18 +67,18 @@ final class DiviPageLoaderTest extends TestCase
|
||||
|
||||
public function testWritableChecks(): void
|
||||
{
|
||||
$loader = new DiviPageLoader(self::schema(false));
|
||||
self::givenPost('');
|
||||
$loader = new DiviPageLoader(DiviFixtures::schema(false));
|
||||
DiviFixtures::givenPost('');
|
||||
$empty = $loader->load(7, true);
|
||||
self::assertSame('lit_unsupported', $loader->writable($empty)->get_error_code());
|
||||
|
||||
$loader = new DiviPageLoader(self::schema());
|
||||
self::givenPost("<!-- wp:paragraph -->\n<p>Gutenberg</p>\n<!-- /wp:paragraph -->");
|
||||
$loader = new DiviPageLoader(DiviFixtures::schema());
|
||||
DiviFixtures::givenPost("<!-- wp:paragraph -->\n<p>Gutenberg</p>\n<!-- /wp:paragraph -->");
|
||||
$gutenberg = $loader->load(7, true);
|
||||
self::assertFalse($gutenberg->isDiviLayout());
|
||||
self::assertStringContainsString('kein Divi-Layout', $loader->writable($gutenberg)->get_error_message());
|
||||
|
||||
self::givenPost('', ['post_status' => 'future', 'post_date_gmt' => '2020-01-01 00:00:00']);
|
||||
DiviFixtures::givenPost('', ['post_status' => 'future', 'post_date_gmt' => '2020-01-01 00:00:00']);
|
||||
$missed = $loader->load(7, true);
|
||||
self::assertTrue($missed->isDiviLayout());
|
||||
self::assertSame('lit_validation_failed', $loader->writable($missed)->get_error_code());
|
||||
|
||||
@@ -8,7 +8,7 @@ use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviNodeGetAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviOutlineAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPageLoader;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use stdClass;
|
||||
@@ -18,16 +18,16 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
private function design(): DesignSystemReader
|
||||
{
|
||||
$reader = Mockery::mock(DesignSystemReader::class);
|
||||
$reader->allows('read')->andReturn(DesignSystemTest::sample());
|
||||
$reader->allows('read')->andReturn(DiviFixtures::designSystem());
|
||||
|
||||
return $reader;
|
||||
}
|
||||
|
||||
public function testOutlineListsNodesWithTreeRevAndPostRev(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
|
||||
self::assertTrue($ability->permission(['post_id' => 7]));
|
||||
$result = $ability->execute(['post_id' => 7]);
|
||||
@@ -46,8 +46,8 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
/** Ruling S18: the "limit" input caps children per parent; "truncated" reports the cut. */
|
||||
public function testOutlineBreadthLimitTruncatesAndReportsIt(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'));
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
|
||||
$result = $ability->execute(['post_id' => 7, 'id' => 's0.r0.c1', 'limit' => 2]);
|
||||
|
||||
@@ -58,8 +58,8 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
|
||||
public function testOutlineOfASubtreeAndUnknownNode(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'));
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
|
||||
$result = $ability->execute(['post_id' => 7, 'id' => 's1', 'depth' => 1]);
|
||||
self::assertSame(['s1', 's1.r0'], array_column($result['nodes'], 'id'));
|
||||
@@ -71,8 +71,8 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
|
||||
public function testOutlineValidatesTheSubtreeId(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'));
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
|
||||
self::assertSame(
|
||||
'lit_validation_failed',
|
||||
@@ -82,11 +82,11 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
|
||||
public function testOutlineHintsForEmptyAndReadOnlyContent(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost('');
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
DiviFixtures::givenPost('');
|
||||
$ability = new DiviOutlineAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
self::assertStringContainsString('lit-divi-insert', $ability->execute(['post_id' => 7])['hints'][0]);
|
||||
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-mixed.html'));
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-mixed.html'));
|
||||
$hints = $ability->execute(['post_id' => 7])['hints'];
|
||||
self::assertStringContainsString('nur lesbar', $hints[0]);
|
||||
self::assertStringContainsString('nur als Ganzes', $hints[0]);
|
||||
@@ -94,8 +94,8 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
|
||||
public function testNodeGetReturnsFullFormShortformAndPresets(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$ability = new DiviNodeGetAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'));
|
||||
$ability = new DiviNodeGetAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
|
||||
$heading = $ability->execute(['post_id' => 7, 'id' => 's0.r0.c1.m0']);
|
||||
|
||||
@@ -117,8 +117,8 @@ final class DiviReadAbilitiesTest extends TestCase
|
||||
|
||||
public function testNodeGetValidatesTheId(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$ability = new DiviNodeGetAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design());
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'));
|
||||
$ability = new DiviNodeGetAbility(new DiviPageLoader(DiviFixtures::schema()), $this->design());
|
||||
|
||||
self::assertSame('lit_validation_failed', $ability->execute(['post_id' => 7, 'id' => 'hero'])->get_error_code());
|
||||
self::assertSame('lit_not_found', $ability->execute(['post_id' => 7, 'id' => 's5.r0'])->get_error_code());
|
||||
|
||||
@@ -7,21 +7,14 @@ namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\Abilities\WriteFailed;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
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\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviComposition;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPageLoader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviReplaceTextAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviWriter;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Compose\ComposeFixture;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Schema\ModuleCatalogTest;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use RuntimeException;
|
||||
@@ -47,29 +40,10 @@ final class DiviReplaceTextAbilityTest extends TestCase
|
||||
/** @param list<int> $ids Rows of the prefilter query. */
|
||||
private function ability(?string $content = null, bool $unfiltered = false, array $ids = [7]): DiviReplaceTextAbility
|
||||
{
|
||||
$this->post = DiviPageLoaderTest::givenPost($content ?? DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$this->post = DiviFixtures::givenPost($content ?? DiviFixtures::markup('synthetic-basic.html'));
|
||||
Functions\when('get_post_type_object')->justReturn((object) ['cap' => (object) ['edit_posts' => 'edit_pages', 'edit_others_posts' => 'edit_others_pages']]);
|
||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.test/?page_id=7&preview=true');
|
||||
$schema = DiviPageLoaderTest::schema();
|
||||
$modules = Mockery::mock(DiviModules::class);
|
||||
$modules->allows('catalog')->andReturn(ModuleCatalogTest::sampleCatalog());
|
||||
$modules->allows('builderVersion')->andReturn('5.2.1');
|
||||
$design = Mockery::mock(DesignSystemReader::class);
|
||||
$design->allows('read')->andReturn(DesignSystemTest::sample());
|
||||
$composition = new DiviComposition($modules, $design, ComposeFixture::sanitizer($unfiltered), ComposeFixture::media());
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->allows('save')->andReturnUsing(function (WP_Post $post, string $content): array {
|
||||
$failure = array_shift($this->failures);
|
||||
if ($failure !== null) {
|
||||
throw $failure;
|
||||
}
|
||||
$this->saved[] = $content;
|
||||
$post->post_content = $content;
|
||||
|
||||
return ['revision_id' => 811, 'warnings' => []];
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(4711);
|
||||
$schema = DiviFixtures::schema();
|
||||
$loader = new DiviPageLoader($schema);
|
||||
$db = Mockery::mock(\wpdb::class)->makePartial();
|
||||
$db->allows('get_col')->andReturnUsing(function (string $sql) use ($ids): array {
|
||||
@@ -81,7 +55,7 @@ final class DiviReplaceTextAbilityTest extends TestCase
|
||||
return new DiviReplaceTextAbility(
|
||||
$schema,
|
||||
$loader,
|
||||
new DiviWriter($loader, $saver, $log, $design, $composition),
|
||||
DiviWriterFixture::writer($this->saved, $this->failures, $unfiltered, $loader),
|
||||
$db
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,26 +6,19 @@ namespace LIT\MCP\Tests\Unit\Integrations\Divi\Pages;
|
||||
|
||||
use Brain\Monkey\Functions;
|
||||
use LIT\MCP\Abilities\Rev;
|
||||
use LIT\MCP\ChangeLog\ChangeLog;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\AttrMap;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\NodeIndex;
|
||||
use LIT\MCP\Integrations\Divi\BlockTree\Parser;
|
||||
use LIT\MCP\Integrations\Divi\Design\DesignSystemReader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviComposition;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviDeleteAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviDuplicateNodeAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviInsertAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviMoveAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviPageLoader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviUpdateAbility;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviWriter;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Compose\ComposeFixture;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Schema\ModuleCatalogTest;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Error;
|
||||
use WP_Post;
|
||||
|
||||
@@ -42,34 +35,10 @@ final class DiviWriteAbilitiesTest extends TestCase
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->original = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
$this->post = DiviPageLoaderTest::givenPost($this->original);
|
||||
$this->original = DiviFixtures::markup('synthetic-basic.html');
|
||||
$this->post = DiviFixtures::givenPost($this->original);
|
||||
Functions\when('get_preview_post_link')->justReturn('https://kunde.test/?page_id=7&preview=true');
|
||||
|
||||
$modules = Mockery::mock(DiviModules::class);
|
||||
$modules->allows('catalog')->andReturn(ModuleCatalogTest::sampleCatalog());
|
||||
$modules->allows('builderVersion')->andReturn('5.2.1');
|
||||
$design = Mockery::mock(DesignSystemReader::class);
|
||||
$design->allows('read')->andReturn(DesignSystemTest::sample());
|
||||
$composition = new DiviComposition($modules, $design, ComposeFixture::sanitizer(), ComposeFixture::media());
|
||||
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->allows('save')->andReturnUsing(function (WP_Post $post, string $content): array {
|
||||
$this->saved[] = $content;
|
||||
$post->post_content = $content;
|
||||
|
||||
return ['revision_id' => 811, 'warnings' => []];
|
||||
});
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
$log->allows('record')->andReturn(4711);
|
||||
|
||||
$this->writer = new DiviWriter(
|
||||
new DiviPageLoader(DiviPageLoaderTest::schema()),
|
||||
$saver,
|
||||
$log,
|
||||
$design,
|
||||
$composition
|
||||
);
|
||||
$this->writer = DiviWriterFixture::writer($this->saved);
|
||||
}
|
||||
|
||||
private function treeRev(): string
|
||||
@@ -274,7 +243,7 @@ final class DiviWriteAbilitiesTest extends TestCase
|
||||
/** StructureRules apply on move: a module directly into a section, or into a specialty column. */
|
||||
public function testMoveRefusedByStructureRules(): void
|
||||
{
|
||||
$mixed = DiviPageLoaderTest::fixture('synthetic-mixed.html');
|
||||
$mixed = DiviFixtures::markup('synthetic-mixed.html');
|
||||
$this->post->post_content = $mixed;
|
||||
$treeRev = Rev::of($mixed);
|
||||
|
||||
@@ -342,7 +311,7 @@ final class DiviWriteAbilitiesTest extends TestCase
|
||||
/** An opaque/global module is removed as a whole – it never gets descended into. */
|
||||
public function testDeleteRemovesAnOpaqueGlobalModuleAsAWhole(): void
|
||||
{
|
||||
$mixed = DiviPageLoaderTest::fixture('synthetic-mixed.html');
|
||||
$mixed = DiviFixtures::markup('synthetic-mixed.html');
|
||||
$this->post->post_content = $mixed;
|
||||
$globalRow = '<!-- wp:divi/row {"globalModule":"913","module":{"meta":{"adminLabel":{"desktop":{"value":'
|
||||
. '"Globale Zeile"}}}}} --><!-- wp:divi/column {"builderVersion":"5.2.1"} --><!-- wp:divi/text '
|
||||
@@ -360,7 +329,7 @@ final class DiviWriteAbilitiesTest extends TestCase
|
||||
|
||||
public function testDeletingTheLastChildLeavesAValidTree(): void
|
||||
{
|
||||
$mixed = DiviPageLoaderTest::fixture('synthetic-mixed.html');
|
||||
$mixed = DiviFixtures::markup('synthetic-mixed.html');
|
||||
$this->post->post_content = $mixed;
|
||||
|
||||
$result = $this->delete()->execute([
|
||||
@@ -443,7 +412,7 @@ final class DiviWriteAbilitiesTest extends TestCase
|
||||
/** A global module copy stays a byte-identical reference (read-only nodes move/duplicate as a whole). */
|
||||
public function testDuplicateGlobalModuleCopyIsAByteIdenticalReference(): void
|
||||
{
|
||||
$mixed = DiviPageLoaderTest::fixture('synthetic-mixed.html');
|
||||
$mixed = DiviFixtures::markup('synthetic-mixed.html');
|
||||
$this->post->post_content = $mixed;
|
||||
$globalRow = '<!-- wp:divi/row {"globalModule":"913","module":{"meta":{"adminLabel":{"desktop":{"value":'
|
||||
. '"Globale Zeile"}}}}} --><!-- wp:divi/column {"builderVersion":"5.2.1"} --><!-- wp:divi/text '
|
||||
@@ -528,7 +497,7 @@ final class DiviWriteAbilitiesTest extends TestCase
|
||||
|
||||
public function testReadOnlyNodesCannotBeUpdated(): void
|
||||
{
|
||||
$this->post->post_content = DiviPageLoaderTest::fixture('synthetic-mixed.html');
|
||||
$this->post->post_content = DiviFixtures::markup('synthetic-mixed.html');
|
||||
|
||||
$result = $this->update()->execute([
|
||||
'post_id' => 7,
|
||||
|
||||
@@ -17,10 +17,8 @@ use LIT\MCP\Integrations\Divi\Pages\DiviPageLoader;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviSaver;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DiviWriter;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Integrations\Divi\Schema\DiviModules;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Compose\ComposeFixture;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Schema\ModuleCatalogTest;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Support\DiviWriterFixture;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use Mockery;
|
||||
use WP_Post;
|
||||
@@ -32,45 +30,41 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
private function writer(DiviSaver $saver, ChangeLog $log): DiviWriter
|
||||
{
|
||||
$modules = Mockery::mock(DiviModules::class);
|
||||
$modules->allows('catalog')->andReturn(ModuleCatalogTest::sampleCatalog());
|
||||
$modules->allows('builderVersion')->andReturn('5.2.1');
|
||||
$design = Mockery::mock(DesignSystemReader::class);
|
||||
$design->allows('read')->andReturn(DesignSystemTest::sample());
|
||||
$design = DiviWriterFixture::designReader();
|
||||
$registry = new DynamicContentMap(function (int $postId): array {
|
||||
$this->registryCalls[] = $postId;
|
||||
|
||||
return DynamicContentMapTest::registry();
|
||||
return DiviFixtures::dynamicContentRegistry();
|
||||
});
|
||||
|
||||
return new DiviWriter(
|
||||
new DiviPageLoader(DiviPageLoaderTest::schema()),
|
||||
new DiviPageLoader(DiviFixtures::schema()),
|
||||
$saver,
|
||||
$log,
|
||||
$design,
|
||||
new DiviComposition($modules, $design, ComposeFixture::sanitizer(), ComposeFixture::media(), $registry)
|
||||
DiviWriterFixture::composition($design, false, $registry)
|
||||
);
|
||||
}
|
||||
|
||||
public function testPageChecksTheTreeRevLock(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$writer = $this->writer(Mockery::mock(DiviSaver::class), Mockery::mock(ChangeLog::class));
|
||||
|
||||
self::assertInstanceOf(DiviPage::class, $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]));
|
||||
self::assertSame('lit_rev_mismatch', $writer->page(['post_id' => 7])->get_error_code());
|
||||
$stale = $writer->page(['post_id' => 7, 'tree_rev' => Rev::ofPost(DiviPageLoaderTest::givenPost($content))]);
|
||||
$stale = $writer->page(['post_id' => 7, 'tree_rev' => Rev::ofPost(DiviFixtures::givenPost($content))]);
|
||||
self::assertSame('lit_rev_mismatch', $stale->get_error_code(), 'the post rev is no tree_rev');
|
||||
self::assertStringContainsString('nichts wurde', $stale->get_error_message());
|
||||
}
|
||||
|
||||
public function testPageRefusesWhatIsNotWritable(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$writer = new DiviWriter(
|
||||
new DiviPageLoader(DiviPageLoaderTest::schema(false)),
|
||||
new DiviPageLoader(DiviFixtures::schema(false)),
|
||||
Mockery::mock(DiviSaver::class),
|
||||
Mockery::mock(ChangeLog::class),
|
||||
Mockery::mock(DesignSystemReader::class),
|
||||
@@ -82,8 +76,8 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
public function testSectionLabelOfANode(): void
|
||||
{
|
||||
DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html'));
|
||||
$page = (new DiviPageLoader(DiviPageLoaderTest::schema()))->load(7, true);
|
||||
DiviFixtures::givenPost(DiviFixtures::markup('synthetic-basic.html'));
|
||||
$page = (new DiviPageLoader(DiviFixtures::schema()))->load(7, true);
|
||||
|
||||
self::assertSame('Hero', DiviWriter::sectionLabel($page->index, $page->index->find('s0.r0.c1')));
|
||||
self::assertSame('', DiviWriter::sectionLabel($page->index, null));
|
||||
@@ -91,8 +85,8 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
public function testCompositionIsBoundToThePage(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$writer = $this->writer(Mockery::mock(DiviSaver::class), Mockery::mock(ChangeLog::class));
|
||||
$page = $writer->page(['post_id' => 7, 'tree_rev' => Rev::of($content)]);
|
||||
|
||||
@@ -103,8 +97,8 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
public function testUnchangedTreeIsNotSaved(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->expects('save')->never();
|
||||
$writer = $this->writer($saver, Mockery::mock(ChangeLog::class));
|
||||
@@ -118,13 +112,13 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
public function testSavesAndReportsChangedNodesOutlineAndTheNewTreeRev(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$stored = null;
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->expects('save')->andReturnUsing(static function (WP_Post $post, string $new) use (&$stored): array {
|
||||
$stored = $new;
|
||||
DiviPageLoaderTest::givenPost($new);
|
||||
DiviFixtures::givenPost($new);
|
||||
|
||||
return ['revision_id' => 811, 'warnings' => ['vom Speichern']];
|
||||
});
|
||||
@@ -163,13 +157,13 @@ final class DiviWriterTest extends TestCase
|
||||
self::assertStringNotContainsString('Leistungen', (string) $result['outline'], 'only affected sections');
|
||||
self::assertContains('eigene Warnung', $result['warnings']);
|
||||
self::assertContains('vom Speichern', $result['warnings']);
|
||||
self::assertSame(Rev::ofPost(DiviPageLoaderTest::givenPost($stored)), $result['rev']);
|
||||
self::assertSame(Rev::ofPost(DiviFixtures::givenPost($stored)), $result['rev']);
|
||||
}
|
||||
|
||||
public function testFailedRollbackIsLoggedAsPartial(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->allows('save')->andThrow(WriteFailed::partial(DiviSaver::REASON, postId: 7, revisionId: 811));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
@@ -184,8 +178,8 @@ final class DiviWriterTest extends TestCase
|
||||
|
||||
public function testCleanFailureIsNotLogged(): void
|
||||
{
|
||||
$content = DiviPageLoaderTest::fixture('synthetic-basic.html');
|
||||
DiviPageLoaderTest::givenPost($content);
|
||||
$content = DiviFixtures::markup('synthetic-basic.html');
|
||||
DiviFixtures::givenPost($content);
|
||||
$saver = Mockery::mock(DiviSaver::class);
|
||||
$saver->allows('save')->andThrow(WriteFailed::rolledBack(DiviSaver::REASON, postId: 7, revisionId: 811));
|
||||
$log = Mockery::mock(ChangeLog::class);
|
||||
|
||||
@@ -8,71 +8,16 @@ use InvalidArgumentException;
|
||||
use LIT\MCP\Integrations\Divi\Compose\Placeholders;
|
||||
use LIT\MCP\Integrations\Divi\Compose\VariableRef;
|
||||
use LIT\MCP\Integrations\Divi\Pages\DynamicContentMap;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Compose\ComposeFixture;
|
||||
use LIT\MCP\Tests\Unit\Integrations\Divi\Design\DesignSystemTest;
|
||||
use LIT\MCP\Tests\Support\ComposeFixture;
|
||||
use LIT\MCP\Tests\Support\DiviFixtures;
|
||||
use LIT\MCP\Tests\Unit\TestCase;
|
||||
use RuntimeException;
|
||||
|
||||
final class DynamicContentMapTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Shape of DynamicContentOptions::get_options($pageId, 'edit') in Divi 5.2.1 (excerpt of a
|
||||
* live dump for a page: no post_categories/post_tags – pages have no such taxonomies).
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
public static function registry(): array
|
||||
{
|
||||
$text = static fn (): array => ['label' => 'x', 'type' => 'text', 'default' => ''];
|
||||
$option = static fn (string $id, string $group, array $fields): array => [
|
||||
'id' => $id, 'label' => $id, 'type' => 'text', 'custom' => false, 'group' => $group, 'fields' => $fields,
|
||||
];
|
||||
|
||||
return [
|
||||
'post_title' => $option('post_title', 'Default', ['before' => $text(), 'after' => $text()]),
|
||||
'post_excerpt' => $option('post_excerpt', 'Default', [
|
||||
'before' => $text(), 'after' => $text(), 'words' => $text(), 'read_more_label' => $text(),
|
||||
]),
|
||||
'post_date' => $option('post_date', 'Default', [
|
||||
'before' => $text(),
|
||||
'after' => $text(),
|
||||
'date_format' => ['label' => 'x', 'type' => 'select', 'default' => 'default'],
|
||||
'custom_date_format' => $text(),
|
||||
]),
|
||||
'post_author' => $option('post_author', 'Default', [
|
||||
'before' => $text(),
|
||||
'after' => $text(),
|
||||
'name_format' => ['type' => 'select'],
|
||||
'link' => ['type' => 'yes_no_button'],
|
||||
]),
|
||||
'site_title' => $option('site_title', 'Default', ['before' => $text(), 'after' => $text()]),
|
||||
'post_link_url' => $option('post_link_url', 'Default', []),
|
||||
'post_link_url_page' => $option('post_link_url_page', 'Default', ['post_id' => ['type' => 'select_post']]),
|
||||
'post_featured_image' => $option('post_featured_image', 'Default', []),
|
||||
'post_meta_key' => $option('post_meta_key', 'Standard', [
|
||||
'before' => $text(),
|
||||
'after' => $text(),
|
||||
'select_meta_key' => ['type' => 'select'],
|
||||
'meta_key' => $text(),
|
||||
'enable_html' => ['type' => 'yes_no_button'],
|
||||
]),
|
||||
'loop_post_title' => $option('loop_post_title', 'Loop', [
|
||||
'before' => $text(), 'after' => $text(), 'loop_position' => $text(),
|
||||
]),
|
||||
'loop_post_meta_key_manual_custom_field' => $option('loop_post_meta_key_manual_custom_field', 'Loop', [
|
||||
'loop_meta_key' => $text(),
|
||||
]),
|
||||
// Odd entries a third-party filter could add.
|
||||
'broken_fields' => $option('broken_fields', 'Default', ['a' => 'not-an-array', 'b' => ['type' => 3]]),
|
||||
'no_fields' => ['id' => 'no_fields', 'type' => 'text'],
|
||||
7 => $option('7', 'Default', []),
|
||||
'not_an_array' => 'x',
|
||||
];
|
||||
}
|
||||
|
||||
public function testFlattensTheRegistryToOptionNameAndFieldTypes(): void
|
||||
{
|
||||
$map = DynamicContentMap::fromOptions(self::registry());
|
||||
$map = DynamicContentMap::fromOptions(DiviFixtures::dynamicContentRegistry());
|
||||
|
||||
// before/after: rich text (Divi outputs them as HTML; text() would trim "Von ").
|
||||
self::assertSame(['before' => 'richtext', 'after' => 'richtext'], $map['post_title']);
|
||||
@@ -92,7 +37,7 @@ final class DynamicContentMapTest extends TestCase
|
||||
|
||||
public function testLoopOptionsNeverEnterTheMap(): void
|
||||
{
|
||||
$map = DynamicContentMap::fromOptions(self::registry());
|
||||
$map = DynamicContentMap::fromOptions(DiviFixtures::dynamicContentRegistry());
|
||||
|
||||
self::assertSame([], array_filter(array_keys($map), static fn (string $name): bool => str_starts_with($name, 'loop_')));
|
||||
}
|
||||
@@ -101,7 +46,7 @@ final class DynamicContentMapTest extends TestCase
|
||||
{
|
||||
// The map replaces VariableRef's default: every {{post:…}} placeholder must stay usable
|
||||
// with the settings it writes (before/after), also where the registry lacks the option.
|
||||
$map = DynamicContentMap::fromOptions(self::registry());
|
||||
$map = DynamicContentMap::fromOptions(DiviFixtures::dynamicContentRegistry());
|
||||
|
||||
foreach (Placeholders::POST as $option) {
|
||||
self::assertArrayHasKey($option, $map, $option);
|
||||
@@ -115,7 +60,7 @@ final class DynamicContentMapTest extends TestCase
|
||||
self::assertSame('select', $map['post_date']['date_format']);
|
||||
self::assertSame('text', $map['post_excerpt']['words']);
|
||||
|
||||
$placeholders = new Placeholders(DesignSystemTest::sample(), $map);
|
||||
$placeholders = new Placeholders(DiviFixtures::designSystem(), $map);
|
||||
foreach (array_keys(Placeholders::POST) as $key) {
|
||||
$reference = $placeholders->resolve('{{post:' . $key . '}}');
|
||||
self::assertSame(
|
||||
@@ -128,7 +73,7 @@ final class DynamicContentMapTest extends TestCase
|
||||
|
||||
public function testTheMapWorksInVariableRef(): void
|
||||
{
|
||||
$references = new VariableRef(DesignSystemTest::sample(), DynamicContentMap::fromOptions(self::registry()));
|
||||
$references = new VariableRef(DiviFixtures::designSystem(), DynamicContentMap::fromOptions(DiviFixtures::dynamicContentRegistry()));
|
||||
$sanitizer = ComposeFixture::sanitizer();
|
||||
$ref = static fn (string $name, array $settings): string => VariableRef::serialize('content', $name, $settings);
|
||||
|
||||
@@ -164,7 +109,7 @@ final class DynamicContentMapTest extends TestCase
|
||||
$map = (new DynamicContentMap(static function (int $postId) use (&$seen): array {
|
||||
$seen[] = $postId;
|
||||
|
||||
return DynamicContentMapTest::registry();
|
||||
return DiviFixtures::dynamicContentRegistry();
|
||||
}))->forPost(42);
|
||||
|
||||
self::assertSame([42], $seen);
|
||||
|
||||
Reference in New Issue
Block a user