1- // https://github.com/nodejs/node/blob/9825a7e01d35b9d49ebb58efed2c316012c19db6 /lib/internal/test_runner/runner.js
1+ // https://github.com/nodejs/node/blob/f8ce9117b19702487eb600493d941f7876e00e01 /lib/internal/test_runner/runner.js
22'use strict'
33const {
44 ArrayFrom,
55 ArrayPrototypeFilter,
6+ ArrayPrototypeForEach,
67 ArrayPrototypeIncludes,
78 ArrayPrototypeJoin,
89 ArrayPrototypePush,
@@ -11,7 +12,8 @@ const {
1112 ObjectAssign,
1213 PromisePrototypeThen,
1314 SafePromiseAll,
14- SafeSet
15+ SafeSet,
16+ StringPrototypeRepeat
1517} = require ( '#internal/per_context/primordials' )
1618
1719const { spawn } = require ( 'child_process' )
@@ -28,7 +30,9 @@ const { validateArray } = require('#internal/validators')
2830const { getInspectPort, isUsingInspector, isInspectorMessage } = require ( '#internal/util/inspector' )
2931const { kEmptyObject } = require ( '#internal/util' )
3032const { createTestTree } = require ( '#internal/test_runner/harness' )
31- const { kSubtestsFailed, Test } = require ( '#internal/test_runner/test' )
33+ const { kDefaultIndent, kSubtestsFailed, Test } = require ( '#internal/test_runner/test' )
34+ const { TapParser } = require ( '#internal/test_runner/tap_parser' )
35+ const { TokenKind } = require ( '#internal/test_runner/tap_lexer' )
3236const {
3337 isSupportedFileType,
3438 doesPathMatchFilter
@@ -114,16 +118,117 @@ function getRunArgs ({ path, inspectPort }) {
114118 return argv
115119}
116120
117- function runTestFile ( path , root , inspectPort ) {
118- const subtest = root . createSubtest ( Test , path , async ( t ) => {
121+ class FileTest extends Test {
122+ #buffer = [ ]
123+ #handleReportItem ( { kind, node, nesting = 0 } ) {
124+ const indent = StringPrototypeRepeat ( kDefaultIndent , nesting + 1 )
125+
126+ const details = ( diagnostic ) => {
127+ return (
128+ diagnostic && {
129+ __proto__ : null ,
130+ yaml :
131+ `${ indent } ` +
132+ ArrayPrototypeJoin ( diagnostic , `\n${ indent } ` ) +
133+ '\n'
134+ }
135+ )
136+ }
137+
138+ switch ( kind ) {
139+ case TokenKind . TAP_VERSION :
140+ // TODO(manekinekko): handle TAP version coming from the parser.
141+ // this.reporter.version(node.version);
142+ break
143+
144+ case TokenKind . TAP_PLAN :
145+ this . reporter . plan ( indent , node . end - node . start + 1 )
146+ break
147+
148+ case TokenKind . TAP_SUBTEST_POINT :
149+ this . reporter . subtest ( indent , node . name )
150+ break
151+
152+ case TokenKind . TAP_TEST_POINT :
153+ // eslint-disable-next-line no-case-declarations
154+ const { todo, skip, pass } = node . status
155+ // eslint-disable-next-line no-case-declarations
156+ let directive
157+
158+ if ( skip ) {
159+ directive = this . reporter . getSkip ( node . reason )
160+ } else if ( todo ) {
161+ directive = this . reporter . getTodo ( node . reason )
162+ } else {
163+ directive = kEmptyObject
164+ }
165+
166+ if ( pass ) {
167+ this . reporter . ok (
168+ indent ,
169+ node . id ,
170+ node . description ,
171+ details ( node . diagnostics ) ,
172+ directive
173+ )
174+ } else {
175+ this . reporter . fail (
176+ indent ,
177+ node . id ,
178+ node . description ,
179+ details ( node . diagnostics ) ,
180+ directive
181+ )
182+ }
183+ break
184+
185+ case TokenKind . COMMENT :
186+ if ( indent === kDefaultIndent ) {
187+ // Ignore file top level diagnostics
188+ break
189+ }
190+ this . reporter . diagnostic ( indent , node . comment )
191+ break
192+
193+ case TokenKind . UNKNOWN :
194+ this . reporter . diagnostic ( indent , node . value )
195+ break
196+ }
197+ }
198+
199+ addToReport ( ast ) {
200+ if ( ! this . isClearToSend ( ) ) {
201+ ArrayPrototypePush ( this . #buffer, ast )
202+ return
203+ }
204+ this . reportSubtest ( )
205+ this . #handleReportItem( ast )
206+ }
207+
208+ report ( ) {
209+ this . reportSubtest ( )
210+ ArrayPrototypeForEach ( this . #buffer, ( ast ) => this . #handleReportItem( ast ) )
211+ super . report ( )
212+ }
213+ }
214+
215+ function runTestFile ( path , root , inspectPort , filesWatcher ) {
216+ const subtest = root . createSubtest ( FileTest , path , async ( t ) => {
119217 const args = getRunArgs ( { path, inspectPort } )
218+ const stdio = [ 'pipe' , 'pipe' , 'pipe' ]
219+ const env = { ...process . env }
220+ if ( filesWatcher ) {
221+ stdio . push ( 'ipc' )
222+ env . WATCH_REPORT_DEPENDENCIES = '1'
223+ }
224+
225+ const child = spawn ( process . execPath , args , { signal : t . signal , encoding : 'utf8' , env, stdio } )
120226
121- const child = spawn ( process . execPath , args , { signal : t . signal , encoding : 'utf8' } )
122- // TODO(cjihrig): Implement a TAP parser to read the child's stdout
123- // instead of just displaying it all if the child fails.
124227 let err
125228 let stderr = ''
126229
230+ filesWatcher ?. watchChildProcessModules ( child , path )
231+
127232 child . on ( 'error' , ( error ) => {
128233 err = error
129234 } )
@@ -141,6 +246,17 @@ function runTestFile (path, root, inspectPort) {
141246 } )
142247 }
143248
249+ const parser = new TapParser ( )
250+ child . stderr . pipe ( parser ) . on ( 'data' , ( ast ) => {
251+ if ( ast . lexeme && isInspectorMessage ( ast . lexeme ) ) {
252+ process . stderr . write ( ast . lexeme + '\n' )
253+ }
254+ } )
255+
256+ child . stdout . pipe ( parser ) . on ( 'data' , ( ast ) => {
257+ subtest . addToReport ( ast )
258+ } )
259+
144260 const { 0 : { 0 : code , 1 : signal } , 1 : stdout } = await SafePromiseAll ( [
145261 once ( child , 'exit' , { signal : t . signal } ) ,
146262 toArray . call ( child . stdout , { signal : t . signal } )
0 commit comments