diff --git a/packages/frontend/editor-ui/src/constants.ts b/packages/frontend/editor-ui/src/constants.ts index c26c0c19e4..c87d334f0e 100644 --- a/packages/frontend/editor-ui/src/constants.ts +++ b/packages/frontend/editor-ui/src/constants.ts @@ -216,6 +216,7 @@ export const GITHUB_NODE_TYPE = 'n8n-nodes-base.github'; export const SLACK_TRIGGER_NODE_TYPE = 'n8n-nodes-base.slackTrigger'; export const TELEGRAM_TRIGGER_NODE_TYPE = 'n8n-nodes-base.telegramTrigger'; export const FACEBOOK_LEAD_ADS_TRIGGER_NODE_TYPE = 'n8n-nodes-base.facebookLeadAdsTrigger'; +export const RESPOND_TO_WEBHOOK_NODE_TYPE = 'n8n-nodes-base.respondToWebhook'; export const CREDENTIAL_ONLY_NODE_PREFIX = 'n8n-creds-base'; export const CREDENTIAL_ONLY_HTTP_NODE_VERSION = 4.1; @@ -795,6 +796,7 @@ export const NODE_TYPES_EXCLUDED_FROM_OUTPUT_NAME_APPEND = [ FILTER_NODE_TYPE, SWITCH_NODE_TYPE, REMOVE_DUPLICATES_NODE_TYPE, + RESPOND_TO_WEBHOOK_NODE_TYPE, ]; type ClearOutgoingConnectonsEvents = { diff --git a/packages/nodes-base/nodes/RespondToWebhook/RespondToWebhook.node.ts b/packages/nodes-base/nodes/RespondToWebhook/RespondToWebhook.node.ts index b7959a43ed..2ec4e0ee7b 100644 --- a/packages/nodes-base/nodes/RespondToWebhook/RespondToWebhook.node.ts +++ b/packages/nodes-base/nodes/RespondToWebhook/RespondToWebhook.node.ts @@ -22,6 +22,7 @@ import { } from 'n8n-workflow'; import type { Readable } from 'stream'; +import { configuredOutputs } from './utils'; import { formatPrivateKey, generatePairedItemData } from '../../utils/utilities'; const respondWithProperty: INodeProperties = { @@ -80,13 +81,13 @@ export class RespondToWebhook implements INodeType { icon: { light: 'file:webhook.svg', dark: 'file:webhook.dark.svg' }, name: 'respondToWebhook', group: ['transform'], - version: [1, 1.1, 1.2], + version: [1, 1.1, 1.2, 1.3], description: 'Returns data for Webhook', defaults: { name: 'Respond to Webhook', }, inputs: [NodeConnectionTypes.Main], - outputs: [NodeConnectionTypes.Main], + outputs: `={{(${configuredOutputs})($nodeVersion)}}`, credentials: [ { name: 'jwtAuth', @@ -318,6 +319,8 @@ export class RespondToWebhook implements INodeType { WAIT_NODE_TYPE, ]; + let response: IN8nHttpFullResponse; + try { if (nodeVersion >= 1.1) { const connectedNodes = this.getParentNodes(this.getNode().name); @@ -445,7 +448,7 @@ export class RespondToWebhook implements INodeType { ); } - const response: IN8nHttpFullResponse = { + response = { body: responseBody, headers, statusCode, @@ -465,6 +468,10 @@ export class RespondToWebhook implements INodeType { throw error; } + if (nodeVersion >= 1.3) { + return [items, [{ json: { response } }]]; + } + return [items]; } } diff --git a/packages/nodes-base/nodes/RespondToWebhook/test/RespondToWebhook.test.ts b/packages/nodes-base/nodes/RespondToWebhook/test/RespondToWebhook.test.ts index 797d1ea304..c2bece0a99 100644 --- a/packages/nodes-base/nodes/RespondToWebhook/test/RespondToWebhook.test.ts +++ b/packages/nodes-base/nodes/RespondToWebhook/test/RespondToWebhook.test.ts @@ -202,12 +202,15 @@ describe('RespondToWebhook Node', () => { }); mockExecuteFunctions.sendResponse.mockReturnValue(); - await expect(respondToWebhook.execute.call(mockExecuteFunctions)).resolves.not.toThrow(); + const result = await respondToWebhook.execute.call(mockExecuteFunctions); expect(mockExecuteFunctions.sendResponse).toHaveBeenCalledWith({ body: inputItems.map((item) => item.json), headers: {}, statusCode: 200, }); + expect(result).toHaveLength(1); + expect(result[0]).toHaveLength(2); + expect(result[0]).toEqual(inputItems); }); it('should correctly return binary', async () => { @@ -259,5 +262,52 @@ describe('RespondToWebhook Node', () => { ]); expect(mockExecuteFunctions.sendResponse).not.toHaveBeenCalled(); }); + + it('should have two outputs in version 1.3', async () => { + const inputItems = [{ json: { index: 0, input: true } }, { json: { index: 1, input: true } }]; + mockExecuteFunctions.getInputData.mockReturnValue(inputItems); + mockExecuteFunctions.getNode.mockReturnValue(mock({ typeVersion: 1.3 })); + mockExecuteFunctions.getParentNodes.mockReturnValue([ + mock({ type: WAIT_NODE_TYPE }), + ]); + mockExecuteFunctions.getNodeParameter.mockImplementation((paramName) => { + if (paramName === 'respondWith') return 'redirect'; + if (paramName === 'redirectURL') return 'n8n.io'; + if (paramName === 'options') return {}; + }); + mockExecuteFunctions.sendResponse.mockReturnValue(); + + const result = await respondToWebhook.execute.call(mockExecuteFunctions); + + expect(result).toHaveLength(2); + expect(result).toEqual([ + [ + { + json: { + index: 0, + input: true, + }, + }, + { + json: { + index: 1, + input: true, + }, + }, + ], + [ + { + json: { + response: { + headers: { + location: 'n8n.io', + }, + statusCode: 307, + }, + }, + }, + ], + ]); + }); }); }); diff --git a/packages/nodes-base/nodes/RespondToWebhook/test/utils.test.ts b/packages/nodes-base/nodes/RespondToWebhook/test/utils.test.ts new file mode 100644 index 0000000000..ad9e44cfda --- /dev/null +++ b/packages/nodes-base/nodes/RespondToWebhook/test/utils.test.ts @@ -0,0 +1,24 @@ +import { configuredOutputs } from '../utils'; + +describe('configuredOutputs', () => { + it('returns array of objects when version >= 1.3', () => { + const result = configuredOutputs(1.3); + expect(result).toEqual([ + { type: 'main', displayName: 'Input Data' }, + { type: 'main', displayName: 'Response' }, + ]); + }); + + it('returns array of objects when version > 1.3', () => { + const result = configuredOutputs(2); + expect(result).toEqual([ + { type: 'main', displayName: 'Input Data' }, + { type: 'main', displayName: 'Response' }, + ]); + }); + + it('returns ["main"] when version < 1.3', () => { + const result = configuredOutputs(1.2); + expect(result).toEqual(['main']); + }); +}); diff --git a/packages/nodes-base/nodes/RespondToWebhook/utils.ts b/packages/nodes-base/nodes/RespondToWebhook/utils.ts new file mode 100644 index 0000000000..7483a5514c --- /dev/null +++ b/packages/nodes-base/nodes/RespondToWebhook/utils.ts @@ -0,0 +1,16 @@ +export const configuredOutputs = (version: number) => { + if (version >= 1.3) { + return [ + { + type: 'main', + displayName: 'Input Data', + }, + { + type: 'main', + displayName: 'Response', + }, + ]; + } + + return ['main']; +};