Something went wrong. Try again.
Monorepo for Tangled forked from tangled.org/core
Something went wrong. Try again.
TypeScript
at sl/gitmirror
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132import { describe, expect, it } from "vitest";import { apply, transform } from "./testids.ts";
const run = (source: string, options?: Parameters<typeof transform>[1]) => { const { inserts, seen } = transform(source, options); return { out: apply(source, inserts), seen };};
const idOf = (markup: string) => run(markup).seen[0]?.id ?? null;
describe("handlers", () => { it("names a plain handler", () => expect(idOf("<button onclick={deleteIssue}>x</button>")).toBe("deleteIssue")); it("names the call inside an arrow", () => { expect(idOf("<button onclick={() => archive(issue)}>x</button>")).toBe("archive"); expect(idOf("<button onclick={() => void copy()}>x</button>")).toBe("copy"); expect(idOf("<button onclick={() => file && upload(file)}>x</button>")).toBe("upload"); }); it("names an action() call after the action, not .run", () => expect(idOf("<button onclick={() => save.run(draft)}>x</button>")).toBe("save")); it("reads assignments as what they do", () => { expect(idOf("<button onclick={() => (open = false)}>x</button>")).toBe("close"); expect(idOf("<button onclick={() => (drawerOpen = true)}>x</button>")).toBe("openDrawer"); expect(idOf("<button onclick={() => (menu = !menu)}>x</button>")).toBe("toggleMenu"); }); it("drops the on prefix a prop carries", () => { expect(idOf("<button onclick={onCancel}>x</button>")).toBe("cancel"); expect(idOf("<button onclick={onconfirm}>x</button>")).toBe("confirm"); }); it("leaves a forwarded onclick for the call site", () => expect(idOf("<button {type} onclick={onclick}>x</button>")).toBeNull()); it("gives up on a handler with no single action", () => expect(idOf("<button onclick={() => { a(); b(); }}>x</button>")).toBeNull());});
describe("links", () => { it("names a literal href by its last word", () => { expect(idOf('<a href="/settings/keys">x</a>')).toBe("keys"); expect(idOf('<Link href={resolve("/signup")}>x</Link>')).toBe("signup"); }); it("skips the parts only known at runtime", () => { expect(idOf("<a href={`/${handle}/${repo}/issues`}>x</a>")).toBe("issues"); expect(idOf("<a href={`/${handle}`}>x</a>")).toBeNull(); }); it("names a variable href after the variable", () => expect(idOf("<a href={newRepoHref}>x</a>")).toBe("newRepoHref")); it("ignores external links and a forwarded href", () => { expect(idOf('<a href="https://example.com">x</a>')).toBeNull(); expect(idOf("<a {href}>x</a>")).toBeNull(); });});
describe("fields", () => { it("names an input after what it binds", () => expect(idOf("<Input bind:value={form.title} />")).toBe("formTitle")); it("names a submit button submit", () => expect(idOf('<button type="submit">x</button>')).toBe("submit")); it("prefers a handler over a name", () => expect(idOf('<button name="a" onclick={go}>x</button>')).toBe("go"));});
describe("injection", () => { it("puts the id on a component call site", () => expect(run("<Button onclick={save}>x</Button>").out).toBe( '<Button data-testid="save" onclick={save}>x</Button>' )); it("leaves a hand-written id alone", () => { const { out, seen } = run('<button data-testid="mine" onclick={save}>x</button>'); expect(out).toBe('<button data-testid="mine" onclick={save}>x</button>'); expect(seen.map((item) => [item.id, item.source])).toEqual([["mine", "hand"]]); }); it("does not touch elements that are not interactive", () => expect(run("<div><p>hi</p></div>").out).toBe("<div><p>hi</p></div>")); it("does not touch a component it has no rule for", () => expect(run("<Avatar bind:value={x}>y</Avatar>").out).toBe( "<Avatar bind:value={x}>y</Avatar>" )); it("marks the root elements with the component, through blocks too", () => { const { out } = run("{#if a}<section>x</section>{/if}<aside>y</aside>", { component: "Panel" }); expect(out).toBe( '{#if a}<section data-component="Panel">x</section>{/if}<aside data-component="Panel">y</aside>' ); }); it("does not mark elements nested in another", () => expect(run("<div><span>x</span></div>", { component: "Panel" }).out).toBe( '<div data-component="Panel"><span>x</span></div>' )); it("copes with typescript in the script", () => expect( run( '<script lang="ts">let n: number = $state(0);</script><button onclick={() => n++}>x</button>' ).out ).toContain("<button onclick"));});
describe("instanced components", () => { it("names a modal after what it binds, without the Open", () => { expect(idOf("<ConfirmModal bind:open={deleteConfirmOpen} title={t} />")).toBe( "deleteConfirm" ); expect(run("<Modal bind:open={showKeys}>x</Modal>").out).toContain('testid="showKeys"'); }); it("does not name a modal after a bare open", () => expect(idOf("<Modal bind:open>x</Modal><Modal bind:open>y</Modal>")).toBeNull()); it("names a menu after its id literal", () => expect(idOf('<Dropdown id="profile-menu" group="topbar">x</Dropdown>')).toBe( "profileMenu" )); it("falls back to the tag only when it is alone in the file", () => { expect(run("<MoreMenu>x</MoreMenu>").out).toBe('<MoreMenu testid="moreMenu">x</MoreMenu>'); expect( run("<MoreMenu>x</MoreMenu><MoreMenu>y</MoreMenu>").seen.map((item) => item.id) ).toEqual([null, null]); }); it("leaves a hand-written testid prop alone", () => expect(run('<Modal testid="mine" bind:open={a}>x</Modal>').out).toBe( '<Modal testid="mine" bind:open={a}>x</Modal>' )); it("lists a hand-written id on any element, not only the interactive ones", () => expect(run('<h1 data-testid="title">x</h1>').seen.map((item) => item.id)).toEqual([ "title" ])); it("passes data-component through a root Card, which spreads rest onto its own root", () => expect(run('<Card padding="none">x</Card>', { component: "Panel" }).out).toBe( '<Card data-component="Panel" padding="none">x</Card>' )); it("does not mark a root component that cannot take it", () => expect(run("<ProfileTabs />", { component: "Panel" }).out).toBe("<ProfileTabs />"));});