Skip to content

Commit 04ff824

Browse files
authored
Merge pull request #159 from errsole/fix/stdout-done-callback
Fix/stdout done callback
2 parents cc59ef0 + 4ea5804 commit 04ff824

File tree

2 files changed

+85
-7
lines changed

2 files changed

+85
-7
lines changed

lib/main/logs/index.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,14 @@ const logCollector = {
5353
process.stderr.write = this.originalStderrWrite;
5454
} else {
5555
console.log('Note: Terminal output will be disabled after initial logs.');
56-
process.stdout.write = (chunk, encoding, done) => done();
57-
process.stderr.write = (chunk, encoding, done) => done();
56+
const swallowWrite = (chunk, encoding, cb) => {
57+
if (typeof encoding === 'function') cb = encoding;
58+
if (typeof cb === 'function') process.nextTick(() => cb(null));
59+
return true;
60+
};
61+
62+
process.stdout.write = swallowWrite;
63+
process.stderr.write = swallowWrite;
5864
}
5965
if (this.collectLogs.includes(LogLevel.INFO)) {
6066
this.interceptLogs(LogLevel.INFO);
@@ -133,7 +139,7 @@ const logCollector = {
133139
Bun.write(Bun.stdout, `${args}\n`);
134140
};
135141
});
136-
142+
137143
stderrMethods.forEach(method => {
138144
console[method] = (...args) => {
139145
const message = args.map(arg =>
@@ -147,17 +153,16 @@ const logCollector = {
147153
hostname: this.hostname,
148154
pid: this.pid
149155
};
150-
156+
151157
this.logStream.write(logEntry);
152158
Bun.write(Bun.stderr, `${args}\n`);
153159
};
154160
});
155-
161+
156162
return;
157163
}
158164

159-
160-
logStream.write = (chunk, encoding, done) => {
165+
logStream.write = (chunk, encoding, done) => {
161166
const cleanedChunk = stripAnsi(chunk.toString());
162167
const logEntry = {
163168
timestamp: new Date().toISOString(),

tests/Logging/logging.test.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,16 @@ describe('logCollector', () => {
225225
process.stderr.write('', null, () => {});
226226
}).not.toThrow();
227227
});
228+
test('logCustomMessage should write to stdout if enableConsoleOutput is true', () => {
229+
logCollector.logStream = { write: jest.fn() };
230+
logCollector.enableConsoleOutput = true;
231+
232+
const stdoutSpy = jest.spyOn(logCollector.originalStdoutWrite, 'call').mockImplementation(() => {});
233+
logCollector.logCustomMessage('info', 'Test message');
234+
235+
expect(stdoutSpy).toHaveBeenCalled();
236+
stdoutSpy.mockRestore();
237+
});
228238
});
229239

230240
describe('createLogStream', () => {
@@ -246,6 +256,14 @@ describe('logCollector', () => {
246256

247257
logCollector.createEmptyLogStream();
248258

259+
expect(destroySpy).toHaveBeenCalled();
260+
});
261+
test('createEmptyLogStream should call destroy on existing logStream', () => {
262+
const destroySpy = jest.fn();
263+
logCollector.logStream = { destroy: destroySpy };
264+
265+
logCollector.createEmptyLogStream();
266+
249267
expect(destroySpy).toHaveBeenCalled();
250268
});
251269
});
@@ -382,4 +400,59 @@ describe('logCollector', () => {
382400
expect(console.error).toHaveBeenCalledWith(error);
383401
});
384402
});
403+
404+
describe('resetConsoleOutput', () => {
405+
test('should restore console output and uncork logStream', () => {
406+
const uncorkSpy = jest.fn();
407+
logCollector.logStream = {
408+
uncork: uncorkSpy,
409+
write: jest.fn()
410+
};
411+
logCollector.enableConsoleOutput = false;
412+
413+
const originalStdout = process.stdout.write;
414+
const originalStderr = process.stderr.write;
415+
416+
logCollector.resetConsoleOutput();
417+
418+
expect(logCollector.enableConsoleOutput).toBe(true);
419+
expect(process.stdout.write).toBe(logCollector.originalStdoutWrite);
420+
expect(process.stderr.write).toBe(logCollector.originalStderrWrite);
421+
expect(uncorkSpy).toHaveBeenCalled();
422+
423+
process.stdout.write = originalStdout;
424+
process.stderr.write = originalStderr;
425+
});
426+
});
427+
428+
describe('setInitializationTimeout', () => {
429+
test('should mark initialization failed and create empty log stream', () => {
430+
jest.useFakeTimers();
431+
const createEmptyLogStreamSpy = jest.spyOn(logCollector, 'createEmptyLogStream');
432+
433+
// ✅ Provide a mock logStream with a destroy() method
434+
logCollector.logStream = { destroy: jest.fn() };
435+
436+
logCollector.setInitializationTimeout();
437+
jest.runAllTimers();
438+
439+
expect(createEmptyLogStreamSpy).toHaveBeenCalled();
440+
expect(logCollector.isInitializationFailed).toBe(true);
441+
expect(console.error).toHaveBeenCalledWith('Error: Unable to initialize Errsole');
442+
443+
jest.useRealTimers();
444+
createEmptyLogStreamSpy.mockRestore();
445+
});
446+
});
447+
448+
describe('initialize swallowWrite', () => {
449+
test('should not throw when stdout.write is called without a callback', () => {
450+
const options = { storage: storageMock, enableConsoleOutput: false };
451+
logCollector.initialize(options);
452+
453+
expect(() => {
454+
process.stdout.write('test message'); // no callback passed
455+
}).not.toThrow();
456+
});
457+
});
385458
});

0 commit comments

Comments
 (0)