1- // QuickJS-based tests for the pure logic in theme/default/js/run.js.
1+ // QuickJS-based tests for the pure logic in theme/default/js/run.js and
2+ // theme/default/js/run-worker.js.
23// Run with: qjs test/js/test_run.mjs (see the "test:js" rake task)
3- // Importing the module doubles as a syntax/eval smoke test: its DOM setup is
4- // guarded by `typeof window !== 'undefined'`.
5- import { createOnceLoader , PRELUDE , formatRunError , truncateOutput } from '../../theme/default/js/run.js'
4+ // Importing each module doubles as a syntax/eval smoke test: run.js's DOM
5+ // setup is guarded by `typeof window !== 'undefined'`, and run-worker.js's
6+ // Worker setup is guarded by `typeof self !== 'undefined' && typeof
7+ // WorkerGlobalScope !== 'undefined'` -- neither exists under QuickJS, so
8+ // importing either file here never touches a real DOM/Worker.
9+ import {
10+ createOnceLoader , formatRunError , truncateOutput ,
11+ accumulateOutput , STOPPED_NOTE , timeoutNote ,
12+ } from '../../theme/default/js/run.js'
13+ import { PRELUDE , formatRunError as formatWorkerRunError } from '../../theme/default/js/run-worker.js'
614
715let failures = 0
816function assert ( cond , message ) {
@@ -52,11 +60,20 @@ function assert(cond, message) {
5260 'next call after a rejection retries the load' )
5361}
5462
55- // PRELUDE captures both streams into one StringIO
56- assert ( PRELUDE . includes ( 'require "stringio"' ) &&
57- PRELUDE . includes ( '$stdout = StringIO.new' ) &&
63+ // PRELUDE (run-worker.js) streams both channels to the main thread via the
64+ // JS bridge, instead of buffering into a StringIO like the old single-eval
65+ // PRELUDE did.
66+ assert ( PRELUDE . includes ( 'require "js"' ) &&
67+ PRELUDE . includes ( 'JS.global.call(:postOutput, text)' ) &&
68+ PRELUDE . includes ( '$stdout = JSStreamIO.new' ) &&
5869 PRELUDE . includes ( '$stderr = $stdout' ) ,
59- 'PRELUDE redirects $stdout and $stderr into one StringIO' )
70+ 'PRELUDE redirects $stdout and $stderr through postOutput()' )
71+
72+ // run-worker.js's formatRunError is the same shape as run.js's copy (each
73+ // runs in its own realm -- main thread vs. worker -- so it is a small
74+ // intentional duplication rather than an import cycle across the two files)
75+ assert ( formatWorkerRunError ( new Error ( 'boom' ) ) === 'boom' ,
76+ 'run-worker.js formatRunError matches run.js formatRunError' )
6077
6178// formatRunError
6279assert ( formatRunError ( new Error ( 'boom' ) ) === 'boom' ,
@@ -78,6 +95,31 @@ assert(truncateOutput('short') === 'short', 'truncateOutput keeps short output')
7895 'truncateOutput cuts long output with a marker' )
7996}
8097
98+ // accumulateOutput: incremental version of truncateOutput, used to append
99+ // each Worker 'output' message to what is already on screen.
100+ assert ( accumulateOutput ( 'foo' , 'bar' ) === 'foobar' ,
101+ 'accumulateOutput appends a chunk to the existing text' )
102+ assert ( accumulateOutput ( '' , 'first' ) === 'first' ,
103+ 'accumulateOutput handles an empty starting value' )
104+ {
105+ const grown = accumulateOutput ( 'x' . repeat ( 8 ) , 'y' . repeat ( 8 ) , 10 )
106+ assert ( grown === 'x' . repeat ( 8 ) + 'y' . repeat ( 2 ) + '\n... (truncated)' ,
107+ 'accumulateOutput truncates once the cap is crossed mid-chunk' )
108+ }
109+ {
110+ // A chunk arriving after the cap was already hit must be a no-op, not a
111+ // second "... (truncated)" marker or renewed growth.
112+ const alreadyTruncated = truncateOutput ( 'x' . repeat ( 20 ) , 10 )
113+ const next = accumulateOutput ( alreadyTruncated , 'more output' , 10 )
114+ assert ( next === alreadyTruncated ,
115+ 'accumulateOutput drops further chunks once truncated' )
116+ }
117+
118+ // STOPPED_NOTE / timeoutNote: the notes appended to output on STOP / timeout
119+ assert ( STOPPED_NOTE === '(停止しました)' , 'STOPPED_NOTE is the stop notice' )
120+ assert ( timeoutNote ( 30 ) === '(30秒でタイムアウトしました)' ,
121+ 'timeoutNote formats the configured timeout in seconds' )
122+
81123if ( failures > 0 ) {
82124 throw new Error ( failures + ' JS test(s) failed' )
83125}
0 commit comments