This repository has no description
1<script module lang="ts">
2 import { defineMeta, type StoryContext } from "@storybook/addon-svelte-csf";
3 import { expect, waitFor } from "storybook/test";
4 import type { DiffFile } from "$lib/api/diff";
5 import DiffView from "./DiffView.svelte";
6
7 const textFile: DiffFile = {
8 name: { old: "src/colors.ts", new: "src/colors.ts" },
9 text_fragments: [
10 {
11 OldPosition: 1,
12 OldLines: 3,
13 NewPosition: 1,
14 NewLines: 4,
15 LinesAdded: 2,
16 LinesDeleted: 1,
17 Lines: [
18 { Op: 0, Line: "export const palette = {\n" },
19 { Op: 1, Line: '\tbackground: "white",\n' },
20 { Op: 2, Line: '\tbackground: "oklch(0.98 0 0)",\n' },
21 { Op: 2, Line: '\tforeground: "oklch(0.2 0 0)",\n' },
22 { Op: 0, Line: "};\n" }
23 ]
24 }
25 ]
26 };
27
28 const binaryFile: DiffFile = {
29 name: { old: "assets/logo.png", new: "assets/logo.png" },
30 is_binary: true
31 };
32
33 const downloadUrls = {
34 patch: "/dawn/tangled/commit/0123456789abcdef0123456789abcdef01234567.patch",
35 diff: "/dawn/tangled/commit/0123456789abcdef0123456789abcdef01234567.diff"
36 };
37
38 const blobBase = "/dawn/tangled/blob/0123456789abcdef0123456789abcdef01234567";
39
40 type PlayContext = Pick<
41 StoryContext<Record<string, unknown>>,
42 "canvas" | "canvasElement" | "userEvent"
43 >;
44
45 // pierre renders inside a shadow root, diff content is invisible to canvas
46 const shadowText = (canvasElement: HTMLElement) =>
47 [...canvasElement.querySelectorAll("diffs-container")]
48 .map((host) => host.shadowRoot?.textContent ?? "")
49 .join("\n");
50
51 const hasSplitColumns = (canvasElement: HTMLElement) =>
52 [...canvasElement.querySelectorAll("diffs-container")].some(
53 (host) =>
54 host.shadowRoot?.querySelector("[data-deletions]") &&
55 host.shadowRoot?.querySelector("[data-additions]")
56 );
57
58 // the per-file cards, excluding the file tree's directory <details>
59 const fileCards = (canvasElement: HTMLElement) => [
60 ...canvasElement.querySelectorAll<HTMLDetailsElement>("details[id^='file-']")
61 ];
62
63 const mixedFiles = async ({ canvas, canvasElement, userEvent }: PlayContext) => {
64 await expect(canvas.getAllByText("+2")).toHaveLength(2);
65 await expect(canvas.getAllByText("-1")).toHaveLength(2);
66 await expect(canvas.getByText("2 changed files")).toBeVisible();
67
68 await expect(canvas.getByText("src/colors.ts")).toBeVisible();
69 await waitFor(() => expect(shadowText(canvasElement)).toContain("palette"));
70 expect(shadowText(canvasElement)).not.toContain("src/colors.ts");
71 expect(hasSplitColumns(canvasElement)).toBe(false);
72
73 await expect(canvas.getByText("assets/logo.png")).toBeVisible();
74 await expect(
75 canvas.getByText("This is a binary file and will not be displayed.")
76 ).toBeVisible();
77 expect(shadowText(canvasElement)).not.toContain("assets/logo.png");
78
79 await expect(canvas.getByRole("link", { name: "colors.ts" })).toHaveAttribute(
80 "href",
81 "#file-src/colors.ts"
82 );
83
84 await expect(canvas.getByRole("link", { name: ".patch" })).toHaveAttribute(
85 "href",
86 downloadUrls.patch
87 );
88 await expect(canvas.getByRole("link", { name: "Split diff" })).toHaveAttribute(
89 "href",
90 "?diff=split"
91 );
92 await expect(canvas.getByRole("link", { name: "Unified diff" })).toHaveAttribute(
93 "href",
94 "?diff=unified"
95 );
96
97 expect(fileCards(canvasElement).every((card) => card.open)).toBe(true);
98 const firstCard = fileCards(canvasElement)[0];
99 await userEvent.click(firstCard.querySelector("summary")!);
100 expect(firstCard.open).toBe(false);
101 expect(fileCards(canvasElement)[1].open).toBe(true);
102
103 await userEvent.click(canvas.getByRole("button", { name: "Expand all" }));
104 expect(fileCards(canvasElement).every((card) => card.open)).toBe(true);
105 await userEvent.click(canvas.getByRole("button", { name: "Collapse all" }));
106 expect(fileCards(canvasElement).every((card) => !card.open)).toBe(true);
107 };
108
109 const splitView = async ({ canvasElement }: PlayContext) => {
110 await waitFor(() => expect(shadowText(canvasElement)).toContain("palette"));
111 await waitFor(() => expect(hasSplitColumns(canvasElement)).toBe(true));
112 };
113
114 const viewFileLinks = async ({ canvas }: PlayContext) => {
115 const links = canvas.getAllByRole("link", { name: "View file" });
116 await expect(links).toHaveLength(2);
117 await expect(links[0]).toHaveAttribute("href", `${blobBase}/src/colors.ts`);
118 await expect(links[1]).toHaveAttribute("href", `${blobBase}/assets/logo.png`);
119 };
120
121 const { Story } = defineMeta({
122 title: "Repo/DiffView",
123 component: DiffView,
124 tags: ["autodocs"],
125 args: {
126 files: [textFile, binaryFile],
127 stat: { insertions: 2, deletions: 1, files_changed: 2 },
128 downloadUrls
129 }
130 });
131</script>
132
133<Story name="Mixed text and binary" play={mixedFiles} />
134
135<Story name="Split" args={{ diffStyle: "split" }} play={splitView} />
136
137<Story name="With blob base" args={{ blobBase }} play={viewFileLinks} />
138
139<Story name="No downloads" args={{ downloadUrls: undefined }} />