diff --git a/packages/lint/src/utils.test.ts b/packages/lint/src/utils.test.ts new file mode 100644 index 0000000000..f31f78138d --- /dev/null +++ b/packages/lint/src/utils.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, it } from "vitest"; + +import { readAttr, readDecodedAttr } from "./utils.js"; + +describe("readAttr", () => { + it("reads a double-quoted value", () => { + expect(readAttr('
', "data-start")).toBe("2.5"); + }); + + it("reads a single-quoted value", () => { + expect(readAttr("
", "data-start")).toBe("2.5"); + }); + + // Unquoted values are valid HTML5 and the runtime reads them, so a + // quoted-only pattern both invents "missing attribute" errors and hides + // real violations on the attributes it cannot see. + it("reads an unquoted value", () => { + expect(readAttr("
", "data-start")).toBe("0"); + }); + + it("reads unquoted values from a tag that mixes quoting styles", () => { + const tag = `
`; + expect(readAttr(tag, "data-composition-id")).toBe("main"); + expect(readAttr(tag, "data-start")).toBe("0"); + expect(readAttr(tag, "data-width")).toBe("1920"); + expect(readAttr(tag, "data-height")).toBe("1080"); + }); + + it("agrees with the parser-backed reader across quoting styles and near-misses", () => { + const cases: Array<[string, string]> = [ + ["
", "data-track-index"], + ["
", "data-duration"], + ['
', "id"], + ['', "class"], + ["
", "data-composition-src"], + ]; + for (const [tag, attr] of cases) { + expect(readAttr(tag, attr)).toBe(readDecodedAttr(tag, attr) || null); + } + }); + + it("reads unquoted values that sit next to other attributes", () => { + expect(readAttr("
", "class")).toBe("clip"); + expect(readAttr("
", "data-composition-src")).toBe( + "scenes/a.html", + ); + }); + + // A `name=value` pair inside another attribute's value is not an attribute. + // Reading it as one made `duplicate_media_id` fire on ids that do not exist + // and hid `media_missing_id` on a video that really had none. + it("does not read a name=value pair out of another attribute's value", () => { + expect(readAttr('', "id")).toBeNull(); + expect(readAttr('', "class")).toBe("clip"); + expect(readAttr('
', "id")).toBe("root"); + expect(readAttr('