Skip to content

Commit 8ed3ab9

Browse files
committed
fix: await async command callbacks
1 parent fcb95c3 commit 8ed3ab9

2 files changed

Lines changed: 100 additions & 3 deletions

File tree

packages/js-sdk/src/sandbox/commands/commandHandle.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,11 @@ export class CommandHandle
226226
try {
227227
for await (const [stdout, stderr, pty] of this.iterateEvents()) {
228228
if (stdout !== null) {
229-
this.onStdout?.(stdout)
229+
await this.onStdout?.(stdout)
230230
} else if (stderr !== null) {
231-
this.onStderr?.(stderr)
231+
await this.onStderr?.(stderr)
232232
} else if (pty) {
233-
this.onPty?.(pty)
233+
await this.onPty?.(pty)
234234
}
235235
}
236236
} catch (e) {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import { describe, expect, it, vi } from 'vitest'
2+
3+
import { CommandHandle } from '../../../src/sandbox/commands/commandHandle'
4+
5+
type EventKind = 'stdout' | 'stderr' | 'pty'
6+
7+
function createEvents(kind: EventKind): AsyncIterable<any> {
8+
async function* events() {
9+
if (kind === 'pty') {
10+
yield {
11+
event: {
12+
event: {
13+
case: 'data',
14+
value: {
15+
output: {
16+
case: 'pty',
17+
value: new Uint8Array([1, 2, 3]),
18+
},
19+
},
20+
},
21+
},
22+
}
23+
} else {
24+
yield {
25+
event: {
26+
event: {
27+
case: 'data',
28+
value: {
29+
output: {
30+
case: kind,
31+
value: new TextEncoder().encode(kind),
32+
},
33+
},
34+
},
35+
},
36+
}
37+
}
38+
39+
yield {
40+
event: {
41+
event: {
42+
case: 'end',
43+
value: {
44+
exitCode: 0,
45+
error: undefined,
46+
},
47+
},
48+
},
49+
}
50+
}
51+
52+
return events()
53+
}
54+
55+
describe('CommandHandle', () => {
56+
it.each<EventKind>(['stdout', 'stderr', 'pty'])(
57+
'wait awaits async %s callbacks',
58+
async kind => {
59+
let callbackStarted = false
60+
let releaseCallback: (() => void) | undefined
61+
62+
const callbackBlocked = new Promise<void>(resolve => {
63+
releaseCallback = resolve
64+
})
65+
66+
const callback = async () => {
67+
callbackStarted = true
68+
await callbackBlocked
69+
}
70+
71+
const handle = new CommandHandle(
72+
1,
73+
() => {},
74+
async () => true,
75+
createEvents(kind),
76+
kind === 'stdout' ? callback : undefined,
77+
kind === 'stderr' ? callback : undefined,
78+
kind === 'pty' ? callback : undefined
79+
)
80+
81+
let waitResolved = false
82+
const waitPromise = handle.wait().then(() => {
83+
waitResolved = true
84+
})
85+
86+
await vi.waitFor(() => {
87+
expect(callbackStarted).toBe(true)
88+
})
89+
expect(waitResolved).toBe(false)
90+
91+
releaseCallback?.()
92+
await waitPromise
93+
94+
expect(waitResolved).toBe(true)
95+
}
96+
)
97+
})

0 commit comments

Comments
 (0)