97 lines
3.7 KiB
TypeScript
97 lines
3.7 KiB
TypeScript
// @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 renderApp(): HTMLElement {
|
|
return render(<ProjectProvider><App /></ProjectProvider>).container
|
|
}
|
|
function find(c: HTMLElement, sel: string, text: string): HTMLElement | undefined {
|
|
return Array.from(c.querySelectorAll<HTMLElement>(sel)).find((el) => el.textContent?.includes(text))
|
|
}
|
|
// The tree opens fully collapsed, so expand each ancestor folder before reaching
|
|
// a nested file. Each folder is clicked exactly once (a second click collapses).
|
|
async function expandTo(c: HTMLElement, ...folders: string[]): Promise<void> {
|
|
for (const name of folders) {
|
|
const row = await waitFor(() => {
|
|
const r = find(c, '.tree-row', name)
|
|
if (!r) throw new Error(`folder ${name} not ready`)
|
|
return r
|
|
})
|
|
fireEvent.click(row)
|
|
}
|
|
}
|
|
|
|
describe('Pass on to Agent', () => {
|
|
it('inserts "<note> <path:line>" via the agentPaste event', async () => {
|
|
const received: string[] = []
|
|
const handler = (e: Event): void => { received.push((e as CustomEvent<string>).detail) }
|
|
window.addEventListener('agentPaste', handler)
|
|
try {
|
|
const c = renderApp()
|
|
await expandTo(c, 'public', 'assets')
|
|
const treeRow = await waitFor(() => {
|
|
const r = find(c, '.tree-row', 'store.js')
|
|
if (!r) throw new Error('tree not ready')
|
|
return r
|
|
})
|
|
fireEvent.click(treeRow)
|
|
const ta = await waitFor(() => {
|
|
const t = c.querySelector<HTMLTextAreaElement>('.ce-ta')
|
|
if (!t) throw new Error('editor not ready')
|
|
return t
|
|
})
|
|
fireEvent.contextMenu(ta)
|
|
const pass = await waitFor(() => {
|
|
const item = find(c, '.ctx-item', 'Pass on to Agent')
|
|
if (!item) throw new Error('menu not open')
|
|
return item
|
|
})
|
|
fireEvent.click(pass)
|
|
const input = await waitFor(() => {
|
|
const i = c.querySelector<HTMLInputElement>('.pass-input')
|
|
if (!i) throw new Error('popup not open')
|
|
return i
|
|
})
|
|
fireEvent.change(input, { target: { value: 'look here' } })
|
|
fireEvent.keyDown(input, { key: 'Enter' })
|
|
await waitFor(() => expect(received.length).toBeGreaterThan(0))
|
|
expect(received[0]).toBe('look here public/assets/store.js:1')
|
|
} finally {
|
|
window.removeEventListener('agentPaste', handler)
|
|
}
|
|
})
|
|
})
|
|
|
|
describe('Stage + commit', () => {
|
|
it('stages a file and commits via Shift+Enter (no commit button)', async () => {
|
|
const c = renderApp()
|
|
const row = await waitFor(() => {
|
|
const r = find(c, '.git-row', 'UserController.php')
|
|
if (!r) throw new Error('git not ready')
|
|
return r
|
|
})
|
|
fireEvent.click(row.querySelector<HTMLButtonElement>('button[title="Stage changes"]')!)
|
|
// the commit button is intentionally gone — committing is keyboard-only
|
|
expect(c.querySelector('.commit-btn')).toBeNull()
|
|
const msg = c.querySelector<HTMLTextAreaElement>('.commit-input')!
|
|
fireEvent.change(msg, { target: { value: 'wire up balance' } })
|
|
fireEvent.keyDown(msg, { key: 'Enter', shiftKey: true })
|
|
await waitFor(() => expect(find(c, '.toast', 'Committed')).toBeTruthy())
|
|
})
|
|
})
|