diff --git a/packages/nodes-base/nodes/Form/Form.node.ts b/packages/nodes-base/nodes/Form/Form.node.ts index 9c50dc988d..735cbc4065 100644 --- a/packages/nodes-base/nodes/Form/Form.node.ts +++ b/packages/nodes-base/nodes/Form/Form.node.ts @@ -19,7 +19,6 @@ import { WAIT_INDEFINITELY, } from 'n8n-workflow'; -import { type CompletionPageConfig } from './interfaces'; import { formDescription, formFields, formTitle } from '../Form/common.descriptions'; import { prepareFormReturnItem, renderForm, resolveRawData } from '../Form/utils'; @@ -273,19 +272,19 @@ export class Form extends Node { const method = context.getRequestObject().method; if (operation === 'completion' && method === 'GET') { - const staticData = context.getWorkflowStaticData('node'); - const id = `${context.getExecutionId()}-${context.getNode().name}`; - const config = staticData?.[id] as CompletionPageConfig; - delete staticData[id]; + const completionTitle = context.getNodeParameter('completionTitle', '') as string; + const completionMessage = context.getNodeParameter('completionMessage', '') as string; + const redirectUrl = context.getNodeParameter('redirectUrl', '') as string; + const options = context.getNodeParameter('options', {}) as { formTitle: string }; - if (config.redirectUrl) { + if (redirectUrl) { res.send( - ``, + ``, ); return { noWebhookResponse: true }; } - let title = config.pageTitle; + let title = options.formTitle; if (!title) { title = context.evaluateExpression( `{{ $('${trigger?.name}').params.formTitle }}`, @@ -296,8 +295,8 @@ export class Form extends Node { ) as boolean; res.render('form-trigger-completion', { - title: config.completionTitle, - message: config.completionMessage, + title: completionTitle, + message: completionMessage, formTitle: title, appendAttribution, }); @@ -419,28 +418,7 @@ export class Form extends Node { ); } - if (operation !== 'completion') { - await context.putExecutionToWait(WAIT_INDEFINITELY); - } else { - const staticData = context.getWorkflowStaticData('node'); - const completionTitle = context.getNodeParameter('completionTitle', 0, '') as string; - const completionMessage = context.getNodeParameter('completionMessage', 0, '') as string; - const redirectUrl = context.getNodeParameter('redirectUrl', 0, '') as string; - const options = context.getNodeParameter('options', 0, {}) as { formTitle: string }; - const id = `${context.getExecutionId()}-${context.getNode().name}`; - - const config: CompletionPageConfig = { - completionTitle, - completionMessage, - redirectUrl, - pageTitle: options.formTitle, - }; - - staticData[id] = config; - - const waitTill = new Date(WAIT_INDEFINITELY); - await context.putExecutionToWait(waitTill); - } + await context.putExecutionToWait(WAIT_INDEFINITELY); return [context.getInputData()]; } diff --git a/packages/nodes-base/nodes/Form/interfaces.ts b/packages/nodes-base/nodes/Form/interfaces.ts index bf69644c77..1cf5f64c92 100644 --- a/packages/nodes-base/nodes/Form/interfaces.ts +++ b/packages/nodes-base/nodes/Form/interfaces.ts @@ -32,11 +32,4 @@ export type FormTriggerData = { buttonLabel?: string; }; -export type CompletionPageConfig = { - pageTitle?: string; - completionMessage?: string; - completionTitle?: string; - redirectUrl?: string; -}; - export const FORM_TRIGGER_AUTHENTICATION_PROPERTY = 'authentication'; diff --git a/packages/nodes-base/nodes/Form/test/Form.node.test.ts b/packages/nodes-base/nodes/Form/test/Form.node.test.ts index 8b1a24abcc..9dd0e4bbf2 100644 --- a/packages/nodes-base/nodes/Form/test/Form.node.test.ts +++ b/packages/nodes-base/nodes/Form/test/Form.node.test.ts @@ -172,7 +172,7 @@ describe('Form Node', () => { ]); }); - it('should handle completion operation', async () => { + it('should handle completion operation and render completion page', async () => { mockWebhookFunctions.getRequestObject.mockReturnValue({ method: 'GET' } as Request); mockWebhookFunctions.getNodeParameter.mockImplementation((paramName) => { if (paramName === 'operation') return 'completion'; @@ -181,6 +181,7 @@ describe('Form Node', () => { if (paramName === 'respondWith') return 'text'; if (paramName === 'completionTitle') return 'Test Title'; if (paramName === 'completionMessage') return 'Test Message'; + if (paramName === 'redirectUrl') return ''; return {}; }); mockWebhookFunctions.getParentNodes.mockReturnValue([ @@ -202,16 +203,55 @@ describe('Form Node', () => { ); mockWebhookFunctions.getNode.mockReturnValue(mock({ name: formCompletionNodeName })); mockWebhookFunctions.getExecutionId.mockReturnValue(testExecutionId); - mockWebhookFunctions.getWorkflowStaticData.mockReturnValue({ - [`${testExecutionId}-${formCompletionNodeName}`]: { redirectUrl: '' }, - }); const result = await form.webhook(mockWebhookFunctions); expect(result).toEqual({ noWebhookResponse: true }); - expect(mockResponseObject.render).toHaveBeenCalledWith( - 'form-trigger-completion', - expect.any(Object), + expect(mockResponseObject.render).toHaveBeenCalledWith('form-trigger-completion', { + appendAttribution: 'test', + formTitle: 'test', + message: 'Test Message', + title: 'Test Title', + }); + }); + + it('should handle completion operation and redirect', async () => { + mockWebhookFunctions.getRequestObject.mockReturnValue({ method: 'GET' } as Request); + mockWebhookFunctions.getNodeParameter.mockImplementation((paramName) => { + if (paramName === 'operation') return 'completion'; + if (paramName === 'useJson') return false; + if (paramName === 'jsonOutput') return '[]'; + if (paramName === 'respondWith') return 'text'; + if (paramName === 'completionTitle') return 'Test Title'; + if (paramName === 'completionMessage') return 'Test Message'; + if (paramName === 'redirectUrl') return 'https://n8n.io'; + return {}; + }); + mockWebhookFunctions.getParentNodes.mockReturnValue([ + { + type: 'n8n-nodes-base.formTrigger', + name: 'Form Trigger', + typeVersion: 2.1, + disabled: false, + }, + ]); + mockWebhookFunctions.evaluateExpression.mockReturnValue('test'); + + const mockResponseObject = { + render: jest.fn(), + redirect: jest.fn(), + send: jest.fn(), + }; + mockWebhookFunctions.getResponseObject.mockReturnValue( + mockResponseObject as unknown as Response, + ); + mockWebhookFunctions.getNode.mockReturnValue(mock({ name: formCompletionNodeName })); + + const result = await form.webhook(mockWebhookFunctions); + + expect(result).toEqual({ noWebhookResponse: true }); + expect(mockResponseObject.send).toHaveBeenCalledWith( + '', ); }); });