From ce596bca7ebb5db4ee91de0a951ba128aecdc444 Mon Sep 17 00:00:00 2001 From: Simon Hamp Date: Fri, 10 Jul 2026 17:40:08 +0100 Subject: [PATCH] fix(docs): escape example Blade expression in mobile v4 Text doc The "Dynamic content" aside contained an inline `{{ $variable }}` in prose that was neither wrapped in @verbatim nor escaped. Doc .md files render through the Blade engine before markdown conversion, so Blade evaluated it and threw "Undefined variable $variable", 500ing the page. Escape it with @{{ }} (the convention already used elsewhere) so the literal renders. Adds a regression test plus a guard that renders every docs page as Blade to catch any other unescaped example expressions. Fixes #72 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../docs/mobile/4/edge-components/text.md | 2 +- tests/Feature/DocumentationRenderingTest.php | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/DocumentationRenderingTest.php diff --git a/resources/views/docs/mobile/4/edge-components/text.md b/resources/views/docs/mobile/4/edge-components/text.md index 604bb096..de099f67 100644 --- a/resources/views/docs/mobile/4/edge-components/text.md +++ b/resources/views/docs/mobile/4/edge-components/text.md @@ -152,7 +152,7 @@ Use the `dark:` prefix with Tailwind classes or pass a dark-mode color override. diff --git a/tests/Feature/DocumentationRenderingTest.php b/tests/Feature/DocumentationRenderingTest.php new file mode 100644 index 00000000..1535797b --- /dev/null +++ b/tests/Feature/DocumentationRenderingTest.php @@ -0,0 +1,72 @@ + 'test-token']); + Http::fake([ + '*' => Http::response(['blocks' => []], 200), + ]); + } + + #[Test] + public function text_page_shows_example_blade_expression_literally_instead_of_evaluating_it(): void + { + $this->withoutVite() + ->get('/docs/mobile/4/edge-components/text') + ->assertOk() + ->assertSee('{{ $variable }}'); + } + + #[Test] + public function every_documentation_page_renders_without_evaluating_example_variables(): void + { + /** @var ViewFactory $factory */ + $factory = resolve(ViewFactory::class); + $factory->addExtension('md', 'blade'); + + $base = resource_path('views/docs'); + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($base, \FilesystemIterator::SKIP_DOTS) + ); + + $failures = []; + + foreach ($iterator as $file) { + if ($file->getExtension() !== 'md' || str_starts_with($file->getBasename(), '_')) { + continue; + } + + $view = 'docs/'.substr($file->getPathname(), strlen($base) + 1, -3); + + try { + $factory->make($view, ['user' => null])->render(); + } catch (\Throwable $e) { + $failures[$view] = $e->getMessage(); + } + } + + $this->assertSame( + [], + $failures, + 'Documentation pages must escape example Blade expressions with @{{ }} or @verbatim. ' + .'These pages threw while rendering: '.json_encode($failures, JSON_PRETTY_PRINT), + ); + } +}