Public: anyone can read this; the crew can change it.
A test pins the terminal's hunk list: the cursor stays on a hunk that exists when the file changes under it #6663
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/6658-a-test-pins-the-terminal-s-hunk-list-the → main 1 commit fork 1 thread · 1 unresolved
1 file
changed +50
−0
test/tui-hunks.test.ts added +50
| @@ -0,0 +1,50 @@ | ||
| 1 | import { expect, test } from "bun:test"; | |
| 2 | import { parseUnifiedDiff, type FileDiff } from "../src/git/diff.ts"; | |
| 3 | import { | |
| 4 | HunkList, | |
| 5 | sectionLabel, | |
| 6 | sectionNote, | |
| 7 | type Section, | |
| 8 | } from "../src/tui/local/hunks.ts"; | |
| 9 | ||
| 10 | /** A one-file unified diff with `n` hunks, parsed by the module's own parser. */ | |
| 11 | function fileWith(n: number): FileDiff { | |
| 12 | let text = "diff --git a/f.txt b/f.txt\n--- a/f.txt\n+++ b/f.txt\n"; | |
| 13 | for (let i = 0; i < n; i++) { | |
| 14 | const at = 1 + i * 20; | |
| 15 | text += `@@ -${at},1 +${at},1 @@\n-old ${i}\n+new ${i}\n`; | |
| 16 | } | |
| 17 | const file = parseUnifiedDiff(text).files[0]; | |
| 18 | if (file === undefined) throw new Error("fixture did not parse"); | |
| 19 | return file; | |
| 20 | } | |
| 21 | ||
| 22 | test("the cursor lands on a hunk that exists when the file shrinks", () => { | |
| 23 | const list = new HunkList(); | |
| 24 | list.setFile(fileWith(3)); | |
| 25 | expect(list.hunks.length).toBe(3); | |
| 26 | list.select(2); | |
| 27 | expect(list.index).toBe(2); | |
| 28 | ||
| 29 | const one = fileWith(1); | |
| 30 | list.setFile(one); | |
| 31 | expect(list.index).toBe(0); | |
| 32 | expect(list.current).toBe(one.hunks[0]); | |
| 33 | }); | |
| 34 | ||
| 35 | test("a null file leaves no hunks and no current", () => { | |
| 36 | const list = new HunkList(); | |
| 37 | list.setFile(fileWith(2)); | |
| 38 | list.setFile(null); | |
| 39 | expect(list.hunks).toEqual([]); | |
| 40 | expect(list.current).toBeUndefined(); | |
| 41 | expect(list.index).toBe(0); | |
| 42 | }); | |
| 43 | ||
| 44 | test("every section has a label and a note", () => { | |
| 45 | const sections: Section[] = ["staged", "unstaged", "untracked", "conflicted"]; | |
| 46 | for (const s of sections) { | |
| 47 | expect(sectionLabel(s).length).toBeGreaterThan(0); | |
| 48 | expect(sectionNote(s).length).toBeGreaterThan(0); | |
| 49 | } | |
| 50 | }); |
new above
offline
Non-empty is a weak pin: swapping two labels still passes. Assert the exact strings, e.g. expect(sectionLabel("unstaged")).toBe("Changed").