From 023c64df8550c9b12ddba64bebc99fb6d584f7da Mon Sep 17 00:00:00 2001 From: coderaiser Date: Tue, 4 Jun 2024 19:26:17 +0300 Subject: [PATCH] feature: supertape: add ability to use console.log in worker mode --- packages/supertape/bin/formatter.mjs | 14 ++ packages/supertape/bin/subscribe.mjs | 30 +++ packages/supertape/lib/formatter/harness.js | 1 + .../lib/worker/create-console-log.js | 47 +++++ .../lib/worker/create-console-log.spec.js | 179 ++++++++++++++++++ packages/supertape/package.json | 3 +- 6 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 packages/supertape/lib/worker/create-console-log.js create mode 100644 packages/supertape/lib/worker/create-console-log.spec.js diff --git a/packages/supertape/bin/formatter.mjs b/packages/supertape/bin/formatter.mjs index 278484b..5da0dfc 100644 --- a/packages/supertape/bin/formatter.mjs +++ b/packages/supertape/bin/formatter.mjs @@ -1,7 +1,18 @@ import {EventEmitter} from 'node:events'; +import { + overrideConsoleError, + overrideConsoleLog, +} from '../lib/worker/create-console-log.js'; export const createFormatter = (parentPort) => { const formatter = new EventEmitter(); + const {getBackConsoleLog} = overrideConsoleLog(parentPort, { + console, + }); + + const {getBackConsoleError} = overrideConsoleError(parentPort, { + console, + }); formatter.on('start', ({total}) => { parentPort.postMessage(['start', { @@ -51,6 +62,9 @@ export const createFormatter = (parentPort) => { }); formatter.on('end', ({count, passed, failed, skiped}) => { + getBackConsoleLog(); + getBackConsoleError(); + parentPort.postMessage(['end', { count, passed, diff --git a/packages/supertape/bin/subscribe.mjs b/packages/supertape/bin/subscribe.mjs index 9615e16..02d0144 100644 --- a/packages/supertape/bin/subscribe.mjs +++ b/packages/supertape/bin/subscribe.mjs @@ -1,5 +1,13 @@ import keyPress from '@putout/cli-keypress'; import harnessCreator from '../lib/formatter/harness.js'; +import {parse} from 'flatted'; +import { + SPLITTER, + CONSOLE_LOG, + CONSOLE_ERROR, +} from '../lib/worker/create-console-log.js'; + +const one = (fn) => (a) => fn(a); const {createHarness} = harnessCreator; const resolveFormatter = async (name) => await import(`@supertape/formatter-${name}`); @@ -15,6 +23,12 @@ export async function subscribe({name, exit, worker, stdout}) { }); worker.on('message', ([type, a]) => { + if (type === CONSOLE_LOG) + return consoleLog(a); + + if (type === CONSOLE_ERROR) + return consoleError(a); + harness.write({ type, ...a, @@ -24,3 +38,19 @@ export async function subscribe({name, exit, worker, stdout}) { worker.postMessage(['stop']); }); } + +function consoleLog({message}) { + const messages = message + .split(SPLITTER) + .map(one(parse)); + + console.log(...messages); +} + +function consoleError({message}) { + const messages = message + .split(SPLITTER) + .map(one(parse)); + + console.error(...messages); +} diff --git a/packages/supertape/lib/formatter/harness.js b/packages/supertape/lib/formatter/harness.js index e0a9af3..d73eb94 100644 --- a/packages/supertape/lib/formatter/harness.js +++ b/packages/supertape/lib/formatter/harness.js @@ -1,6 +1,7 @@ 'use strict'; const {Transform: _Transform} = require('node:stream'); + const {assign} = Object; module.exports.createHarness = (reporter, {Transform = _Transform} = {}) => { diff --git a/packages/supertape/lib/worker/create-console-log.js b/packages/supertape/lib/worker/create-console-log.js new file mode 100644 index 0000000..b69d2c8 --- /dev/null +++ b/packages/supertape/lib/worker/create-console-log.js @@ -0,0 +1,47 @@ +'use strict'; + +const {stringify} = require('flatted'); +const SPLITTER = '>[supertape-splitter]<'; +const CONSOLE_LOG = 'console:log'; +const CONSOLE_ERROR = 'console:error'; + +module.exports.CONSOLE_ERROR = CONSOLE_ERROR; +module.exports.CONSOLE_LOG = CONSOLE_LOG; +module.exports.SPLITTER = SPLITTER; + +module.exports.overrideConsoleLog = (parentPort, {console = global.console} = {}) => { + const {log} = console; + + console.log = createConsoleMethod(CONSOLE_LOG, parentPort); + return { + getBackConsoleLog: () => { + console.log = log; + }, + }; +}; + +module.exports.overrideConsoleError = (parentPort, {console = global.console} = {}) => { + const {error} = console; + + console.error = createConsoleMethod(CONSOLE_ERROR, parentPort); + return { + getBackConsoleError: () => { + console.error = error; + }, + }; +}; + +const createConsoleMethod = (type, parentPort) => (...messages) => { + const prepared = []; + + for (const message of messages) + prepared.push(stringify(message)); + + parentPort.postMessage([ + type, { + message: prepared.join(SPLITTER), + }, + ]); +}; + +module.exports._createConsoleLog = createConsoleMethod; diff --git a/packages/supertape/lib/worker/create-console-log.spec.js b/packages/supertape/lib/worker/create-console-log.spec.js new file mode 100644 index 0000000..6c3cc1a --- /dev/null +++ b/packages/supertape/lib/worker/create-console-log.spec.js @@ -0,0 +1,179 @@ +'use strict'; + +const {test, stub} = require('supertape'); +const { + overrideConsoleLog, + CONSOLE_LOG, +} = require('./create-console-log'); + +const {stringify} = require('flatted'); + +test('supertape: worker: create-console-log', (t) => { + const log = stub(); + const consoleStub = { + log, + }; + + const parentPort = { + postMessage: stub(), + }; + + overrideConsoleLog(parentPort, { + console: consoleStub, + }); + + consoleStub.log('hello'); + + t.notCalled(log); + t.end(); +}); + +test('supertape: worker: create-console-log: get back', (t) => { + const log = stub(); + const consoleStub = { + log, + }; + + const parentPort = { + postMessage: stub(), + }; + + const {getBackConsoleLog} = overrideConsoleLog(parentPort, { + console: consoleStub, + }); + + consoleStub.log('hello'); + + getBackConsoleLog(); + + consoleStub.log('world'); + + t.calledWith(log, ['world']); + t.end(); +}); + +test('supertape: worker: create-console-log: postMessage', (t) => { + const log = stub(); + const consoleStub = { + log, + }; + + const postMessage = stub(); + + const parentPort = { + postMessage, + }; + + overrideConsoleLog(parentPort, { + console: consoleStub, + }); + + consoleStub.log('hello'); + + const arg = [ + CONSOLE_LOG, { + message: '["hello"]', + }, + ]; + + t.calledWith(postMessage, [arg]); + t.end(); +}); + +test('supertape: worker: create-console-log: postMessage: array', (t) => { + const log = stub(); + const consoleStub = { + log, + }; + + const postMessage = stub(); + + const parentPort = { + postMessage, + }; + + const {getBackConsoleLog} = overrideConsoleLog(parentPort, { + console: consoleStub, + }); + + consoleStub.log([1, 2]); + + getBackConsoleLog(); + + const arg = [ + CONSOLE_LOG, { + message: '[[1,2]]', + }, + ]; + + t.calledWith(postMessage, [arg]); + t.end(); +}); + +test('supertape: worker: create-console-log: postMessage: object', (t) => { + const log = stub(); + const consoleStub = { + log, + }; + + const postMessage = stub(); + + const parentPort = { + postMessage, + }; + + overrideConsoleLog(parentPort, { + console: consoleStub, + }); + + const objectB = {}; + + const objectA = { + objectB, + }; + + objectA.objectB = { + objectA, + }; + + consoleStub.log(objectA); + + const arg = [ + CONSOLE_LOG, { + message: stringify(objectA), + }, + ]; + + t.calledWith(postMessage, [arg]); + t.end(); +}); + +test('supertape: worker: create-console-log: postMessage: simple object', (t) => { + const log = stub(); + const consoleStub = { + log, + }; + + const postMessage = stub(); + + const parentPort = { + postMessage, + }; + + overrideConsoleLog(parentPort, { + console: consoleStub, + }); + + consoleStub.log({ + hello: 'world', + }); + + const arg = [ + CONSOLE_LOG, { + message: '[{"hello":"1"},"world"]', + }, + ]; + + t.calledWith(postMessage, [arg]); + t.end(); +}); diff --git a/packages/supertape/package.json b/packages/supertape/package.json index 78bcd82..d3c29f9 100644 --- a/packages/supertape/package.json +++ b/packages/supertape/package.json @@ -51,6 +51,7 @@ "@supertape/formatter-time": "^1.0.0", "@supertape/operator-stub": "^3.0.0", "cli-progress": "^3.8.2", + "flatted": "^3.3.1", "fullstore": "^3.0.0", "glob": "^10.3.10", "jest-diff": "^29.0.1", @@ -88,7 +89,7 @@ "pullout": "^5.0.1", "putout": "^35.0.0", "runsome": "^1.0.0", - "try-catch": "^3.0.0", + "try-catch": "^3.0.1", "typescript": "^5.1.6" }, "license": "MIT",