spacehub

surshar / claude-code

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

Built by Anthropic · github.com/anthropics

diff tests: the wheel moves the body not the list, the list keys move its window, and off fullscreen /diff opens the dialog, lists five files a page and shows one aloneBrowse files
poteat authored on Sep 13, 2026 parent 325256e · commit f305b6cea030
5 changed files+144 -15compared with 325256e
Amods/diff/tests/fixtures/dialog-diff.ts
Mmods/diff/tests/fixtures/index.ts
Amods/diff/tests/fixtures/wheel-tick.ts
Mmods/diff/tests/register.test.ts
Mmods/diff/tests/views.test.ts
@@ -1,0 +1,12 @@
1+import type { CommandRunInput } from 'claude-code'
2+
3+import { DIFF } from './diff.js'
4+
5+/**
6+ * The command as the person types it on the main screen (no fullscreen
7+ * layout), where the built-in answers with its dialog.
8+ */
9+export const DIALOG_DIFF: CommandRunInput = {
10+ ...DIFF,
11+ presentation: { isFullscreen: false, columns: 100 },
12+}
@@ -1,5 +1,6 @@
11 export * from './builtin-holds.js'
22 export * from './clear.js'
3+export * from './dialog-diff.js'
34 export * from './diff.js'
45 export * from './git-hung.js'
56 export * from './git-in.js'
@@ -23,5 +24,6 @@
2324 export * from './starts-session.js'
2425 export * from './text-of.js'
2526 export * from './two-files.js'
27+export * from './wheel-tick.js'
2628
2729 export * as default from '.'
@@ -1,0 +1,17 @@
1+import type { UiScrollInput } from 'claude-code'
2+
3+import { PANE } from './pane.js'
4+
5+/**
6+ * One tick of the person's wheel toward the foot over the docked pane, as
7+ * the engine raises it before anything moves.
8+ */
9+export const WHEEL_TICK: UiScrollInput = {
10+ component: 'Pane',
11+ requestId: PANE.requestId,
12+ offset: 1,
13+ by: 1,
14+ bodyRows: PANE.props.scroll.bodyRows,
15+ contentRows: PANE.props.scroll.bodyRows + 1,
16+ origin: { kind: 'person' },
17+}
@@ -129,7 +129,9 @@
129129 text: 'Diff panel shown',
130130 })
131131
132- expect(world.opened).toEqual([{ id: 'diff', title: 'Diff' }])
132+ expect(world.opened).toEqual([
133+ { id: 'diff', title: 'Diff', holdToasts: true },
134+ ])
133135
134136 await world.clock.advance(Fixtures.SETTLE_MS)
135137
@@ -139,6 +141,28 @@
139141 expect(drawn).toContain('app.ts')
140142 })
141143
144+ test('off fullscreen, /diff opens the dialog, focused', async ($, on) => {
145+ const world = Fixtures.inRepository(on)
146+
147+ await $.session.start(Fixtures.SESSION)
148+
149+ expect(await $.command.run(Fixtures.DIALOG_DIFF)).toEqual({})
150+
151+ expect(world.opened).toEqual([
152+ {
153+ id: 'diff',
154+ title: 'Diff',
155+ holdToasts: true,
156+ focus: true,
157+ closeOnEscape: true,
158+ },
159+ ])
160+
161+ expect(await $.command.run(Fixtures.DIALOG_DIFF)).toEqual({
162+ text: 'Diff dialog dismissed',
163+ })
164+ })
165+
142166 test('/diff again closes the pane and says so', async ($, on) => {
143167 const world = Fixtures.inRepository(on)
144168
@@ -24,11 +24,11 @@
2424 expect(drawn).not.toContain('❯')
2525 })
2626
27- test('inline, a row moves the pointer and the body to it', async ($, on) => {
27+ test('inline, a row opens that file alone', async ($, on) => {
2828 const world = Fixtures.inRepository(on, Fixtures.TWO_FILES)
2929
3030 await $.session.start(Fixtures.SESSION)
31- await $.command.run(Fixtures.DIFF)
31+ await $.command.run(Fixtures.DIALOG_DIFF)
3232 await world.clock.advance(Fixtures.SETTLE_MS)
3333 await $.ui.render(Fixtures.INLINE_PANE)
3434
@@ -38,27 +38,59 @@
3838
3939 const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
4040
41- expect(drawn).toContain('\u276f lib.ts')
4241 expect(drawn).toContain('+export const c = 2')
4342 expect(drawn).not.toContain('+const a = 2')
43+ expect(drawn).not.toContain('app.ts')
44+ expect(drawn).toContain('\u2191/\u2193 to scroll \u00b7 Esc to back')
4445 })
4546
46- test('past eight files the docked list counts the rest', async ($, on) => {
47+ test('docked, a wheel tick moves the body, not the list', async ($, on) => {
4748 const world = Fixtures.inRepository(on, Fixtures.MANY_FILES)
4849
4950 await $.session.start(Fixtures.SESSION)
5051 await $.command.run(Fixtures.DIFF)
5152 await world.clock.advance(Fixtures.SETTLE_MS)
5253
54+ const before = Fixtures.textOf(await $.ui.render(Fixtures.PANE))
55+
56+ expect(before, 'listed, and named over its body').toContain('file0.ts')
57+ expect(before.split('file0.ts')).toHaveLength(3)
58+
59+ expect(await $.ui.scroll(Fixtures.WHEEL_TICK)).toEqual({})
60+
61+ const after = Fixtures.textOf(await $.ui.render(Fixtures.PANE))
62+
63+ expect(after.split('file0.ts'), 'its name row scrolled away').toHaveLength(
64+ 2,
65+ )
66+
67+ expect(after).toContain('-const v = 0')
68+ expect(after).toContain('10 files changed +10 -10')
69+ })
70+
71+ test('past eight files the docked list scrolls by key', async ($, on) => {
72+ const world = Fixtures.inRepository(on, Fixtures.MANY_FILES)
73+
74+ await $.session.start(Fixtures.SESSION)
75+ await $.command.run(Fixtures.DIFF)
76+ await world.clock.advance(Fixtures.SETTLE_MS)
77+
5378 const drawn = Fixtures.textOf(await $.ui.render(Fixtures.PANE))
5479
5580 expect(drawn).toContain('10 files changed +10 -10')
5681 expect(drawn).toContain('file7.ts')
57- expect(drawn).toContain('↓ 2 more below')
82+ expect(drawn).toContain('\u2193 2 more below (opt+\u2193 to scroll)')
83+ expect(drawn).not.toContain('file8.ts')
5884
59- expect(drawn.indexOf('↓ 2 more below')).toBeLessThan(
60- drawn.indexOf('file8.ts'),
61- )
85+ expect(await $.ui.press({ plugin: 'diff', key: 'list-down' })).toEqual({
86+ element: 'list-down',
87+ })
88+
89+ const scrolled = Fixtures.textOf(await $.ui.render(Fixtures.PANE))
90+
91+ expect(scrolled).toContain('\u2191 1 more above')
92+ expect(scrolled).toContain('file8.ts')
93+ expect(scrolled).toContain('\u2193 1 more below')
6294 })
6395
6496 test('a rename lists as git prints it, and reads no body', async ($, on) => {
@@ -79,21 +111,27 @@
79111 ).toEqual([])
80112 })
81113
82- test('inline on a wide terminal, the rows round one file', async ($, on) => {
114+ test('inline, the dialog lists every file and its keys', async ($, on) => {
83115 const world = Fixtures.inRepository(on, Fixtures.TWO_FILES)
84116
85117 await $.session.start(Fixtures.SESSION)
86- await $.command.run(Fixtures.DIFF)
118+ await $.command.run(Fixtures.DIALOG_DIFF)
87119 await world.clock.advance(Fixtures.SETTLE_MS)
88120
89121 const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
90122
91- expect(drawn).toContain('❯ app.ts')
92- expect(drawn).toContain('+const a = 2')
93- expect(drawn).not.toContain('+export const c = 2')
123+ expect(drawn).toContain('Uncommitted changes (git diff HEAD)')
124+ expect(drawn).toContain('2 files changed +3 -1')
125+ expect(drawn).toContain(' app.ts')
126+ expect(drawn).toContain(' lib.ts')
127+ expect(drawn).not.toContain('+const a = 2')
128+
129+ expect(drawn).toContain(
130+ '\u2191/\u2193 to select \u00b7 Enter to view \u00b7 Esc to close',
131+ )
94132 })
95133
96- test('inline on a narrow terminal, the resize line', async ($, on) => {
134+ test('narrow under the fullscreen layout, the resize line', async ($, on) => {
97135 const world = Fixtures.inRepository(on, Fixtures.TWO_FILES)
98136
99137 await $.session.start(Fixtures.SESSION)
@@ -106,4 +144,40 @@
106144 'Resize your terminal to at least 110 columns to show the diff panel',
107145 )
108146 })
147+
148+ test('off fullscreen, forty files list five at a time', async ($, on) => {
149+ const world = Fixtures.inRepository(on, Fixtures.MANY_FILES)
150+
151+ await $.session.start(Fixtures.SESSION)
152+ await $.command.run(Fixtures.DIALOG_DIFF)
153+ await world.clock.advance(Fixtures.SETTLE_MS)
154+
155+ const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
156+
157+ expect(drawn).toContain(' file4.ts')
158+ expect(drawn).not.toContain('file5.ts')
159+ expect(drawn).toContain(' \u2193 5 more files')
160+
161+ expect(await $.ui.press({ plugin: 'diff', key: 'files-down' })).toEqual({
162+ element: 'files-down',
163+ })
164+
165+ const paged = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))
166+
167+ expect(paged).toContain(' \u2191 5 more files')
168+ expect(paged).toContain(' file9.ts')
169+ expect(paged).not.toContain('file4.ts')
170+ })
171+
172+ test('off fullscreen, the dialog draws at any width', async ($, on) => {
173+ const world = Fixtures.inRepository(on, Fixtures.TWO_FILES)
174+
175+ await $.session.start(Fixtures.SESSION)
176+ await $.command.run(Fixtures.DIALOG_DIFF)
177+ await world.clock.advance(Fixtures.SETTLE_MS)
178+
179+ expect(
180+ Fixtures.textOf(await $.ui.render(Fixtures.NARROW_INLINE_PANE)),
181+ ).toContain('Uncommitted changes (git diff HEAD)')
182+ })
109183 })