allows('read')->andReturn(DesignSystemTest::sample()); return $reader; } public function testOutlineListsNodesWithTreeRevAndPostRev(): void { $content = DiviPageLoaderTest::fixture('synthetic-basic.html'); DiviPageLoaderTest::givenPost($content); $ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design()); self::assertTrue($ability->permission(['post_id' => 7])); $result = $ability->execute(['post_id' => 7]); self::assertSame(substr(hash('sha256', $content), 0, 12), $result['tree_rev']); self::assertSame(12, strlen($result['rev'])); self::assertNotSame($result['tree_rev'], $result['rev']); self::assertCount(16, $result['nodes']); self::assertStringStartsWith('s0 section "Hero"', $result['outline']); self::assertSame([], $result['hints']); self::assertTrue($ability->isDirect()); self::assertTrue($ability->annotations()['readonly']); } public function testOutlineOfASubtreeAndUnknownNode(): void { DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html')); $ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design()); $result = $ability->execute(['post_id' => 7, 'id' => 's1', 'depth' => 1]); self::assertSame(['s1', 's1.r0'], array_column($result['nodes'], 'id')); $missing = $ability->execute(['post_id' => 7, 'id' => 's7']); self::assertSame('lit_not_found', $missing->get_error_code()); self::assertStringContainsString('tree_rev', $missing->get_error_message()); } public function testOutlineValidatesTheSubtreeId(): void { DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html')); $ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design()); self::assertSame( 'lit_validation_failed', $ability->execute(['post_id' => 7, 'id' => 'hero'])->get_error_code() ); } public function testOutlineHintsForEmptyAndReadOnlyContent(): void { DiviPageLoaderTest::givenPost(''); $ability = new DiviOutlineAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design()); self::assertSame(['Die Seite hat noch keinen Divi-Inhalt.'], $ability->execute(['post_id' => 7])['hints']); DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-mixed.html')); $hints = $ability->execute(['post_id' => 7])['hints']; self::assertStringContainsString('nur lesbar', $hints[0]); } public function testNodeGetReturnsFullFormShortformAndPresets(): void { DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html')); $ability = new DiviNodeGetAbility(new DiviPageLoader(DiviPageLoaderTest::schema()), $this->design()); $heading = $ability->execute(['post_id' => 7, 'id' => 's0.r0.c1.m0']); self::assertSame('heading', $heading['type']); self::assertSame('s0.r0.c1', $heading['parent']); self::assertSame(12, strlen($heading['rev'])); self::assertSame( ['desktop' => ['value' => ['headingLevel' => 'h1', 'color' => '#1a1a1a']], 'phone' => ['value' => ['size' => '28px']]], $heading['attrs']['title.decoration.font.font'] ); self::assertSame(['text' => 'Willkommen bei Müller & Söhne', 'level' => 'h1'], $heading['shortform']); self::assertSame([['id' => 'a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d', 'name' => '']], $heading['presets']); self::assertSame('5.2.1', $heading['builder_version']); $accordion = $ability->execute(['post_id' => 7, 'id' => 's1.r0.c1.m0']); self::assertSame(['s1.r0.c1.m0.m0', 's1.r0.c1.m0.m1'], $accordion['children']); self::assertInstanceOf(stdClass::class, $accordion['shortform']); } public function testNodeGetValidatesTheId(): void { DiviPageLoaderTest::givenPost(DiviPageLoaderTest::fixture('synthetic-basic.html')); $ability = new DiviNodeGetAbility(new DiviPageLoader(DiviPageLoaderTest::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()); } }