Skip to content
File

Blob: src/workerd/api/node/tests/process-stdio-nodejs-test.js

javascript217 lines
1// Copyright (c) 2025 Cloudflare, Inc.
2// Licensed under the Apache 2.0 license found in the LICENSE file or at:
3// https://opensource.org/licenses/Apache-2.0
4import { Buffer } from 'node:buffer';
5import { Readable, Writable } from 'node:stream';
6import assert from 'node:assert';
7import process from 'node:process';
8 
9export const processStdioPropertiesTest = {
10 test() {
11 assert.strictEqual(process.stdin.fd, 0, 'stdin should have fd 0');
12 assert(
13 process.stdin instanceof Readable,
14 'stdin should be instance of Readable'
15 );
16 
17 assert.strictEqual(process.stdout.fd, 1, 'stdout should have fd 1');
18 assert.strictEqual(
19 process.stdout.readable,
20 false,
21 'stdout should not be readable'
22 );
23 assert.strictEqual(
24 process.stdout._type,
25 'fs',
26 'stdout should have _type "fs"'
27 );
28 assert.strictEqual(
29 process.stdout._isStdio,
30 true,
31 'stdout should have _isStdio true'
32 );
33 assert(
34 process.stdout instanceof Writable,
35 'stdout should be instance of Writable'
36 );
37 
38 assert.strictEqual(process.stderr.fd, 2, 'stderr should have fd 2');
39 assert.strictEqual(
40 process.stderr.readable,
41 false,
42 'stderr should not be readable'
43 );
44 assert.strictEqual(
45 process.stderr._type,
46 'fs',
47 'stderr should have _type "fs"'
48 );
49 assert.strictEqual(
50 process.stderr._isStdio,
51 true,
52 'stderr should have _isStdio true'
53 );
54 assert(
55 process.stderr instanceof Writable,
56 'stderr should be instance of Writable'
57 );
58 },
59};
60 
61export const processStdioWriteTest = {
62 async test() {
63 process.stdout.write('Test string write to stdout\n');
64 process.stderr.write('Test string write to stderr\n');
65 
66 const bufferData = Buffer.from('Test buffer write\n');
67 process.stdout.write(bufferData);
68 process.stderr.write(bufferData);
69 
70 const uint8Array = new Uint8Array([72, 101, 108, 108, 111, 10]); // "Hello\n"
71 process.stdout.write(uint8Array);
72 process.stderr.write(uint8Array);
73 
74 process.stdout.write('Test UTF-8: café\n', 'utf8');
75 console.error('console.error');
76 console.log('console.log');
77 process.stdout.write('Test base64: ', 'utf8');
78 process.stdout.write('SGVsbG8gV29ybGQh', 'base64'); // "Hello World!"
79 process.stdout.write('\n');
80 
81 // these get ignored!
82 console.dir('test');
83 console.table([
84 { a: 'a', b: 'b' },
85 { a: 'c', b: 'd' },
86 ]);
87 console.log('console.log interleaves');
88 console.error('console.error interleaves');
89 
90 process.stdout.write('1');
91 process.stderr.write('2');
92 process.stdout.write('3');
93 process.stderr.write('4');
94 
95 process.stdout.write('\uD83D');
96 await new Promise((resolve) => setTimeout(resolve, 1));
97 process.stdout.write('\uDE00');
98 process.stderr.write('😀');
99 
100 // should buffer until the newline, supporting the partial emoji above
101 process.stdout.write('\n');
102 // stderr doesn't get final newline -> should still be a flush before exit
103 },
104};
105 
106export const processStdioCallbackTest = {
107 async test() {
108 await new Promise((resolve, reject) => {
109 process.stdout.write('Test with callback\n', (err) => {
110 if (err) {
111 reject(err);
112 } else {
113 resolve();
114 }
115 });
116 });
117 
118 await new Promise((resolve, reject) => {
119 process.stdout.write(
120 'Test with encoding and callback\n',
121 'utf8',
122 (err) => {
123 if (err) {
124 reject(err);
125 } else {
126 resolve();
127 }
128 }
129 );
130 });
131 },
132};
133 
134export const processStdioStreamMethodsTest = {
135 test() {
136 assert(
137 typeof process.stdout.end === 'function',
138 'stdout should have end method'
139 );
140 assert(
141 typeof process.stdout.cork === 'function',
142 'stdout should have cork method'
143 );
144 assert(
145 typeof process.stdout.uncork === 'function',
146 'stdout should have uncork method'
147 );
148 assert(
149 typeof process.stdout.destroy === 'function',
150 'stdout should have destroy method'
151 );
152 
153 process.stdout.cork();
154 process.stdout.write('Corked write 1\n');
155 process.stdout.write('Corked write 2\n');
156 process.stdout.uncork(); // Should flush the buffered writes
157 },
158};
159 
160export const processStdinTest = {
161 async test() {
162 assert.strictEqual(process.stdin.fd, 0, 'stdin should have fd 0');
163 assert(process.stdin instanceof Readable, 'stdin should be Readable');
164 
165 let dataReceived = false;
166 let endReceived = false;
167 
168 process.stdin.on('data', (chunk) => {
169 dataReceived = true;
170 console.log('Received data from stdin:', chunk);
171 });
172 
173 await new Promise((resolve) =>
174 process.stdin.on('end', () => {
175 endReceived = true;
176 resolve();
177 })
178 );
179 
180 assert.strictEqual(dataReceived, false);
181 assert.strictEqual(endReceived, true);
182 },
183};
184 
185export const lineBufferTruncationTest = {
186 async test() {
187 process.stdout.write(Buffer.alloc(4096, 'AB'));
188 process.stdout.write('X');
189 await new Promise((resolve) => setTimeout(resolve, 1));
190 process.stdout.write('AFTER_FLUSH\n');
191 process.stdout.write(Buffer.alloc(3000, 'C'));
192 process.stdout.write(Buffer.alloc(2000, 'D'));
193 await new Promise((resolve) => setTimeout(resolve, 1));
194 process.stdout.write('END_ROLLING\n');
195 },
196};
197 
198export const multipleNewlinesStdoutTest = {
199 test() {
200 process.stdout.write('Line 1\nLine 2\nLine 3\n');
201 process.stdout.write('First\n\nSecond with empty line before\n');
202 process.stdout.write('Multiple trailing newlines\n\n\n');
203 process.stdout.write('Start\nMiddle1\nMiddle2\nEnd');
204 process.stdout.write('\n');
205 },
206};
207 
208export const multipleNewlinesStderrTest = {
209 test() {
210 process.stderr.write('Error Line 1\nError Line 2\nError Line 3\n');
211 process.stderr.write('Error First\n\nError Second with empty line\n');
212 process.stderr.write('Error with trailing newlines\n\n\n');
213 process.stderr.write('Error Start\nError Mid1\nError Mid2\nError End');
214 process.stderr.write('\n');
215 },
216};