1+ import { type ChildProcess , type ExecOptions , exec as nodeExec } from 'node:child_process' ;
12import path from 'node:path' ;
23import { test as baseTest } from 'rstack/test' ;
3- import { execCli as baseExecCli , type ExecCli } from './cli.ts' ;
4+ import { execCli as baseExecCli , type ExecCli , RSTACK_BIN_PATH } from './cli.ts' ;
45import { type ExtendedLogHelper , proxyConsole } from './logs.ts' ;
56
7+ type Exec = (
8+ command : string ,
9+ options ?: ExecOptions ,
10+ ) => {
11+ childProcess : ChildProcess ;
12+ } ;
13+
614export type CliTestFixtures = {
715 cwd : string ;
16+ exec : Exec ;
817 execCli : ExecCli ;
18+ execCliAsync : Exec ;
919 logHelper : ExtendedLogHelper ;
1020} ;
1121
@@ -20,6 +30,15 @@ function makeBox(title: string) {
2030 } ;
2131}
2232
33+ const setupExecOptions = < T extends ExecOptions > ( options : T , cwd : string ) : T => {
34+ // inherit process.env from current process
35+ const { NODE_ENV : _ , ...restEnv } = process . env ;
36+ options . env ||= { } ;
37+ options . env = { ...restEnv , ...options . env } ;
38+ options . cwd ||= cwd ;
39+ return options ;
40+ } ;
41+
2342export const test : CliTest = baseTest . extend < CliTestFixtures > ( {
2443 cwd : async ( { expect } , use ) => {
2544 const { testPath } = expect . getState ( ) ;
@@ -55,4 +74,35 @@ export const test: CliTest = baseTest.extend<CliTestFixtures>({
5574
5675 await use ( execCli ) ;
5776 } ,
77+ exec : async ( { cwd, logHelper } , use ) => {
78+ let close : ( ( ) => void ) | undefined ;
79+
80+ const exec : Exec = ( command , options = { } ) => {
81+ const childProcess = nodeExec ( command , setupExecOptions ( options , cwd ) ) ;
82+
83+ const onData = ( data : Buffer ) => {
84+ logHelper . addLog ( data . toString ( ) ) ;
85+ } ;
86+
87+ childProcess . stdout ?. on ( 'data' , onData ) ;
88+ childProcess . stderr ?. on ( 'data' , onData ) ;
89+
90+ close = ( ) => {
91+ childProcess . stdout ?. off ( 'data' , onData ) ;
92+ childProcess . stderr ?. off ( 'data' , onData ) ;
93+ childProcess . kill ( ) ;
94+ } ;
95+
96+ return { childProcess } ;
97+ } ;
98+
99+ await use ( exec ) ;
100+ close ?.( ) ;
101+ } ,
102+ execCliAsync : async ( { exec } , use ) => {
103+ const execCliAsync : Exec = ( command , options = { } ) => {
104+ return exec ( `node ${ RSTACK_BIN_PATH } ${ command } ` , options ) ;
105+ } ;
106+ await use ( execCliAsync ) ;
107+ } ,
58108} ) ;
0 commit comments