Skip to content
Source
Sign inSign up

markdownTaskList.test.ts

72 lines3.4 KB

1import { describe, expect, it } from "vite-plus/test";
2​
3import { markdownTaskMarkerOffset, setMarkdownTaskChecked } from "./markdownTaskList.ts";
4​
5describe("setMarkdownTaskChecked", () => {
6 const markdown = "- [ ] First\n- [x] Second\n";
7​
8 it("checks and unchecks the task marker at the supplied offset", () => {
9 expect(setMarkdownTaskChecked(markdown, 2, true)).toBe("- [x] First\n- [x] Second\n");
10 expect(setMarkdownTaskChecked(markdown, 14, false)).toBe("- [ ] First\n- [ ] Second\n");
11 expect(setMarkdownTaskChecked("1. [X] Ordered\n", 3, false)).toBe("1. [ ] Ordered\n");
12 });
13​
14 it("leaves the document unchanged for a stale or invalid marker offset", () => {
15 expect(setMarkdownTaskChecked(markdown, 0, true)).toBe(markdown);
16 expect(setMarkdownTaskChecked(markdown, 200, true)).toBe(markdown);
17 });
18});
19​
20describe("markdownTaskMarkerOffset", () => {
21 const markdown = [
22 "## Test plan",
23 "- [ ] `vp lint` passes",
24 " - [x] Nested **step**",
25 "```md",
26 "- [ ] Inside a fence",
27 "```",
28 "> 1. [X] Quoted [link](https://example.com)",
29 "- [ ] Wrapped",
30 " onto two lines",
31 ].join("\n");
32 const marker = (offset: number | null) =>
33 offset === null ? null : markdown.slice(offset, offset + 3);
34​
35 it("finds the tapped checkbox, skipping look-alikes in code", () => {
36 expect(marker(markdownTaskMarkerOffset(markdown, 0, "vp lint passes", true))).toBe("[ ]");
37 expect(marker(markdownTaskMarkerOffset(markdown, 1, "Nested step", false))).toBe("[x]");
38 // Native numbering restarts after code blocks and blockquotes.
39 expect(marker(markdownTaskMarkerOffset(markdown, 0, "Quoted link", false))).toBe("[X]");
40 // Android cuts the text at a line break, a soft one too with hard line breaks; iOS doesn't.
41 for (const text of ["Wrapped", "Wrapped onto two lines"]) {
42 expect(markdownTaskMarkerOffset(markdown, 0, text, true)).toBe(markdown.lastIndexOf("[ ]"));
43 }
44 });
45​
46 it("tells identical labels apart by count within one list and by state", () => {
47 const same = "- [ ] Same\n- [ ] Same\n\n```\nx\n```\n\n- [x] Same\n";
48 expect(markdownTaskMarkerOffset(same, 0, "Same", true)).toBe(2);
49 expect(markdownTaskMarkerOffset(same, 1, "Same", true)).toBe(13);
50 expect(markdownTaskMarkerOffset(same, 0, "Same", false)).toBe(same.lastIndexOf("[x]"));
51 });
52​
53 it("refuses a checkbox it can't trace to exactly one task", () => {
54 expect(markdownTaskMarkerOffset(markdown, 1, "vp lint passes", true)).toBeNull();
55 expect(markdownTaskMarkerOffset(markdown, 0, "vp lint passes", false)).toBeNull();
56 expect(markdownTaskMarkerOffset(markdown, 0, "Wrapped onto", true)).toBeNull();
57 expect(markdownTaskMarkerOffset(markdown, 4, "", true)).toBeNull();
58​
59 const similar = "- [ ] Similar\n\n```text\nseparator\n```\n\n- [ ] Similar<br>different\n";
60 // iOS keeps hard breaks in the text, so it names the second task.
61 expect(markdownTaskMarkerOffset(similar, 0, "Similar
different", true)).toBe(
62 similar.lastIndexOf("[ ]"),
63 );
64 // Android cuts it to "Similar", which both tasks could be.
65 expect(markdownTaskMarkerOffset(similar, 0, "Similar", true)).toBeNull();
66​
67 for (const label of ["Similar [docs](https://github.com/pingdotgg/t3code)", "Similar $x$"]) {
68 const attachment = similar.replace("Similar<br>different", label);
69 expect(markdownTaskMarkerOffset(attachment, 0, "Similar \uFFFC", true)).toBeNull();
70 }
71 });
72});