test: add render-regression checks to prevent #7079-class bugs#7085
Merged
jstirnaman merged 1 commit intomasterfrom Apr 9, 2026
Merged
test: add render-regression checks to prevent #7079-class bugs#7085jstirnaman merged 1 commit intomasterfrom
jstirnaman merged 1 commit intomasterfrom
Conversation
Adds four layers of coverage against the class of rendering bug reported in #7079: whitespace leaks in Hugo render hooks or wrapper shortcode templates that cause Goldmark to HTML-escape highlighted code blocks. Each layer catches the bug at a different point in the lifecycle — together they mean this specific regression can't land again without somebody actively defeating every layer. Layer 1 — Site-wide HTML grep after Hugo build .ci/scripts/check-render-artifacts.sh Scans every .html file under `public/` for three literal patterns that can only appear when a render hook leaked whitespace into its output: `<div class="highlight"`, `<pre tabindex="0"`, and `<span class="line"><span class="cl"`. Runs in ~1 second on the full built site. Catches regressions on every page automatically, including pages no test lists explicitly. Verified against a rebuild with the pre-fix render-codeblock.html from commit d80eb2f — correctly reports 54 affected files — and against the current clean build — reports 0. Layer 2 — Pre-commit lint for render hooks .ci/scripts/check-render-hook-whitespace.sh lefthook.yml: new pre-commit command `check-render-hook-whitespace` Enforces the invariant that every action tag inside `layouts/_default/_markup/render-*.html` uses `{{- ... -}}` whitespace trimming. Bare `{{ ... }}` actions leak their surrounding indent and newline into the render-hook output; the lint catches this at commit time, before a PR is even opened. Scoped narrowly to render hooks so it doesn't nag on normal Hugo templates where bare actions are fine. Also hardens render-codeblock.html lines 1 and 19, which had bare `{{ ... }}` actions that happened to work correctly because surrounding `{{- ... -}}` operators trimmed their whitespace by accident. The lint flagged them as fragile; rewriting them as `{{- ... -}}` makes the file unconditionally correct and lets the lint ship with no exceptions. Layer 3 — Cypress render-regression spec cypress/e2e/content/render-regression.cy.js package.json: `test:render-regression`, `test:render-artifacts` DOM-level assertion that no `pre > code` element on a curated page list contains the escaped chroma fragments. Two sections: * Shortcode examples page (/example/) — a single exhaustive shortcode fixture that covers every render-hook combination documented in the site. * Representative product pages — one page per InfluxDB 3 edition, hand-picked for the wrapper/attribute combination it exercises: - core/reference/sample-data (placeholders + custom-timestamps + code-tab-content) - enterprise/admin/backup-restore (placeholders inside tab-content — the page that regressed worst in #7079) - cloud-dedicated/reference/sample-data (placeholders with regex grouping inside custom-timestamps) - clustered/admin/users/add (placeholders + callouts in nested expand wrappers) - cloud-serverless/reference/sample-data (post-migration fence-attribute syntax) Layer 4 — Example page coverage for the render-hook attributes content/example.md: new "Render-regression fixtures" section Adds fence-attribute and wrapper fixtures that exercise every code path implicated in #7079: `placeholders=` with and without regex grouping, `callout=` with default and explicit color, combined `placeholders=` + `callout=`, placeholder fences inside `influxdb/custom-timestamps`, and the worst-case nested shape (expand > code-tabs > code-tab-content > custom-timestamps > placeholder fence) that every sample-data page uses. Before this commit `content/example.md` had zero uses of either attribute, which meant the shortcode-examples smoke test was blind to #7079-class bugs. Verified after rebuild: 11 placeholder wrappers, 3 callouts, and 3 custom-timestamps wrappers render on /example/. CI workflow .github/workflows/pr-render-check.yml Runs on every pull_request. Two jobs: * check-artifacts: Unconditional site-wide grep on every PR. * cypress-render: Cypress spec, gated on a path filter that only triggers when the PR touches layouts/, assets/, the render-regression spec itself, the check-artifacts script, or this workflow file. The unconditional grep is the backstop — it runs even on content-only PRs and catches any regression anywhere in the site. Cypress runs on the subset of PRs that can actually cause this class of bug. Refs #7079
Contributor
Vale Style Check Results
✅ Check passed |
Contributor
|
17 tasks
Contributor
Author
|
👍 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds four layers of coverage to prevent the class of rendering regression reported in #7079 (whitespace leaks in Hugo render hooks or wrapper shortcode templates causing Goldmark to HTML-escape highlighted code blocks). Each layer catches the bug at a different point in the lifecycle — together they mean this specific regression can't land again without actively defeating every layer.
What shipped
Layer 1 — Site-wide HTML grep after Hugo build
.ci/scripts/check-render-artifacts.shScans every
.htmlfile underpublic/for three literal patterns that can only appear when a render hook has leaked whitespace into its output:<div class="highlight"<pre tabindex="0"<span class="line"><span class="cl"Runs in ~1 second on the full built site. Zero curation required — any page anywhere in the site is covered automatically. Verified against a rebuild with the pre-fix
render-codeblock.htmlfrom commitd80eb2f(correctly reports 54 affected files) and against the current clean build (reports 0).Layer 2 — Pre-commit lint for render hooks
.ci/scripts/check-render-hook-whitespace.sh+ newcheck-render-hook-whitespacecommand inlefthook.ymlEnforces the invariant that every action tag inside
layouts/_default/_markup/render-*.htmluses{{- ... -}}whitespace trimming. Bare{{ ... }}actions leak their surrounding indent and newline into the render-hook output — the exact mechanism that caused #7079. The lint catches this at commit time, before a PR is even opened. Scoped narrowly to render hook files so it doesn't nag on normal Hugo templates where bare actions are fine.Also hardens
render-codeblock.htmllines 1 and 19, which had bare{{ ... }}actions that happened to work correctly because surrounding{{- ... -}}operators trimmed their whitespace by accident. Rewriting them as{{- ... -}}makes the file unconditionally correct and lets the lint ship with no exceptions.Layer 3 — Cypress render-regression spec
cypress/e2e/content/render-regression.cy.js, newtest:render-regressionandtest:render-artifactsnpm scriptsDOM-level assertion that no
pre > codeelement on a curated page list contains the escaped chroma fragments. Twodescribeblocks:Shortcode examples page (
/example/) — exhaustive shortcode showcase. Any layout/render-hook change that breaks a documented shortcode will show up here, regardless of which product it affects.Representative product pages — one page per InfluxDB 3 edition, hand-picked for the wrapper/attribute combination it exercises:
/influxdb3/core/reference/sample-data/custom-timestampswrapper +code-tab-content/influxdb3/enterprise/admin/backup-restore/tab-content(the page that regressed worst in Broken HTML formatting in sample data pages #7079)/influxdb3/cloud-dedicated/reference/sample-data/placeholders="DATABASE_(TOKEN|NAME)"regex grouping insidecustom-timestamps/influxdb3/clustered/admin/users/add//influxdb3/cloud-serverless/reference/sample-data/Each test also asserts the page actually has highlighted code blocks (guards against a broken fixture silently passing).
Layer 4 — Example page coverage for the render-hook attributes
content/example.md: new "Render-regression fixtures" section at the end.Before this PR,
content/example.mdhad zero uses ofplaceholders=orcallout=fence attributes — which meant the shortcode-examples smoke test was structurally blind to #7079-class bugs. This PR adds fixtures for every code path the #7069 regression affected:placeholders="DATABASE_NAME|AUTH_TOKEN"(simple alternation)placeholders="DATABASE_(TOKEN|NAME)"(regex group)callout="--host"(default green)callout="--host" callout-color="magenta"(explicit color)placeholders="DATABASE_NAME" callout="--host" callout-color="orange"(both on one fence){{% influxdb/custom-timestamps %}}expand-wrapper > code-tabs-wrapper > code-tab-content > influxdb/custom-timestamps > placeholder fence(the shape every sample-data page uses)Verified after rebuild:
/example/now renders 11 placeholder wrappers, 3 callouts, and 3 custom-timestamps wrappers.CI workflow
.github/workflows/pr-render-check.ymlRuns on every
pull_request. Two jobs:check-artifacts— unconditional. Builds the site, runs the grep from layer 1. Runs even on content-only PRs and catches any regression anywhere in the site. Target runtime: <2 min.cypress-render— gated on a path filter. Only triggers when the PR toucheslayouts/,assets/, the render-regression spec itself, the check-artifacts script, or this workflow file. Runs the Cypress spec from layer 3.The unconditional grep is the backstop. Cypress runs on the subset of PRs that can actually cause this class of bug.
How the layers compose
Verification
shellcheckclean on both new scripts.check-render-hook-whitespace.shlint passes against the current (hardened)render-codeblock.htmland fails against the known-buggy pre-fix(layouts): trim whitespace in render-codeblock placeholder/callout branch #7084 version with 9 offenders reported.check-render-artifacts.shpasses against a clean build (0 artifacts) and fails against a rebuild with the pre-fix(layouts): trim whitespace in render-codeblock placeholder/callout branch #7084render-codeblock.html(54 affected files reported).content/example.mdfixtures.Not yet done / possible follow-ups
{{<,{{%,ZgotmplZ) deliberately excluded fromcheck-render-artifacts.shv1 because of pre-existing false positives (Helm template docs with literal{{content, and a separate pre-existingZgotmplZleak on ~4600 pages viadata-influxdb-urls). Script header documents the gap. Can be re-added as warnings or after those pre-existing issues are cleaned up.test:shortcode-examplesnpm script has a pre-existing mismatch: it runscypress/e2e/content/index.cy.js(which tests the home page, notexample.md). Left unchanged to keep this PR focused.Test plan
check-render-artifacts.shreports 0 on current clean buildcheck-render-artifacts.shreports 54 when rebuilt against pre-fix(layouts): trim whitespace in render-codeblock placeholder/callout branch #7084 render-codeblockcheck-render-hook-whitespace.shpasses on current template, fails on pre-fix(layouts): trim whitespace in render-codeblock placeholder/callout branch #7084 versioncontent/example.mdrenders expected number of placeholder/callout/custom-timestamps artifacts/example/Refs #7079