Skip to content

test(youtube): assert the rendered anchor, and teach the shim href/src - #567

Merged
PathGao merged 1 commit into
masterfrom
test/youtube-behavior
Aug 10, 2026
Merged

test(youtube): assert the rendered anchor, and teach the shim href/src#567
PathGao merged 1 commit into
masterfrom
test/youtube-behavior

Conversation

@PathGao

@PathGao PathGao commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

What this is

Third slice of the source-shape → behaviour conversion (after #564, #565). Test files only.

  • youtubeExternalFallback.test.ts — rewritten to render documents and look at the output.
  • renderProtocolDom.ts — the shim now reflects href and src into attributes, as a browser does.

Mechanism

The old file made six assertions about how replaceWithYoutubeLink is written: its exact signature, link.className = 'youtube-link', link.href = href, the thumbnail URL template, the call site, and doesNotMatch(/createElement\(["']iframe["']\)/). None of them rendered a document.

What that missed is not subtle. Two decisions make this feature bearable and neither was covered:

  • Only a paragraph that is nothing but the link becomes a poster. A link in the middle of a sentence stays a link — otherwise prose gets rewritten into a 480px thumbnail.
  • An id that is not 11 characters is left alone, rather than becoming an anchor wrapped around a thumbnail URL that 404s.

Both are now tested, along with all four recognised URL spellings. youtube.com/embed/ earns its own case: it is the URL people paste out of an embed snippet, so it is the one most likely to be missed if the detection list is ever split.

The shim change

replaceWithYoutubeLink sets link.href = href and thumbnail.src = … as properties. A browser reflects those into attributes; renderProtocolDom had accessors for id and className and nothing else, so the assignment landed on a plain JS property, never reached getAttribute, and never reached the serialized HTML:

<p><a class="youtube-link" aria-label="Open YouTube video in browser"><img></a></p>

An anchor with no href and an image with no src. Every existing shim-based test was blind to where a link points, which is the entire content of a link. Four accessors alongside the existing pair fixes it. The full suite — including the six other files that install the shim — passes with the change: 952 tests, 0 failures.

Scope

  • The CSP assertion is unchanged and stays source-shape. frame-src in tauri.conf.json is a contract with the packaged app, nothing type-checks it, and a frame-src that outlived the iframe is permission granted for a feature that no longer exists.
  • The click-ordering assertion stays too, because handleLinkClick lives in a Svelte component this runner cannot import — but it is now the ordering it actually claims (closest('a') resolved before closest('img')) rather than a 60-character regex over the branch bodies that any reformatting would break.
  • No source file changes.

Tests

Restoring the pre-fix renderer — createElement("iframe") in place of the anchor — turns 3 of the 7 red. Ran it, then reverted.

The two new negative cases were written against the current behaviour and checked by hand against getYoutubeId's 11-character rule and the parent.childNodes.length === 1 guard, not derived from the code by inspection alone.

Verification

npm run check   # 674 files, 0 errors
npm test        # 952 pass, 0 fail

Not verified: the shim is not a browser. href/src reflection now matches what a browser does for these two attributes specifically; the rest of the reflection surface (value, checked, htmlFor, …) is still absent, and this PR does not add it speculatively.

🤖 Generated with Claude Code

`youtubeExternalFallback` matched markdown.ts for the signature of
`replaceWithYoutubeLink`, for each assignment inside it, and for the
absence of `createElement("iframe")`. Six assertions about how one
function is written, none about what a document renders as.

It also could not see the two decisions that make the feature bearable:
only a paragraph that is *nothing but* the link becomes a poster (a link
mid-sentence stays a link), and an id that is not 11 characters is left
alone rather than turned into an anchor around a thumbnail that 404s.
Both are now covered, along with the four recognised URL spellings —
`youtube.com/embed/` in particular, since that is the one people paste
out of an embed snippet.

The CSP assertion stays as it is: `frame-src` in tauri.conf.json is a
contract with the packaged app, and nothing type-checks it. The click
ordering in MarkdownViewer stays too, but as the ordering it actually
claims — `closest('a')` before `closest('img')` — rather than a 60
character regex over the branch bodies.

renderProtocolDom gains `href` and `src` reflection. A browser writes the
attribute when you assign the property, so `link.href = url` is visible
to getAttribute and survives serialization; the shim dropped it on the
floor, which left every test blind to where a link points — the whole
content of a link. Four accessors next to the existing `id` and
`className` ones. All 952 tests pass with it, including the six other
files that use the shim.

Reverting to `createElement("iframe")` turns three of the seven red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@PathGao
PathGao merged commit 2c2c1a8 into master Aug 10, 2026
4 checks passed
@PathGao
PathGao deleted the test/youtube-behavior branch August 10, 2026 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant