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:
2026-09-26 17:47:11 +02:00
co-authored by Claude Opus 5.5
parent d2cc8497c9
commit 3d96a41366
24 changed files with 489 additions and 404 deletions
@@ -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);