@@ -272,6 +272,62 @@ describe("shell-terminal", () => {
272272
273273 expect ( harness . screenshotTrimmed ( ) ) . toBe ( screenAfterNoecho ) ;
274274 } ) ;
275+
276+ it ( "waitFor occurrence=2 — waits for second appearance of text" , async ( ) => {
277+ const driver = new MockShellDriver ( ) ;
278+ const { kernel } = await createTestKernel ( { drivers : [ driver ] } ) ;
279+ harness = new TerminalHarness ( kernel ) ;
280+
281+ await harness . waitFor ( "$" ) ;
282+
283+ // Run command: screen shows "$ echo AAA\nAAA\n$ " — "AAA" appears twice
284+ await harness . type ( "echo AAA\n" ) ;
285+
286+ // occurrence=2 should succeed (once in echoed command line, once in output)
287+ await harness . waitFor ( "AAA" , 2 ) ;
288+
289+ expect ( harness . screenshotTrimmed ( ) ) . toBe (
290+ [ "$ echo AAA" , "AAA" , "$ " ] . join ( "\n" ) ,
291+ ) ;
292+ } ) ;
293+
294+ it ( "waitFor occurrence=3 on text appearing twice — times out" , async ( ) => {
295+ const driver = new MockShellDriver ( ) ;
296+ const { kernel } = await createTestKernel ( { drivers : [ driver ] } ) ;
297+ harness = new TerminalHarness ( kernel ) ;
298+
299+ await harness . waitFor ( "$" ) ;
300+ await harness . type ( "echo AAA\n" ) ;
301+
302+ // "AAA" appears only twice — occurrence=3 should timeout
303+ await expect (
304+ harness . waitFor ( "AAA" , 3 , 200 ) ,
305+ ) . rejects . toThrow ( / t i m e d o u t / ) ;
306+ } ) ;
307+
308+ it ( "type() on no-output input — resolves via settlement timer" , async ( ) => {
309+ const driver = new MockShellDriver ( ) ;
310+ const { kernel } = await createTestKernel ( { drivers : [ driver ] } ) ;
311+ harness = new TerminalHarness ( kernel ) ;
312+
313+ await harness . waitFor ( "$" ) ;
314+
315+ // Disable echo so typed text produces zero output
316+ await harness . type ( "noecho\n" ) ;
317+
318+ // type() with echo off and no newline → zero output produced.
319+ // Settlement timer fires after SETTLE_MS (50ms), resolving the promise.
320+ const start = Date . now ( ) ;
321+ await harness . type ( "silent" ) ;
322+ const elapsed = Date . now ( ) - start ;
323+
324+ // Should resolve in roughly SETTLE_MS (50ms), not hang or instant
325+ expect ( elapsed ) . toBeGreaterThanOrEqual ( 30 ) ;
326+ expect ( elapsed ) . toBeLessThan ( 500 ) ;
327+
328+ // Screen unchanged — "silent" is not visible because echo is off
329+ expect ( harness . screenshotTrimmed ( ) ) . toBe ( [ "$ noecho" , "$ " ] . join ( "\n" ) ) ;
330+ } ) ;
275331} ) ;
276332
277333// ---------------------------------------------------------------------------
0 commit comments