61 lines
2.6 KiB
TypeScript
61 lines
2.6 KiB
TypeScript
/**
|
|
* TerminalWaitBanner unit tests: localized text with the needle, the skip
|
|
* button wiring, and the long-needle display cap (full text stays on the
|
|
* title attribute). The component imports no xterm — renderable in plain
|
|
* jsdom (the repo's jsdom pattern, see bottom-auto-terminal.spec.tsx head).
|
|
*/
|
|
// @vitest-environment jsdom
|
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
import { createElement } from 'react'
|
|
import { createRoot, type Root } from 'react-dom/client'
|
|
import { act } from 'react-dom/test-utils'
|
|
import { setupReactAct } from './test-utils.ts'
|
|
setupReactAct()
|
|
|
|
import { TerminalWaitBanner } from '../src/client/TerminalWaitBanner.tsx'
|
|
|
|
describe('TerminalWaitBanner', () => {
|
|
const mounted: Array<{ root: Root; container: HTMLDivElement }> = []
|
|
function mount(needle: string, onSkip: () => void): HTMLDivElement {
|
|
const container = document.createElement('div')
|
|
document.body.append(container)
|
|
const root = createRoot(container)
|
|
act(() => { root.render(createElement(TerminalWaitBanner, { needle, onSkip })) })
|
|
mounted.push({ root, container })
|
|
return container
|
|
}
|
|
afterEach(() => {
|
|
for (const { root, container } of mounted.splice(0)) {
|
|
act(() => { root.unmount() })
|
|
container.remove()
|
|
}
|
|
})
|
|
|
|
it('shows the localized waiting text with the needle and a working skip button', () => {
|
|
let skipped = 0
|
|
const container = mount('BUILD_OK', () => { skipped += 1 })
|
|
// jsdom navigator.language is en-US → the en dictionary applies.
|
|
expect(container.textContent).toContain('Agent is waiting for')
|
|
expect(container.textContent).toContain('BUILD_OK')
|
|
expect(container.textContent).toContain('Skip wait')
|
|
const button = container.querySelector('button')
|
|
expect(button).not.toBeNull()
|
|
act(() => { button!.dispatchEvent(new MouseEvent('click', { bubbles: true })) })
|
|
expect(skipped).toBe(1)
|
|
})
|
|
|
|
it('truncates a long needle for display but keeps the full text on the title', () => {
|
|
const long = 'X'.repeat(200)
|
|
const container = mount(long, () => {})
|
|
const span = container.querySelector('span[title]')
|
|
expect(span).not.toBeNull()
|
|
expect(span!.getAttribute('title')).toBe(long)
|
|
// The needle's inline contribution is capped (NEEDLE_DISPLAY_CAP): at
|
|
// most 80 X's are rendered — the full 200-char run only rides the title
|
|
// tooltip. The localized sentence around the needle is not measured;
|
|
// its length varies per language, so counting the needle's own chars is
|
|
// the language-agnostic form of the display-cap assertion.
|
|
expect((span!.textContent?.match(/X/g) ?? []).length).toBeLessThanOrEqual(80)
|
|
})
|
|
})
|