Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

84 linesCodeBlameRaw
1import assert from "node:assert/strict";
2import { readFileSync } from "node:fs";
3import { test } from "node:test";
4
5import { rehypeTaskLines } from "./markdown-plugins.ts";
6import { markdownTree } from "./markdown-tree.ts";
7import { taskCheckOf } from "./task-check.ts";
8import { taskList } from "@g1t/contracts/tasks";
9import rehypeRaw from "rehype-raw";
10import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
11import remarkGfm from "remark-gfm";
12import { visit } from "unist-util-visit";
13
14function form(fields: Record<string, string>): FormData {
15 const data = new FormData();
16 for (const [key, value] of Object.entries(fields)) data.set(key, value);
17 return data;
18}
19
20test("reads the box a form names", () => {
21 assert.deepEqual(taskCheckOf(form({ task: "2", expected: "Write the docs", checked: "1" })), { task: 2, expected: "Write the docs", checked: true });
22 assert.deepEqual(taskCheckOf(form({ task: "3", checked: "" })), { task: 3, checked: false });
23 // Nothing usable is left out, for the work service to refuse.
24 assert.deepEqual(taskCheckOf(form({ task: "0" })), { checked: false });
25 assert.deepEqual(taskCheckOf(form({ task: "two", checked: "1" })), { checked: true });
26});
27
28/** The line each box markdown draws says, in order, as the site renders it. */
29function drawnLines(source: string): (number | undefined)[] {
30 const tree = markdownTree(source, {
31 remarkPlugins: [remarkGfm],
32 rehypePlugins: [rehypeRaw, [rehypeSanitize, defaultSchema], rehypeTaskLines],
33 });
34 const lines: (number | undefined)[] = [];
35 visit(tree, "element", (node) => {
36 if (node.tagName === "input") lines.push(node.properties.dataTaskLine as number | undefined);
37 });
38 return lines;
39}
40
41test("each box markdown draws is a box the work service counts, on its line", () => {
42 const source = [
43 "Intro",
44 "",
45 "- [ ] one",
46 " - [x] nested",
47 "- plain",
48 "",
49 "> - [ ] quoted",
50 "",
51 "```",
52 "- [ ] code",
53 "```",
54 "",
55 "1. [X] numbered",
56 "",
57 "- [ ] loose",
58 "",
59 "- [x] list",
60 ].join("\n");
61 const drawn = drawnLines(source);
62 assert.deepEqual(drawn, [3, 4, 7, 13, 15, 17]);
63 assert.deepEqual(
64 taskList(source).map((task) => task.line),
65 drawn,
66 );
67});
68
69test("markdown draws the boxes of every shared case where the work service counts them", () => {
70 const fixtures = JSON.parse(readFileSync(new URL("../../../../packages/contracts/src/tasks.fixtures.json", import.meta.url), "utf8")) as {
71 lists: { body: string; tasks: { line: number }[] }[];
72 };
73 for (const { body, tasks } of fixtures.lists) {
74 assert.deepEqual(
75 drawnLines(body),
76 tasks.map((task) => task.line),
77 JSON.stringify(body),
78 );
79 }
80});
81
82test("a box written as HTML only shows", () => {
83 assert.deepEqual(drawnLines('<ul><li class="task-list-item"><input type="checkbox" checked> by hand</li></ul>\n\n- [ ] by markdown'), [undefined, 3]);
84});