@@ -23,17 +23,22 @@ const shellOpts = {
2323} as const
2424
2525/**
26- * Markdown blocks highlight asynchronously; settle before capturing a frame.
27- * A row with several top-level blocks (heading, list, fence, link) resolves
28- * its highlight promises one render at a time, so a fixed couple of ticks
29- * that was enough for one block is not enough for several .
26+ * Highlighting runs on a worker outside the render scheduler, so the
27+ * scheduler goes idle before the highlighted frame lands. Pass a predicate
28+ * for the settled shape and get the frame back the moment it's true, rather
29+ * than gambling on a fixed sleep long enough to outrun load .
3030 */
31- async function settle ( h : Harness ) : Promise < string > {
32- for ( let i = 0 ; i < 8 ; i += 1 ) {
33- await new Promise ( ( resolve ) => setTimeout ( resolve , 50 ) )
31+ async function settle ( h : Harness , isSettled : ( frame : string ) => boolean ) : Promise < string > {
32+ const deadline = Date . now ( ) + 2000
33+ for ( ; ; ) {
3434 await h . renderOnce ( )
35+ const frame = h . captureCharFrame ( )
36+ if ( isSettled ( frame ) ) return frame
37+ if ( Date . now ( ) >= deadline ) {
38+ throw new Error ( `markdown row never settled; last frame:\n${ frame } ` )
39+ }
40+ await new Promise ( ( resolve ) => setTimeout ( resolve , 20 ) )
3541 }
36- return h . captureCharFrame ( )
3742}
3843
3944describe ( "markdown transcript rows" , ( ) => {
@@ -68,7 +73,10 @@ describe("markdown transcript rows", () => {
6873 ] . join ( "\n" ) ,
6974 } )
7075
71- const frame = await settle ( h )
76+ const frame = await settle (
77+ h ,
78+ ( f ) => f . includes ( "docs" ) && ! f . includes ( "## Title" ) && ! f . includes ( "**bolded**" ) ,
79+ )
7280 expect ( frame ) . toContain ( "Title" )
7381 expect ( frame ) . not . toContain ( "## Title" )
7482 expect ( frame ) . toContain ( "bolded" )
@@ -94,7 +102,10 @@ describe("markdown transcript rows", () => {
94102 ] . join ( "\n" ) ,
95103 } )
96104
97- const frame = await settle ( h )
105+ const frame = await settle (
106+ h ,
107+ ( f ) => f . includes ( "What the site is" ) && ! f . includes ( "###" ) && ! f . includes ( "**Hardware:**" ) ,
108+ )
98109 expect ( frame ) . toContain ( "What the site is" )
99110 expect ( frame ) . not . toContain ( "###" )
100111 expect ( frame ) . toContain ( "Hardware:" )
@@ -108,7 +119,7 @@ describe("markdown transcript rows", () => {
108119 appendStreamRow ( shell , { role : "tool" , text : "## not a heading" } )
109120 appendStreamRow ( shell , { role : "system" , text : "**raw**" } )
110121
111- const frame = await settle ( h )
122+ const frame = await settle ( h , ( f ) => f . includes ( "**raw**" ) )
112123 expect ( frame ) . toContain ( "## not a heading" )
113124 expect ( frame ) . toContain ( "**raw**" )
114125 } , WIDE )
@@ -123,7 +134,10 @@ describe("markdown transcript rows", () => {
123134 text : [ "## Done" , "" , "```ts" , "const partial = " ] . join ( "\n" ) ,
124135 } )
125136
126- const frame = await settle ( h )
137+ const frame = await settle (
138+ h ,
139+ ( f ) => f . includes ( "Done" ) && ! f . includes ( "## Done" ) && f . includes ( "const partial =" ) ,
140+ )
127141 expect ( frame ) . toContain ( "Done" )
128142 expect ( frame ) . not . toContain ( "## Done" )
129143 expect ( frame ) . toContain ( "const partial =" )
@@ -143,7 +157,7 @@ describe("markdown transcript rows", () => {
143157 // literal text and the row paints the bare markers until the title's
144158 // first character lands. Held back instead, so the line's classification
145159 // cannot flip under text already on screen.
146- const frame = await settle ( h )
160+ const frame = await settle ( h , ( f ) => f . includes ( "Some body text." ) && ! f . includes ( "####" ) )
147161 expect ( frame ) . toContain ( "Some body text." )
148162 expect ( frame ) . not . toContain ( "####" )
149163
@@ -152,7 +166,7 @@ describe("markdown transcript rows", () => {
152166 streaming : true ,
153167 text : [ "Some body text." , "" , "#### Title" ] . join ( "\n" ) ,
154168 } )
155- const next = await settle ( h )
169+ const next = await settle ( h , ( f ) => f . includes ( "Title" ) && ! f . includes ( "#### Title" ) )
156170 expect ( next ) . toContain ( "Title" )
157171 expect ( next ) . not . toContain ( "#### Title" )
158172 } , WIDE )
@@ -240,7 +254,7 @@ describe("markdown transcript rows", () => {
240254 role : "assistant" ,
241255 text : [ "### Title" , "" , "Here is the list:" , "- alpha" , "- beta" ] . join ( "\n" ) ,
242256 } )
243- const frame = await settle ( h )
257+ const frame = await settle ( h , ( f ) => f . includes ( "alpha" ) )
244258 const lines = frame . split ( "\n" ) . map ( ( line ) => line . trimEnd ( ) )
245259 const listLine = lines . findIndex ( ( line ) => line . includes ( "Here is the list:" ) )
246260 expect ( listLine ) . toBeGreaterThan ( - 1 )
@@ -257,7 +271,7 @@ describe("markdown transcript rows", () => {
257271 role : "assistant" ,
258272 text : [ "### Steps" , "" , ...items ] . join ( "\n" ) ,
259273 } )
260- const frame = await settle ( h )
274+ const frame = await settle ( h , ( f ) => f . includes ( "10. item 10" ) )
261275 expect ( frame ) . toContain ( "1. item 1" )
262276 expect ( frame ) . toContain ( "10. item 10" )
263277 } , WIDE )
@@ -290,7 +304,8 @@ describe("markdown transcript rows", () => {
290304 } )
291305 // Warm up once: the first highlight pass in a process loads the
292306 // tree-sitter grammar and is not itself part of what this test samples.
293- const baseline = await settle ( h ) . then ( ( ) => headingSpan ( h ) )
307+ await settle ( h , ( ) => headingSpan ( h ) !== null )
308+ const baseline = headingSpan ( h )
294309 expect ( baseline ) . not . toBeNull ( )
295310
296311 for ( let i = 2 ; i <= full . length ; i += 1 ) {
@@ -375,7 +390,10 @@ describe("markdown transcript rows", () => {
375390 "more prose streaming in" ,
376391 ] . join ( "\n" ) ,
377392 } )
378- const frame = await settle ( h )
393+ const frame = await settle (
394+ h ,
395+ ( f ) => f . includes ( "# this is a comment, not a heading" ) && f . includes ( "more prose streaming in" ) ,
396+ )
379397 expect ( frame ) . toContain ( "# this is a comment, not a heading" )
380398 expect ( frame ) . toContain ( "echo hi" )
381399 expect ( frame ) . toContain ( "more prose streaming in" )
0 commit comments