import { describe, expect, test, tier } from 'claude-code/testing' import Fixtures from './fixtures' tier('builtin') describe('views', () => { test('docked, every file has its hunks under the list', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.TWO_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIFF) await world.clock.advance(Fixtures.SETTLE_MS) const drawn = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(drawn).toContain('2 files changed +3 -1') expect(drawn, "a closing empty row, as the built-in's").toContain( '+const a = 2\n ', ) expect(drawn, 'none after the last file').toMatch(/\+export const c = 2$/) expect(drawn).not.toContain('❯') }) test('inline, a row opens that file alone', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.TWO_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIALOG_DIFF) await world.clock.advance(Fixtures.SETTLE_MS) await $.ui.render(Fixtures.INLINE_PANE) expect(await $.ui.press({ plugin: 'diff', key: 'file:lib.ts' })).toEqual({ element: 'file:lib.ts', }) const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE)) expect(drawn).toContain('+export const c = 2') expect(drawn).not.toContain('+const a = 2') expect(drawn).not.toContain('app.ts') expect(drawn).toContain('\u2191/\u2193 to scroll \u00b7 Esc to back') }) test('docked, a wheel tick moves the body, not the list', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.MANY_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIFF) await world.clock.advance(Fixtures.SETTLE_MS) const before = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(before, 'listed, and named over its body').toContain('file0.ts') expect(before.split('file0.ts')).toHaveLength(3) expect(await $.ui.scroll(Fixtures.WHEEL_TICK)).toEqual({}) const after = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(after.split('file0.ts'), 'its name row scrolled away').toHaveLength( 2, ) expect(after).toContain('-const v = 0') expect(after).toContain('10 files changed +10 -10') expect(after, 'the list stays').not.toContain('more above') }) test('docked, the wheel over a long list moves the list', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.MANY_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIFF) await world.clock.advance(Fixtures.SETTLE_MS) await $.ui.render(Fixtures.PANE) expect(await $.ui.scroll(Fixtures.WHEEL_OVER_LIST)).toEqual({}) const after = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(after).toContain('\u2191 1 more above') expect(after).toContain('file8.ts') expect(after.split('file0.ts'), 'the body stays').toHaveLength(2) }) test('past eight files the docked list scrolls by key', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.MANY_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIFF) await world.clock.advance(Fixtures.SETTLE_MS) const drawn = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(drawn).toContain('10 files changed +10 -10') expect(drawn).toContain('file7.ts') expect(drawn).toContain('\u2193 2 more below (opt+\u2193 to scroll)') expect(drawn).not.toContain('file8.ts') expect(await $.ui.press({ plugin: 'diff', key: 'list-down' })).toEqual({ element: 'list-down', }) const scrolled = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(scrolled).toContain('\u2191 1 more above') expect(scrolled).toContain('file8.ts') expect(scrolled).toContain('\u2193 1 more below') }) test('a rename lists as git prints it, and reads no body', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.RENAMED) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIFF) await world.clock.advance(Fixtures.SETTLE_MS) const drawn = Fixtures.textOf(await $.ui.render(Fixtures.PANE)) expect(drawn).toContain('1 file changed') expect(drawn).toContain('docs/{notes.txt => renamed-notes.txt}') expect(drawn).toContain('No diff content') expect( world.runs.filter(run => run.argv.includes('docs/renamed-notes.txt')), ).toEqual([]) }) test('inline, the dialog lists every file and its keys', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.TWO_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIALOG_DIFF) await world.clock.advance(Fixtures.SETTLE_MS) const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE)) expect(drawn).toContain('Uncommitted changes (git diff HEAD)') expect(drawn).toContain('2 files changed +3 -1') expect(drawn).toContain('\u276f app.ts') expect(drawn).toContain(' lib.ts') expect(drawn).not.toContain('+const a = 2') expect(drawn).toContain( '\u2191/\u2193 to select \u00b7 Enter to view \u00b7 Esc to close', ) expect(world.opened.at(-1), 'sized to its rows once listed').toEqual({ id: 'diff', title: 'Diff', holdToasts: true, closeOnEscape: true, rows: 8, }) }) test('narrow under the fullscreen layout, the resize line', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.TWO_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIFF) await world.clock.advance(Fixtures.SETTLE_MS) expect( Fixtures.textOf(await $.ui.render(Fixtures.NARROW_INLINE_PANE)), ).toBe( 'Resize your terminal to at least 110 columns to show the diff panel', ) }) test('off fullscreen, the window follows the walk', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.MANY_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIALOG_DIFF) await world.clock.advance(Fixtures.SETTLE_MS) const drawn = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE)) expect(drawn).toContain('\u276f file0.ts') expect(drawn).toContain(' file4.ts') expect(drawn).not.toContain('file5.ts') expect(drawn).toContain(' \u2193 5 more files') expect(await $.ui.focus(Fixtures.ringOnto('file:file3.ts'))).toEqual({}) expect( world.focused.map(focus => focus.element), 'its row once centred', ).toEqual(['file:file2.ts']) const walked = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE)) expect(walked).toContain(' \u2191 1 more file') expect(walked).toContain('\u276f file3.ts') expect(walked).toContain(' file5.ts') expect(walked).toContain(' \u2193 4 more files') expect(walked).not.toContain('file0.ts') }) test('off fullscreen, the walk stops at the last file', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.MANY_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIALOG_DIFF) await world.clock.advance(Fixtures.SETTLE_MS) await $.ui.render(Fixtures.INLINE_PANE) await $.ui.focus(Fixtures.ringOnto('file:file3.ts')) await $.ui.render(Fixtures.INLINE_PANE) await $.ui.focus(Fixtures.ringOnto('file:file5.ts')) await $.ui.render(Fixtures.INLINE_PANE) await $.ui.focus(Fixtures.ringOnto('file:file7.ts')) await $.ui.render(Fixtures.INLINE_PANE) await $.ui.focus(Fixtures.ringOnto('file:file9.ts')) const last = Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE)) expect(last).toContain('\u276f file9.ts') expect(last).toContain(' \u2191 5 more files') expect( await $.ui.focus(Fixtures.ringOnto('file:file5.ts')), 'the ring would wrap to the first row drawn; it stays', ).toEqual({}) expect(Fixtures.textOf(await $.ui.render(Fixtures.INLINE_PANE))).toContain( '\u276f file9.ts', ) expect(world.focused, 'the wrap never reached the engine').toHaveLength(4) }) test('off fullscreen, the dialog draws at any width', async ($, on) => { const world = Fixtures.inRepository(on, Fixtures.TWO_FILES) await $.session.start(Fixtures.SESSION) await $.command.run(Fixtures.DIALOG_DIFF) await world.clock.advance(Fixtures.SETTLE_MS) expect( Fixtures.textOf(await $.ui.render(Fixtures.NARROW_INLINE_PANE)), ).toContain('Uncommitted changes (git diff HEAD)') }) })