// @vitest-environment jsdom import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest' import { cleanup, fireEvent, render, waitFor } from '@testing-library/react' import React from 'react' vi.mock('../src/renderer/src/terminals', () => { let n = 0 return { Terminal: () => null, lid: () => ++n } }) import { App } from '../src/renderer/src/App' import { ProjectProvider } from '../src/renderer/src/project' beforeAll(() => { globalThis.ResizeObserver = class { observe() {} unobserve() {} disconnect() {} } as never if (!Element.prototype.scrollIntoView) Element.prototype.scrollIntoView = () => {} }) afterEach(() => { cleanup(); localStorage.clear() }) function find(c: HTMLElement, sel: string, text: string): HTMLElement | undefined { return Array.from(c.querySelectorAll(sel)).find((el) => el.textContent?.trim() === text) } // Open a changed file and switch to the writable buffer. async function openEditor(): Promise { const c = render().container const row = await waitFor(() => { const r = Array.from(c.querySelectorAll('.git-row')).find((el) => el.textContent?.includes('UserController.php')) if (!r) throw new Error('git not ready') return r }) fireEvent.click(row) await waitFor(() => expect(c.querySelector('.diff-bar')).toBeTruthy()) fireEvent.click(find(c, '.seg button', 'Actual')!) return await waitFor(() => { const ta = c.querySelector('.ce-ta') if (!ta) throw new Error('no buffer') return ta }) } function tab(ta: HTMLTextAreaElement, shift = false): boolean { return fireEvent.keyDown(ta, { key: 'Tab', shiftKey: shift }) } describe('Tab in the code editor', () => { it('inserts four spaces at the caret instead of moving focus', async () => { const ta = await openEditor() const before = ta.value ta.setSelectionRange(0, 0) // fireEvent returns false when a handler called preventDefault, which is // what stops the browser tabbing focus over to the agent column. expect(tab(ta)).toBe(false) await waitFor(() => expect(ta.value).toBe(' ' + before)) }) it('indents every line a multi-line selection touches', async () => { const ta = await openEditor() const lines = ta.value.split('\n') // Select from inside line 1 to inside line 2. ta.setSelectionRange(1, lines[0].length + 2) tab(ta) await waitFor(() => { const now = ta.value.split('\n') expect(now[0]).toBe(' ' + lines[0]) expect(now[1]).toBe(' ' + lines[1]) expect(now[2]).toBe(lines[2]) }) }) it('Shift+Tab outdents the current line', async () => { const ta = await openEditor() ta.setSelectionRange(0, 0) tab(ta) await waitFor(() => expect(ta.value.startsWith(' ')).toBe(true)) ta.setSelectionRange(6, 6) expect(tab(ta, true)).toBe(false) await waitFor(() => expect(ta.value.startsWith(' ')).toBe(false)) }) })