@@ -3435,4 +3435,170 @@ export default async () => {
34353435 expect ( stdout ) . toContain ( 'headers-object test complete' ) ;
34363436 } ) ;
34373437 } ) ;
3438+
3439+ // ==================== SUBPROCESS API ====================
3440+
3441+ describe ( 'subprocess' , ( ) => {
3442+ /**
3443+ * Subprocess API test suite
3444+ *
3445+ * These tests verify funee's subprocess spawning and management API.
3446+ * The API provides:
3447+ * - spawn() for running commands
3448+ * - Process object for managing running processes
3449+ * - Streaming stdin/stdout/stderr
3450+ * - Signal handling and process control
3451+ */
3452+
3453+ it ( 'spawns a basic command and gets exit code' , async ( ) => {
3454+ /**
3455+ * Tests basic subprocess spawning:
3456+ * - spawn(command, args) runs a command
3457+ * - Returns status with exit code
3458+ * - success is true for exit code 0
3459+ */
3460+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-basic.ts' ] ) ;
3461+
3462+ expect ( exitCode ) . toBe ( 0 ) ;
3463+ expect ( stdout ) . toContain ( 'exit code: 0' ) ;
3464+ expect ( stdout ) . toContain ( 'success: true' ) ;
3465+ expect ( stdout ) . toContain ( 'spawn-basic: pass' ) ;
3466+ } ) ;
3467+
3468+ it ( 'captures stdout output from subprocess' , async ( ) => {
3469+ /**
3470+ * Tests stdout capture:
3471+ * - stdout is available as Uint8Array
3472+ * - stdoutText() returns decoded string
3473+ * - Output matches command output
3474+ */
3475+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-stdout.ts' ] ) ;
3476+
3477+ expect ( exitCode ) . toBe ( 0 ) ;
3478+ expect ( stdout ) . toContain ( 'stdout text: "hello world"' ) ;
3479+ expect ( stdout ) . toContain ( 'spawn-stdout: pass' ) ;
3480+ } ) ;
3481+
3482+ it ( 'captures stderr output from subprocess' , async ( ) => {
3483+ /**
3484+ * Tests stderr capture:
3485+ * - stderr is captured separately
3486+ * - stderrText() returns decoded string
3487+ * - Errors appear in stderr, not stdout
3488+ */
3489+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-stderr.ts' ] ) ;
3490+
3491+ expect ( exitCode ) . toBe ( 0 ) ;
3492+ expect ( stdout ) . toContain ( 'stderr contains error: true' ) ;
3493+ expect ( stdout ) . toContain ( 'stdout is empty: true' ) ;
3494+ expect ( stdout ) . toContain ( 'success: false' ) ;
3495+ expect ( stdout ) . toContain ( 'spawn-stderr: pass' ) ;
3496+ } ) ;
3497+
3498+ it ( 'writes to subprocess stdin' , async ( ) => {
3499+ /**
3500+ * Tests stdin writing:
3501+ * - stdin: "piped" enables writing
3502+ * - writeInput() sends data
3503+ * - Process receives input
3504+ */
3505+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-stdin.ts' ] ) ;
3506+
3507+ expect ( exitCode ) . toBe ( 0 ) ;
3508+ expect ( stdout ) . toContain ( 'output: "hello from stdin"' ) ;
3509+ expect ( stdout ) . toContain ( 'matches input: true' ) ;
3510+ expect ( stdout ) . toContain ( 'spawn-stdin: pass' ) ;
3511+ } ) ;
3512+
3513+ it ( 'sets working directory for subprocess' , async ( ) => {
3514+ /**
3515+ * Tests cwd option:
3516+ * - cwd sets process working directory
3517+ * - Commands run in specified directory
3518+ */
3519+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-cwd.ts' ] ) ;
3520+
3521+ expect ( exitCode ) . toBe ( 0 ) ;
3522+ expect ( stdout ) . toContain ( 'is /tmp: true' ) ;
3523+ expect ( stdout ) . toContain ( 'spawn-cwd: pass' ) ;
3524+ } ) ;
3525+
3526+ it ( 'sets environment variables for subprocess' , async ( ) => {
3527+ /**
3528+ * Tests env options:
3529+ * - env sets custom environment variables
3530+ * - inheritEnv controls parent env inheritance
3531+ */
3532+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-env.ts' ] ) ;
3533+
3534+ expect ( exitCode ) . toBe ( 0 ) ;
3535+ expect ( stdout ) . toContain ( 'custom env var: custom_value' ) ;
3536+ expect ( stdout ) . toContain ( 'inheritEnv true, has PATH: true' ) ;
3537+ expect ( stdout ) . toContain ( 'spawn-env: pass' ) ;
3538+ } ) ;
3539+
3540+ it ( 'kills a running subprocess' , async ( ) => {
3541+ /**
3542+ * Tests process killing:
3543+ * - kill(signal) sends signal to process
3544+ * - Process terminates
3545+ * - status.signal contains termination signal
3546+ */
3547+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-kill.ts' ] ) ;
3548+
3549+ expect ( exitCode ) . toBe ( 0 ) ;
3550+ expect ( stdout ) . toContain ( 'pid is number: true' ) ;
3551+ expect ( stdout ) . toContain ( 'success: false' ) ;
3552+ expect ( stdout ) . toContain ( 'signal: SIGTERM' ) ;
3553+ expect ( stdout ) . toContain ( 'spawn-kill: pass' ) ;
3554+ } ) ;
3555+
3556+ it ( 'handles subprocess errors gracefully' , async ( ) => {
3557+ /**
3558+ * Tests error handling:
3559+ * - Command not found throws error
3560+ * - Invalid cwd throws error
3561+ * - Errors have descriptive messages
3562+ */
3563+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-error.ts' ] ) ;
3564+
3565+ expect ( exitCode ) . toBe ( 0 ) ;
3566+ expect ( stdout ) . toContain ( 'command not found error caught: true' ) ;
3567+ expect ( stdout ) . toContain ( 'spawn-error: pass' ) ;
3568+ } ) ;
3569+
3570+ it ( 'passes arguments to subprocess correctly' , async ( ) => {
3571+ /**
3572+ * Tests argument handling:
3573+ * - Multiple arguments work
3574+ * - Arguments with spaces handled
3575+ * - cmd array form works
3576+ */
3577+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-args.ts' ] ) ;
3578+
3579+ expect ( exitCode ) . toBe ( 0 ) ;
3580+ expect ( stdout ) . toContain ( 'multiple args: "one two three"' ) ;
3581+ expect ( stdout ) . toContain ( 'cmd array args: "from cmd array"' ) ;
3582+ expect ( stdout ) . toContain ( 'spawn-args: pass' ) ;
3583+ } ) ;
3584+
3585+ it ( 'captures non-zero exit codes' , async ( ) => {
3586+ /**
3587+ * Tests exit code handling:
3588+ * - Non-zero codes captured correctly
3589+ * - success is false for non-zero
3590+ * - Different codes are distinguishable
3591+ */
3592+ const { stdout, stderr, exitCode } = await runFunee ( [ 'process/spawn-exit-code.ts' ] ) ;
3593+
3594+ expect ( exitCode ) . toBe ( 0 ) ;
3595+ expect ( stdout ) . toContain ( 'exit 1 - code: 1' ) ;
3596+ expect ( stdout ) . toContain ( 'exit 1 - success: false' ) ;
3597+ expect ( stdout ) . toContain ( 'exit 42 - code: 42' ) ;
3598+ expect ( stdout ) . toContain ( 'exit 0 - code: 0' ) ;
3599+ expect ( stdout ) . toContain ( 'exit 0 - success: true' ) ;
3600+ expect ( stdout ) . toContain ( 'exit 255 - code: 255' ) ;
3601+ expect ( stdout ) . toContain ( 'spawn-exit-code: pass' ) ;
3602+ } ) ;
3603+ } ) ;
34383604} ) ;
0 commit comments