Body Content
', $article->renderBody()); + $this->assertSame('Body Content
', $article->renderBody()->toHtml()); } public function testClassCanHandleDocumentWithNoHeader() { $article = $this->makeArticle('Body Content'); - $this->assertEquals('', $article->renderHeader()); - $this->assertEquals('Body Content
', $article->renderBody()); + $this->assertSame('', $article->renderHeader()->toHtml()); + $this->assertSame('Body Content
', $article->renderBody()->toHtml()); } public function testClassCanHandleDocumentWithOnlyHeader() { $article = $this->makeArticle('# Header Content'); - $this->assertEquals('Hello world.
', $article->renderBody()); + $this->assertSame('Hello world.
', $article->renderBody()->toHtml()); } public function testRenderHeaderReturnsTheExtractedHeader() @@ -214,6 +214,16 @@ public function renderHeader(): HtmlString $this->assertStringContainsString('Hello world.
', $rendered); } + public function testClassCanParseDocumentWithDisabledPermalinks() + { + config(['markdown.permalinks.enabled' => false]); + + $article = $this->makeArticle("# Header Content \n\n Body Content"); + + $this->assertSame('Body Content
', $article->renderBody()->toHtml()); + } + protected function makeArticle(string $sourceFileContents = "# Foo\n\nHello world."): SemanticDocumentationArticle { $this->file('_docs/foo.md', $sourceFileContents); diff --git a/packages/framework/tests/Feature/StaticSiteBuilderDocumentationModuleTest.php b/packages/framework/tests/Feature/StaticSiteBuilderDocumentationModuleTest.php index 9584f15907f..5f14a6ad7af 100644 --- a/packages/framework/tests/Feature/StaticSiteBuilderDocumentationModuleTest.php +++ b/packages/framework/tests/Feature/StaticSiteBuilderDocumentationModuleTest.php @@ -44,7 +44,7 @@ public function testPageContainsExpectedContent() { $this->inspectHtml([ 'Adventures in Wonderland', - 'So she was considering in her own mind, as well as she could', ]); } @@ -55,7 +55,7 @@ public function testCanCompilePageToRootOutputDirectory() $this->inspectHtml([ 'Adventures in Wonderland', - '
So she was considering in her own mind, as well as she could', ], '_site/test-page.html'); } diff --git a/packages/framework/tests/Unit/HeadingRendererUnitTest.php b/packages/framework/tests/Unit/HeadingRendererUnitTest.php new file mode 100644 index 00000000000..ef4fb697f0d --- /dev/null +++ b/packages/framework/tests/Unit/HeadingRendererUnitTest.php @@ -0,0 +1,283 @@ +createRealBladeCompilerEnvironment(); + + self::mockConfig(['markdown' => self::$cachedConfig ??= require __DIR__.'/../../config/markdown.php']); + } + + public function testCanConstruct() + { + $renderer = new HeadingRenderer(DocumentationPage::class); + $this->assertInstanceOf(HeadingRenderer::class, $renderer); + } + + public function testCanConstructWithPageClass() + { + $renderer = new HeadingRenderer(DocumentationPage::class); + $this->assertInstanceOf(HeadingRenderer::class, $renderer); + } + + public function testCanRenderHeading() + { + $childRenderer = $this->mockChildNodeRenderer(); + $renderer = new HeadingRenderer(DocumentationPage::class); + $rendered = $renderer->render(new Heading(2), $childRenderer); + + $this->assertStringContainsString('Test Heading', $rendered); + $this->assertStringContainsString('
Paragraph
'; + + $this->assertSame('Paragraph
', (new HeadingRenderer())->postProcess($html)); + } + + protected function createRealBladeCompilerEnvironment(): void + { + $resolver = new EngineResolver(); + $filesystem = new Filesystem(); + + $resolver->register('blade', function () use ($filesystem) { + return new CompilerEngine( + new BladeCompiler($filesystem, sys_get_temp_dir()) + ); + }); + + $finder = new FileViewFinder($filesystem, [realpath(__DIR__.'/../../resources/views')]); + $finder->addNamespace('hyde', realpath(__DIR__.'/../../resources/views')); + + $view = new Factory($resolver, $finder, new Dispatcher()); + + app()->instance('view', $view); + app()->instance(FactoryContract::class, $view); + } + + protected function mockChildNodeRenderer(string $contents = 'Test Heading'): ChildNodeRendererInterface + { + $childRenderer = Mockery::mock(ChildNodeRendererInterface::class); + $childRenderer->shouldReceive('renderNodes')->andReturn($contents); + + return $childRenderer; + } + + protected function validateHeadingPermalinkStates(HeadingRenderer $renderer, ChildNodeRendererInterface $childRenderer): void + { + foreach (range(1, 6) as $level) { + $rendered = $renderer->render(new Heading($level), $childRenderer); + + $shouldHavePermalink = $level >= config('markdown.permalinks.min_level') && $level <= config('markdown.permalinks.max_level'); + + if ($shouldHavePermalink) { + $this->assertStringContainsString('heading-permalink', $rendered); + } else { + $this->assertStringNotContainsString('heading-permalink', $rendered); + } + } + } +} diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index 17f982db1de..37e830b33fe 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -4,6 +4,7 @@ namespace Hyde\Framework\Testing\Unit; +use Illuminate\Contracts\View\Factory; use Mockery; use Closure; use Hyde\Hyde; @@ -150,6 +151,8 @@ public function testMarkdownReturnsRenderedPartial() $filesystem->shouldReceive('get')->with($this->includesPath($filename))->andReturn($content); }); + $this->mockViewFactory($expected); + $this->assertHtmlStringIsSame($expected, Includes::markdown($filename)); } @@ -163,6 +166,8 @@ public function testMarkdownReturnsRenderedDefaultValueWhenNotFound() $filesystem->shouldReceive('exists')->with($this->includesPath($filename))->andReturn(false); }); + $this->mockViewFactory($expected); + $this->assertNull(Includes::markdown($filename)); $this->assertHtmlStringIsSame($expected, Includes::markdown($filename, $default)); } @@ -179,6 +184,8 @@ public function testMarkdownWithAndWithoutExtension() $filesystem->shouldReceive('get')->with($this->includesPath($filename))->andReturn($content); }); + $this->mockViewFactory($expected); + $this->assertHtmlStringIsSame($expected, Includes::markdown('foo.md')); $this->assertHtmlStringIsSame(Includes::markdown('foo.md'), Includes::markdown('foo')); $this->assertHtmlStringIsSame(Includes::markdown('foo.md'), Includes::markdown('foo.md')); @@ -242,6 +249,18 @@ protected function mockFilesystemFromClosure(Closure $config): void app()->instance(Filesystem::class, $filesystem); } + protected function mockViewFactory(string $result): void + { + $viewFactory = Mockery::mock(Factory::class); + $viewFactory->shouldReceive('make') + ->andReturn(Mockery::mock([ + 'render' => $result, + ]))->byDefault(); + + app()->instance('view', $viewFactory); + app()->instance(Factory::class, $viewFactory); + } + protected function includesPath(string $filename): string { return Hyde::path('resources/includes/'.$filename); diff --git a/packages/hydefront/components/heading-permalinks.css b/packages/hydefront/components/heading-permalinks.css deleted file mode 100644 index c1add8ef904..00000000000 --- a/packages/hydefront/components/heading-permalinks.css +++ /dev/null @@ -1,20 +0,0 @@ -.prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6 { - @apply w-fit; -} - -.prose :is(h1,h2,h3,h4,h5,h6):hover .heading-permalink, -.prose :is(h1,h2,h3,h4,h5,h6):focus .heading-permalink { - @apply opacity-75 grayscale transition-opacity duration-100 ease-out; -} - -.heading-permalink { - @apply opacity-0 ml-1 transition-opacity duration-300 ease-linear px-1 scroll-m-4; -} - -.heading-permalink::before { - @apply content-['#']; -} - -.heading-permalink:hover, .heading-permalink:focus { - @apply opacity-100 grayscale-0; -} diff --git a/resources/assets/app.css b/resources/assets/app.css index 1523247f427..0b95f5d9fe4 100644 --- a/resources/assets/app.css +++ b/resources/assets/app.css @@ -11,7 +11,6 @@ * See https://hydephp.com/docs/1.x/managing-assets#loading-from-cdn */ -@import 'hydefront/components/heading-permalinks.css'; @import 'hydefront/components/torchlight.css'; @import 'hydefront/components/blockquotes.css';