From 1e2f4217e06e3924c776cb1c9bcae54b2c3bef2c Mon Sep 17 00:00:00 2001 From: Jaakko Husso Date: Fri, 12 Sep 2025 15:05:35 +0300 Subject: [PATCH] fix(Code Tool Node): Fix `console.log` output not being logged on browser (#19422) --- .../__tests__/supply-data-context.test.ts | 34 +++++++++++++++++++ .../supply-data-context.ts | 16 ++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/packages/core/src/execution-engine/node-execution-context/__tests__/supply-data-context.test.ts b/packages/core/src/execution-engine/node-execution-context/__tests__/supply-data-context.test.ts index 058ea0fdc6..6efb94cb1b 100644 --- a/packages/core/src/execution-engine/node-execution-context/__tests__/supply-data-context.test.ts +++ b/packages/core/src/execution-engine/node-execution-context/__tests__/supply-data-context.test.ts @@ -220,6 +220,40 @@ describe('SupplyDataContext', () => { }); }); + describe('logNodeOutput', () => { + it('it should parse JSON', () => { + const json = '{"key": "value", "nested": {"foo": "bar"}}'; + const expectedParsedObject = { key: 'value', nested: { foo: 'bar' } }; + const numberArg = 42; + const stringArg = 'hello world!'; + + const supplyDataContext = new SupplyDataContext( + workflow, + node, + additionalData, + mode, + runExecutionData, + runIndex, + connectionInputData, + inputData, + connectionType, + executeData, + [closeFn], + abortSignal, + ); + + const sendMessageSpy = jest.spyOn(supplyDataContext, 'sendMessageToUI'); + + supplyDataContext.logNodeOutput(json, numberArg, stringArg); + + expect(sendMessageSpy.mock.calls[0][0]).toEqual(expectedParsedObject); + expect(sendMessageSpy.mock.calls[0][1]).toBe(numberArg); + expect(sendMessageSpy.mock.calls[0][2]).toBe(stringArg); + + sendMessageSpy.mockRestore(); + }); + }); + describe('addExecutionDataFunctions', () => { it('should preserve canceled status when execution is aborted and output has error', async () => { const errorData = new ExecutionCancelledError('Execution was aborted'); diff --git a/packages/core/src/execution-engine/node-execution-context/supply-data-context.ts b/packages/core/src/execution-engine/node-execution-context/supply-data-context.ts index 7663a48870..45d468298c 100644 --- a/packages/core/src/execution-engine/node-execution-context/supply-data-context.ts +++ b/packages/core/src/execution-engine/node-execution-context/supply-data-context.ts @@ -18,7 +18,7 @@ import type { NodeConnectionType, ISourceData, } from 'n8n-workflow'; -import { createDeferredPromise, NodeConnectionTypes } from 'n8n-workflow'; +import { createDeferredPromise, jsonParse, NodeConnectionTypes } from 'n8n-workflow'; import { BaseExecuteContext } from './base-execute-context'; import { @@ -344,4 +344,18 @@ export class SupplyDataContext extends BaseExecuteContext implements ISupplyData }); } } + + logNodeOutput(...args: unknown[]): void { + if (this.mode === 'manual') { + const parsedLogArgs = args.map((arg) => + typeof arg === 'string' ? jsonParse(arg, { fallbackValue: arg }) : arg, + ); + this.sendMessageToUI(...parsedLogArgs); + return; + } + + if (process.env.CODE_ENABLE_STDOUT === 'true') { + console.log(`[Workflow "${this.getWorkflow().id}"][Node "${this.node.name}"]`, ...args); + } + } }