fix(pty): retain send ownership through cancellation
This commit is contained in:
@@ -340,6 +340,60 @@ describe('LocalPtySession readiness and output', () => {
|
||||
await operation.done
|
||||
})
|
||||
|
||||
it('retains a canceled send until asynchronous foreground signalling settles', async () => {
|
||||
vi.useFakeTimers()
|
||||
const terminal = new FakeTerminal()
|
||||
const inspector = new FakeInspector()
|
||||
const session = makeSession(terminal, inspector, config())
|
||||
await initialize(session, terminal)
|
||||
|
||||
const signalGate = Promise.withResolvers<undefined>()
|
||||
terminal.signalForeground = async (signal) => {
|
||||
await signalGate.promise
|
||||
const foreground = await terminal.inspectForeground()
|
||||
if (foreground === undefined) throw new Error('cannot resolve foreground')
|
||||
inspector.signalGroup(foreground.processGroupId, signal)
|
||||
return foreground.processGroupId
|
||||
}
|
||||
const operation = session.startSend({ text: 'first', submit: true })
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
expect(operation.cancel()).toBe(true)
|
||||
|
||||
terminal.emitData('\x1b]133;D;130\x07dsh> ')
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(() => session.startSend({ text: 'successor', submit: true })).toThrow('active send')
|
||||
signalGate.resolve(undefined)
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
await operation.done
|
||||
expect(inspector.groups).toContainEqual([456, 'SIGINT'])
|
||||
expect(inspector.groups).not.toContainEqual([789, 'SIGINT'])
|
||||
})
|
||||
|
||||
it('does not resume cancellation polling after the terminal exits during signalling', async () => {
|
||||
vi.useFakeTimers()
|
||||
const terminal = new FakeTerminal()
|
||||
const inspector = new FakeInspector()
|
||||
const session = makeSession(terminal, inspector, config())
|
||||
await initialize(session, terminal)
|
||||
|
||||
const signalGate = Promise.withResolvers<undefined>()
|
||||
terminal.signalForeground = async () => {
|
||||
await signalGate.promise
|
||||
return 456
|
||||
}
|
||||
const operation = session.startSend({ text: 'first', submit: true })
|
||||
await Promise.resolve()
|
||||
await Promise.resolve()
|
||||
expect(operation.cancel()).toBe(true)
|
||||
terminal.emitExit(0)
|
||||
await expect(operation.done).resolves.toMatchObject({ waitReason: 'session_exit' })
|
||||
|
||||
signalGate.resolve(undefined)
|
||||
await vi.advanceTimersByTimeAsync(10)
|
||||
expect(session.status()).toEqual({ kind: 'exited', exitCode: 0, signal: null })
|
||||
})
|
||||
|
||||
it('retains send ownership after timeout until an asynchronous provider write settles', async () => {
|
||||
vi.useFakeTimers()
|
||||
const terminal = new FakeTerminal()
|
||||
|
||||
Reference in New Issue
Block a user