Skip to content

feat(assert): match a cell by its OSC 8 link - #203

Open
Ayman Bagabas (aymanbagabas) wants to merge 1 commit into
aymanbagabas/hyperlinksfrom
aymanbagabas/hyperlink-assertions
Open

feat(assert): match a cell by its OSC 8 link#203
Ayman Bagabas (aymanbagabas) wants to merge 1 commit into
aymanbagabas/hyperlinksfrom
aymanbagabas/hyperlink-assertions

Conversation

@aymanbagabas

Copy link
Copy Markdown
Member

Makes OSC 8 links assertable, not just readable.

Stacked on #181. That PR records links on cells; this one adds the assertion surface. Review #181 first.

Why

#181 makes links observable through cells --json and snapshots, but the style query has no link field. So a test that wants to check where a link points has to shell out and parse JSON:

tui-test cells 0 0 4 1 --json | jq -r '.data.cells[0].link'

That is precisely what the style query exists to avoid. --fg, --underline-color and the rest are all first-class; the link was not.

What

link joins the other style properties, so it works everywhere they already do:

tui-test expect text "Docs" --link "https://example.com"
tui-test expect text "plain" --link ""
await term.getByStyle({ link: "https://example.com" }).expect();
await term.get_by_style(TextStyle(link="https://example.com")).expect()

Because it is an ordinary style property it also composes with the within, after and before locator stages for free.

An empty string is a requirement, not an absence

--link "" asks for a cell that links nowhere. That is how a test asserts OSC 8 ;; actually closed a link, rather than only that some other link is absent — a distinction that matters because a link running to the end of the row is exactly the bug #181 found in the xterm.js shim.

The Option already carries "the caller did not ask", which leaves the inner String free to mean something. Hence Option<String> rather than a bare String with a sentinel.

Verification

Unit tests cover the matcher: matching URL, non-matching URL, empty-link-vs-linked-cell in both directions, and a style with no link still matching a linked cell (so this does not silently narrow existing queries). A CLI test pins that --link "" survives parsing as an empty string rather than collapsing to None.

Checked against a live session too, since a parse test would not catch a wiring mistake:

assertion exit
expect text "LINK" --link "https://example.com" 0
expect text "LINK" --link "https://wrong.example" 1
expect text "plain" --link "" 0
expect text "plain" --link "https://example.com" 1
expect text "LINK" --link "" 1

cargo test --workspace --features tui-test-rs/ghostty,tui-test-rs/rio,tui-test-rs/xtermjs gives 633 passed, 0 failed. cargo fmt --check and both clippy -D warnings invocations are clean.

Recording hyperlinks made them readable through `cells` and snapshots, but
not assertable: the style query had no link field, so a test that wanted to
check where a link pointed had to shell out to `cells --json` and parse it,
which is the thing the style query exists to avoid.

`link` joins the other style properties, so it works everywhere they already
do: `expect text ... --link`, `get_by_style` / `getByStyle`, and the `within`
and `after` locator stages.

An empty string is a requirement rather than an absence. `--link ""` asks for
a cell that links nowhere, which is how a test asserts that `OSC 8 ;;` closed
a link rather than merely that some other link is not present. The `Option`
already carries "the caller did not ask", so the inner `String` is free to
mean something.

Verified against a live session as well as in unit tests: the right URL
passes, a wrong URL fails, plain text with a link filter fails, and linked
text with an empty link filter fails.

Signed-off-by: Ayman Bagabas <ayman.bagabas@gmail.com>
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