@@ -169,6 +169,109 @@ describe.skipIf(wasmSkip)('cross-runtime exec: node', () => {
169169 } , 15_000 ) ;
170170} ) ;
171171
172+ // ---------------------------------------------------------------------------
173+ // Node kernel.exec() stderr tests
174+ // ---------------------------------------------------------------------------
175+
176+ describe . skipIf ( wasmSkip ) ( 'cross-runtime exec: node stderr' , ( ) => {
177+ let ctx : IntegrationKernelResult ;
178+
179+ afterEach ( async ( ) => {
180+ await ctx ?. dispose ( ) ;
181+ } ) ;
182+
183+ it ( 'kernel.exec node -e with undefined var returns ReferenceError on stderr' , async ( ) => {
184+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
185+ const result = await ctx . kernel . exec ( 'node -e "lskdjf"' ) ;
186+ expect ( result . exitCode ) . not . toBe ( 0 ) ;
187+ expect ( result . stderr ) . toContain ( 'ReferenceError' ) ;
188+ } ) ;
189+
190+ it ( 'kernel.exec node -e throw Error returns message on stderr' , async ( ) => {
191+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
192+ const result = await ctx . kernel . exec ( 'node -e "throw new Error(\'boom\')"' ) ;
193+ expect ( result . exitCode ) . not . toBe ( 0 ) ;
194+ expect ( result . stderr ) . toContain ( 'boom' ) ;
195+ } ) ;
196+
197+ it ( 'kernel.exec node -e with syntax error returns SyntaxError on stderr' , async ( ) => {
198+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
199+ const result = await ctx . kernel . exec ( 'node -e "({"' ) ;
200+ expect ( result . exitCode ) . not . toBe ( 0 ) ;
201+ expect ( result . stderr ) . toContain ( 'SyntaxError' ) ;
202+ } ) ;
203+
204+ it ( 'kernel.exec node -e console.error returns stderr' , async ( ) => {
205+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
206+ const result = await ctx . kernel . exec ( 'node -e "console.error(\'ERRMSG\')"' ) ;
207+ expect ( result . stderr ) . toContain ( 'ERRMSG' ) ;
208+ expect ( result . exitCode ) . toBe ( 0 ) ;
209+ } ) ;
210+ } ) ;
211+
212+ // ---------------------------------------------------------------------------
213+ // Node cross-runtime terminal: stderr tests
214+ // ---------------------------------------------------------------------------
215+
216+ describe . skipIf ( wasmSkip ) ( 'cross-runtime terminal: node stderr' , ( ) => {
217+ let harness : TerminalHarness ;
218+ let ctx : IntegrationKernelResult ;
219+
220+ afterEach ( async ( ) => {
221+ await harness ?. dispose ( ) ;
222+ await ctx ?. dispose ( ) ;
223+ } ) ;
224+
225+ it ( 'node -e with undefined var shows ReferenceError on terminal' , async ( ) => {
226+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
227+ harness = new TerminalHarness ( ctx . kernel ) ;
228+
229+ await harness . waitFor ( PROMPT ) ;
230+ await harness . type ( 'node -e "lskdjf"\n' ) ;
231+ await harness . waitFor ( PROMPT , 2 , 10_000 ) ;
232+
233+ const screen = harness . screenshotTrimmed ( ) ;
234+ expect ( screen ) . toContain ( 'ReferenceError' ) ;
235+ } , 15_000 ) ;
236+
237+ it ( 'node -e throw Error shows error message on terminal' , async ( ) => {
238+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
239+ harness = new TerminalHarness ( ctx . kernel ) ;
240+
241+ await harness . waitFor ( PROMPT ) ;
242+ await harness . type ( 'node -e "throw new Error(\'boom\')"\n' ) ;
243+ await harness . waitFor ( PROMPT , 2 , 10_000 ) ;
244+
245+ const screen = harness . screenshotTrimmed ( ) ;
246+ expect ( screen ) . toContain ( 'boom' ) ;
247+ } , 15_000 ) ;
248+
249+ it ( 'node -e syntax error shows SyntaxError on terminal' , async ( ) => {
250+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
251+ harness = new TerminalHarness ( ctx . kernel ) ;
252+
253+ await harness . waitFor ( PROMPT ) ;
254+ await harness . type ( 'node -e "({"\n' ) ;
255+ await harness . waitFor ( PROMPT , 2 , 10_000 ) ;
256+
257+ const screen = harness . screenshotTrimmed ( ) ;
258+ expect ( screen ) . toContain ( 'SyntaxError' ) ;
259+ } , 15_000 ) ;
260+
261+ it ( 'stderr callback chain: NodeRuntimeDriver → ctx.onStderr → PTY slave' , async ( ) => {
262+ ctx = await createIntegrationKernel ( { runtimes : [ 'wasmvm' , 'node' ] } ) ;
263+ harness = new TerminalHarness ( ctx . kernel ) ;
264+
265+ await harness . waitFor ( PROMPT ) ;
266+ // console.error goes through onStdio → ctx.onStderr → PTY write
267+ await harness . type ( 'node -e "console.error(\'STDERRTEST\')"\n' ) ;
268+ await harness . waitFor ( PROMPT , 2 , 10_000 ) ;
269+
270+ const screen = harness . screenshotTrimmed ( ) ;
271+ expect ( screen ) . toContain ( 'STDERRTEST' ) ;
272+ } , 15_000 ) ;
273+ } ) ;
274+
172275// ---------------------------------------------------------------------------
173276// Python cross-runtime terminal tests
174277// ---------------------------------------------------------------------------
0 commit comments