Skip to content

Commit be8fd38

Browse files
committed
test(coverage): cmd-nuget + cmd-bundler both-null exit/signal branch
1 parent b01bcaa commit be8fd38

4 files changed

Lines changed: 91 additions & 7 deletions

File tree

packages/cli/src/utils/output/scrubber.mts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ export function trace(
162162
): void {
163163
if (isTraceEnabled()) {
164164
const prefix = adapterName ? `${adapterName}:${verdict}` : verdict
165-
process.stderr.write(`[scrub ${prefix}] ${line}\n`)
165+
// Direct stderr write (not via logger) bypasses the routed noise
166+
// stream so trace lines don't interleave with buffered scrubber output.
167+
process.stderr.write(`[scrub ${prefix}] ${line}\n`) // socket-hook: allow logger
166168
}
167169
}
168170

packages/cli/src/utils/terminal/FramedHeader.mts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export async function renderFramedHeader(
4141
): Promise<void> {
4242
const { animate = true, fps = 15, theme = 'default' } = props || {}
4343

44-
// Hide cursor.
45-
process.stdout.write('\x1B[?25l')
44+
// Hide cursor — raw ANSI escape, must hit stdout directly.
45+
process.stdout.write('\x1B[?25l') // socket-hook: allow logger
4646

4747
let frame = 0
4848
const frameDelay = 1000 / fps
@@ -52,8 +52,8 @@ export async function renderFramedHeader(
5252
const width = 40
5353
const framedLogo = drawBorder(logo, width)
5454

55-
// Move cursor to home and clear from cursor down.
56-
process.stdout.write('\x1B[H\x1B[J')
55+
// Move cursor home + clear from cursor down — raw ANSI, direct stdout.
56+
process.stdout.write('\x1B[H\x1B[J') // socket-hook: allow logger
5757
logger.log(`\nTheme: ${theme} | Frame: ${frame}\n`)
5858
logger.log(framedLogo)
5959

@@ -62,7 +62,8 @@ export async function renderFramedHeader(
6262

6363
if (!animate) {
6464
renderFrame()
65-
process.stdout.write('\x1B[?25h')
65+
// Restore cursor — raw ANSI, direct stdout.
66+
process.stdout.write('\x1B[?25h') // socket-hook: allow logger
6667
return
6768
}
6869

@@ -71,7 +72,8 @@ export async function renderFramedHeader(
7172

7273
const cleanup = () => {
7374
clearInterval(interval)
74-
process.stdout.write('\x1B[?25h')
75+
// Restore cursor — raw ANSI, direct stdout.
76+
process.stdout.write('\x1B[?25h') // socket-hook: allow logger
7577
}
7678

7779
// Handle cleanup on interrupt.

packages/cli/test/unit/commands/bundler/cmd-bundler.test.mts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,45 @@ describe('cmd-bundler', () => {
175175
})
176176

177177
describe('exit handling', () => {
178+
it('skips exit/kill when both code and signal are null', async () => {
179+
const mockChildProcess = new EventEmitter()
180+
const mockSpawnPromise = Promise.resolve({
181+
code: null,
182+
signal: null,
183+
stderr: Buffer.from(''),
184+
stdout: Buffer.from(''),
185+
})
186+
;(mockSpawnPromise as any).process = mockChildProcess
187+
188+
mockSpawnSfwDlx.mockResolvedValue({ spawnPromise: mockSpawnPromise })
189+
mockFilterFlags.mockReturnValue([])
190+
191+
const mockExit = vi
192+
.spyOn(process, 'exit')
193+
.mockImplementation((() => {}) as any)
194+
mockExit.mockClear()
195+
const mockKill = vi
196+
.spyOn(process, 'kill')
197+
.mockImplementation((() => {}) as any)
198+
mockKill.mockClear()
199+
200+
cmdBundler.run([], importMeta, context)
201+
202+
await new Promise(resolve => setImmediate(resolve))
203+
const exitBefore = mockExit.mock.calls.length
204+
const killBefore = mockKill.mock.calls.length
205+
206+
mockChildProcess.emit('exit', null, null)
207+
208+
await new Promise(resolve => setImmediate(resolve))
209+
210+
expect(mockExit.mock.calls.length).toBe(exitBefore)
211+
expect(mockKill.mock.calls.length).toBe(killBefore)
212+
213+
mockExit.mockRestore()
214+
mockKill.mockRestore()
215+
})
216+
178217
it('should set default exit code to 1 before child process exits', async () => {
179218
const mockChildProcess = new EventEmitter()
180219
const mockSpawnPromise = Promise.resolve({

packages/cli/test/unit/commands/nuget/cmd-nuget.test.mts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,47 @@ describe('cmd-nuget', () => {
215215
})
216216
})
217217

218+
it('skips exit/kill when both code and signal are null', async () => {
219+
const mockChildProcess = new EventEmitter()
220+
const mockSpawnPromise = Promise.resolve({
221+
code: null,
222+
signal: null,
223+
stderr: Buffer.from(''),
224+
stdout: Buffer.from(''),
225+
})
226+
;(mockSpawnPromise as any).process = mockChildProcess
227+
228+
mockSpawnSfwDlx.mockResolvedValue({ spawnPromise: mockSpawnPromise })
229+
mockFilterFlags.mockReturnValue([])
230+
231+
const mockExit = vi
232+
.spyOn(process, 'exit')
233+
.mockImplementation((() => {}) as any)
234+
mockExit.mockClear()
235+
const mockKill = vi
236+
.spyOn(process, 'kill')
237+
.mockImplementation((() => {}) as any)
238+
mockKill.mockClear()
239+
240+
cmdNuget.run([], { url: import.meta.url } as any, {
241+
parentName: 'socket',
242+
} as any)
243+
244+
await new Promise(resolve => setImmediate(resolve))
245+
const exitBefore = mockExit.mock.calls.length
246+
const killBefore = mockKill.mock.calls.length
247+
248+
mockChildProcess.emit('exit', null, null)
249+
250+
await new Promise(resolve => setImmediate(resolve))
251+
252+
expect(mockExit.mock.calls.length).toBe(exitBefore)
253+
expect(mockKill.mock.calls.length).toBe(killBefore)
254+
255+
mockExit.mockRestore()
256+
mockKill.mockRestore()
257+
})
258+
218259
it('should set default exit code to 1', async () => {
219260
const mockChildProcess = new EventEmitter()
220261
const mockSpawnPromise = Promise.resolve({

0 commit comments

Comments
 (0)