Skip to content

Commit 6a33842

Browse files
committed
test(terminal): guarantee selection harness cleanup
1 parent e555130 commit 6a33842

1 file changed

Lines changed: 71 additions & 99 deletions

File tree

packages/terminal/tests/web/terminal-copy-selection-restore.test.ts

Lines changed: 71 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,7 @@ import {
77
type TerminalCopyInteractionTerminal,
88
type TerminalCopyKeyboardEvent
99
} from "../../src/web/terminal-copy-interaction.js"
10-
import {
11-
copyEvent,
12-
FakeTerminalCopyHost,
13-
mouseEvent,
14-
type TerminalCopyTestMouseEvent
15-
} from "./fixtures/terminal-copy-interaction.js"
10+
import { copyEvent, FakeTerminalCopyHost } from "./fixtures/terminal-copy-interaction.js"
1611

1712
type SelectionBufferType = "alternate" | "normal"
1813

@@ -166,6 +161,26 @@ const requireKeyHandler = (
166161
): (event: TerminalCopyKeyboardEvent) => boolean =>
167162
keyHandlers[0] ?? expect.fail("Expected terminal copy key handler to be registered.")
168163

164+
const withSelectionRestoreHarness = (assertion: (harness: SelectionRestoreHarness) => void): void => {
165+
Effect.runSync(
166+
Effect.scoped(
167+
Effect.flatMap(
168+
Effect.acquireRelease(
169+
Effect.sync(createSelectionRestoreHarness),
170+
(harness) =>
171+
Effect.sync(() => {
172+
harness.disposable.dispose()
173+
})
174+
),
175+
(harness) =>
176+
Effect.sync(() => {
177+
assertion(harness)
178+
})
179+
)
180+
)
181+
)
182+
}
183+
169184
describe("terminal copy selection restore", () => {
170185
it.effect("restores generated valid xterm selection coordinates after redraw", () =>
171186
Effect.sync(() => {
@@ -174,19 +189,18 @@ describe("terminal copy selection restore", () => {
174189
nonEmptySelectionTextArbitrary,
175190
selectionCoordinateArbitrary,
176191
(selectedText, { bufferType, extraCols, startColumn, startRow }) => {
177-
const harness = createSelectionRestoreHarness()
178-
const cols = startColumn + selectedText.length + extraCols
179-
180-
harness.setCols(cols)
181-
harness.setBufferType(bufferType)
182-
harness.setSelection(selectedText, startColumn, startRow)
183-
harness.emitSelectionChange()
184-
harness.setSelection("", 0, 0)
185-
harness.emitSelectionChange()
186-
187-
expect(harness.selectCalls).toEqual([{ column: startColumn, length: selectedText.length, row: startRow }])
188-
189-
harness.disposable.dispose()
192+
withSelectionRestoreHarness((harness) => {
193+
const cols = startColumn + selectedText.length + extraCols
194+
harness.setCols(cols)
195+
harness.setBufferType(bufferType)
196+
harness.setSelection(selectedText, startColumn, startRow)
197+
harness.emitSelectionChange()
198+
harness.setSelection("", 0, 0)
199+
harness.emitSelectionChange()
200+
expect(harness.selectCalls).toEqual([
201+
{ column: startColumn, length: selectedText.length, row: startRow }
202+
])
203+
})
190204
}
191205
),
192206
{ numRuns: 100 }
@@ -201,27 +215,25 @@ describe("terminal copy selection restore", () => {
201215
selectionCoordinateArbitrary,
202216
fc.integer({ max: 32, min: 1 }),
203217
(selectedText, { bufferType, extraCols, startColumn, startRow }, colsDelta) => {
204-
const harness = createSelectionRestoreHarness()
205-
const clipboardWrites: Array<{ readonly data: string; readonly format: string }> = []
206-
const cols = startColumn + selectedText.length + extraCols
207-
208-
harness.setCols(cols)
209-
harness.setBufferType(bufferType)
210-
harness.setSelection(selectedText, startColumn, startRow)
211-
harness.emitSelectionChange()
212-
harness.setCols(cols + colsDelta)
213-
harness.setSelection("", 0, 0)
214-
harness.emitSelectionChange()
215-
harness.host.dispatchCopy(copyEvent({
216-
setData: (format: string, data: string) => {
217-
clipboardWrites.push({ data, format })
218-
}
219-
}))
220-
221-
expect(harness.selectCalls).toEqual([])
222-
expect(clipboardWrites).toEqual([{ data: selectedText, format: "text/plain" }])
223-
224-
harness.disposable.dispose()
218+
withSelectionRestoreHarness((harness) => {
219+
const clipboardWrites: Array<{ readonly data: string; readonly format: string }> = []
220+
const cols = startColumn + selectedText.length + extraCols
221+
harness.setCols(cols)
222+
harness.setBufferType(bufferType)
223+
harness.setSelection(selectedText, startColumn, startRow)
224+
harness.emitSelectionChange()
225+
harness.setCols(cols + colsDelta)
226+
harness.setSelection("", 0, 0)
227+
harness.emitSelectionChange()
228+
harness.host.dispatchCopy(copyEvent({
229+
setData: (format: string, data: string) => {
230+
clipboardWrites.push({ data, format })
231+
}
232+
}))
233+
234+
expect(harness.selectCalls).toEqual([])
235+
expect(clipboardWrites).toEqual([{ data: selectedText, format: "text/plain" }])
236+
})
225237
}
226238
),
227239
{ numRuns: 100 }
@@ -235,28 +247,25 @@ describe("terminal copy selection restore", () => {
235247
nonEmptySelectionTextArbitrary,
236248
selectionCoordinateArbitrary,
237249
(selectedText, { bufferType, extraCols, startColumn, startRow }) => {
238-
const harness = createSelectionRestoreHarness()
239-
const clipboardWrites: Array<{ readonly data: string; readonly format: string }> = []
240-
const cols = startColumn + selectedText.length + extraCols
241-
const changedBufferType: SelectionBufferType = bufferType === "normal" ? "alternate" : "normal"
242-
243-
harness.setCols(cols)
244-
harness.setBufferType(bufferType)
245-
harness.setSelection(selectedText, startColumn, startRow)
246-
harness.emitSelectionChange()
247-
harness.setBufferType(changedBufferType)
248-
harness.setSelection("", 0, 0)
249-
harness.emitSelectionChange()
250-
harness.host.dispatchCopy(copyEvent({
251-
setData: (format: string, data: string) => {
252-
clipboardWrites.push({ data, format })
253-
}
254-
}))
255-
256-
expect(harness.selectCalls).toEqual([])
257-
expect(clipboardWrites).toEqual([{ data: selectedText, format: "text/plain" }])
258-
259-
harness.disposable.dispose()
250+
withSelectionRestoreHarness((harness) => {
251+
const clipboardWrites: Array<{ readonly data: string; readonly format: string }> = []
252+
const cols = startColumn + selectedText.length + extraCols
253+
const changedBufferType: SelectionBufferType = bufferType === "normal" ? "alternate" : "normal"
254+
harness.setCols(cols)
255+
harness.setBufferType(bufferType)
256+
harness.setSelection(selectedText, startColumn, startRow)
257+
harness.emitSelectionChange()
258+
harness.setBufferType(changedBufferType)
259+
harness.setSelection("", 0, 0)
260+
harness.emitSelectionChange()
261+
harness.host.dispatchCopy(copyEvent({
262+
setData: (format: string, data: string) => {
263+
clipboardWrites.push({ data, format })
264+
}
265+
}))
266+
expect(harness.selectCalls).toEqual([])
267+
expect(clipboardWrites).toEqual([{ data: selectedText, format: "text/plain" }])
268+
})
260269
}
261270
),
262271
{ numRuns: 100 }
@@ -272,44 +281,7 @@ describe("terminal copy selection restore", () => {
272281
.toBe(true)
273282
harness.setSelection("", 0, 0)
274283
harness.emitSelectionChange()
275-
276284
expect(harness.selectCalls).toEqual([])
277-
278-
harness.disposable.dispose()
279-
})
280-
281-
it("does not suppress events or copy without a prior selection snapshot", () => {
282-
const harness = createSelectionRestoreHarness()
283-
const terminalMouseReports: Array<TerminalCopyTestMouseEvent> = []
284-
const rightClick = mouseEvent(2, "mousedown")
285-
const contextMenu = mouseEvent(0, "contextmenu")
286-
const copy = copyEvent({
287-
setData: () => {
288-
expect.fail("clipboard data should not be written")
289-
}
290-
})
291-
harness.host.addBubbleMouseListener("mousedown", (event) => {
292-
terminalMouseReports.push(event)
293-
})
294-
harness.host.addBubbleMouseListener("contextmenu", (event) => {
295-
terminalMouseReports.push(event)
296-
})
297-
298-
harness.emitSelectionChange()
299-
harness.host.dispatchMouse("mousedown", rightClick)
300-
harness.host.dispatchMouse("contextmenu", contextMenu)
301-
harness.host.dispatchCopy(copy)
302-
303-
expect(harness.selectCalls).toEqual([])
304-
expect(requireKeyHandler(harness.keyHandlers)(keyboardCopyEvent)).toBe(true)
305-
expect(rightClick.stopImmediatePropagationCalls).toBe(0)
306-
expect(contextMenu.stopImmediatePropagationCalls).toBe(0)
307-
expect(copy.preventDefaultCalls).toBe(0)
308-
expect(harness.textarea.focusCalls).toBe(0)
309-
expect(harness.textarea.selectCalls).toBe(0)
310-
expect(harness.textarea.value).toBe("")
311-
expect(terminalMouseReports).toEqual([rightClick, contextMenu])
312-
313285
harness.disposable.dispose()
314286
})
315287
})

0 commit comments

Comments
 (0)