Files
Triple-C/app/src/lib/urlDetector.test.ts
T

119 lines
4.2 KiB
TypeScript
Raw Normal View History

2026-08-11 10:36:30 -07:00
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { UrlDetector, flatten } from "./urlDetector";
const COLS = 80;
const enc = new TextEncoder();
/** Feed text and let the debounce + confirmation timers run. */
function feed(detector: UrlDetector, text: string) {
detector.feed(enc.encode(text));
vi.advanceTimersByTime(2000);
}
/** Hard-wrap the way a PTY does: a break every `cols` characters, nothing lost. */
function ptyWrap(text: string, cols = COLS): string {
const lines: string[] = [];
for (let i = 0; i < text.length; i += cols) lines.push(text.slice(i, i + cols));
return lines.join("\r\n");
}
beforeEach(() => vi.useFakeTimers());
afterEach(() => vi.useRealTimers());
describe("flatten", () => {
it("rejoins a break the terminal inserted at the width", () => {
expect(flatten("abcde\nfghij", 5)).toBe("abcdefghij");
});
it("keeps a break that arrived before the width as a separator", () => {
expect(flatten("abc\ndef", 5)).toBe("abc def");
});
it("rejoins nothing when the width isn't known", () => {
// Better to lose a wrapped URL than to invent one.
expect(flatten("abcde\nfghij", 0)).toBe("abcde fghij");
});
});
describe("UrlDetector", () => {
it("reconstructs a URL the PTY hard-wrapped mid-token", () => {
const seen: string[] = [];
const d = new UrlDetector((u) => seen.push(u), () => COLS);
const url =
"https://accounts.example.com/o/oauth2/auth?client_id=1234567890-abcdefghijklmnop.apps.example.com&redirect_uri=http%3A%2F%2Flocalhost%3A45678&scope=openid+email+profile";
feed(d, "Open this link:\r\n" + ptyWrap(url) + "\r\nWaiting for the browser…\r\n");
expect(seen).toEqual([url]);
});
it("does not glue the text that follows a link onto it", () => {
// The bug this file exists for. A terminal wrapping a paragraph emits the
// break *instead of* the space, so deleting every break produced
// `…/tag/preview-63f3c54Butitprovesyournitpick…` — a different host and
// path from the one on screen, opened on the user's machine.
const seen: string[] = [];
const d = new UrlDetector((u) => seen.push(u), () => COLS);
const url =
"https://repo.anhonesthost.net/CyberCoveLLC/Triple-C/releases/tag/preview-63f3c54-with-a-long-enough-suffix-to-scan";
feed(
d,
[
url,
"But it proves your nitpick perfectly: every file in it says 0.3.0.",
"That is the hard-coded patch number.",
].join("\r\n") + "\r\n",
);
expect(seen).toEqual([url]);
expect(seen[0]).not.toContain("But");
// And the host is exactly what was printed — no characters lost.
expect(new URL(seen[0]).host).toBe("repo.anhonesthost.net");
});
it("stops at the end of a short line even when more output follows", () => {
const seen: string[] = [];
const d = new UrlDetector((u) => seen.push(u), () => COLS);
const url = "https://example.com/" + "a".repeat(90);
feed(d, `${url}\r\nnext line of output\r\n`);
expect(seen).toEqual([url]);
});
it("joins the next line when a token ends exactly at the width", () => {
// The one case the width rule cannot decide: a URL whose length is an exact
// multiple of the column count looks identical to one that was cut. Pinned
// as known behaviour rather than pretended away — the toast still shows the
// whole candidate, and nothing opens without the user pressing Open.
const seen: string[] = [];
const d = new UrlDetector((u) => seen.push(u), () => COLS);
const url = "https://example.com/" + "c".repeat(2 * COLS - 20); // exactly 2 lines
feed(d, `${ptyWrap(url)}\r\nTAIL\r\n`);
expect(seen).toEqual([url + "TAIL"]);
});
it("ignores anything under the length threshold", () => {
const seen: string[] = [];
const d = new UrlDetector((u) => seen.push(u), () => COLS);
feed(d, "see https://example.com/short\r\nmore text\r\n");
expect(seen).toEqual([]);
});
it("emits a wrapped URL once, not once per chunk", () => {
const seen: string[] = [];
const d = new UrlDetector((u) => seen.push(u), () => COLS);
const url = "https://example.com/" + "b".repeat(120);
feed(d, ptyWrap(url));
feed(d, "\r\ndone\r\n");
expect(seen).toEqual([url]);
});
});