diff --git a/.prettierignore b/.prettierignore index 4e33d315727bc..4ac8f0dafbf68 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,5 +4,6 @@ package.json pnpm-lock.yaml packages/editor-ui/index.html packages/nodes-base/nodes/**/test +packages/cli/templates/form-trigger.handlebars cypress/fixtures CHANGELOG.md diff --git a/cypress/e2e/16-form-trigger-node.cy.ts b/cypress/e2e/16-form-trigger-node.cy.ts new file mode 100644 index 0000000000000..27198001a8e51 --- /dev/null +++ b/cypress/e2e/16-form-trigger-node.cy.ts @@ -0,0 +1,88 @@ +import { WorkflowPage, NDV } from '../pages'; +import { v4 as uuid } from 'uuid'; +import { getPopper, getVisiblePopper, getVisibleSelect } from '../utils'; +import { META_KEY } from '../constants'; + +const workflowPage = new WorkflowPage(); +const ndv = new NDV(); + +describe('n8n Form Trigger', () => { + beforeEach(() => { + workflowPage.actions.visit(); + }); + + it("add node by clicking on 'On form submission'", () => { + workflowPage.getters.canvasPlusButton().click(); + cy.get('#node-view-root > div:nth-child(2) > div > div > aside ') + .find('span') + .contains('On form submission') + .click(); + ndv.getters.parameterInput('formTitle').type('Test Form'); + ndv.getters.parameterInput('formDescription').type('Test Form Description'); + ndv.getters.parameterInput('fieldLabel').type('Test Field 1'); + ndv.getters.backToCanvas().click(); + workflowPage.getters.nodeIssuesByName('n8n Form Trigger').should('not.exist'); + }); + + it('should fill up form fields', () => { + workflowPage.actions.addInitialNodeToCanvas('n8n Form Trigger'); + workflowPage.getters.canvasNodes().first().dblclick(); + ndv.getters.parameterInput('formTitle').type('Test Form'); + ndv.getters.parameterInput('formDescription').type('Test Form Description'); + //fill up first field of type number + ndv.getters.parameterInput('fieldLabel').type('Test Field 1'); + ndv.getters.parameterInput('fieldType').click(); + getVisibleSelect().contains('Number').click(); + cy.get( + '[data-test-id="parameter-input-requiredField"] > .parameter-input > .el-switch > .el-switch__core', + ).click(); + //fill up second field of type text + cy.get('.fixed-collection-parameter > :nth-child(2) > .button > span').click(); + cy.get('.border-top-dashed > .parameter-input-list-wrapper > :nth-child(1) > .parameter-item') + .find('input[placeholder*="e.g. What is your name?"]') + .type('Test Field 2'); + //fill up second field of type date + cy.get('.fixed-collection-parameter > :nth-child(2) > .button > span').click(); + cy.get( + ':nth-child(3) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(1) > .parameter-item', + ) + .find('input[placeholder*="e.g. What is your name?"]') + .type('Test Field 3'); + cy.get( + ':nth-child(3) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(2) > .parameter-item', + ).click(); + getVisibleSelect().contains('Date').click(); + // fill up second field of type dropdown + cy.get('.fixed-collection-parameter > :nth-child(2) > .button').click(); + cy.get( + ':nth-child(4) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(1) > .parameter-item', + ) + .find('input[placeholder*="e.g. What is your name?"]') + .type('Test Field 4'); + cy.get( + ':nth-child(4) > .border-top-dashed > .parameter-input-list-wrapper > :nth-child(2) > .parameter-item', + ).click(); + getVisibleSelect().contains('Dropdown').click(); + cy.get( + '.border-top-dashed > :nth-child(2) > :nth-child(3) > .multi-parameter > .fixed-collection-parameter > :nth-child(2) > .button', + ).click(); + cy.get( + ':nth-child(4) > :nth-child(1) > :nth-child(2) > :nth-child(3) > .multi-parameter > .fixed-collection-parameter > .fixed-collection-parameter-property > :nth-child(1) > :nth-child(1)', + ) + .find('input') + .type('Option 1'); + cy.get( + ':nth-child(4) > :nth-child(1) > :nth-child(2) > :nth-child(3) > .multi-parameter > .fixed-collection-parameter > .fixed-collection-parameter-property > :nth-child(1) > :nth-child(2)', + ) + .find('input') + .type('Option 2'); + //add optionall submitted message + cy.get('.param-options > .button').click(); + cy.get('.indent > .parameter-item') + .find('input') + .clear() + .type('Your test form was successfully submitted'); + ndv.getters.backToCanvas().click(); + workflowPage.getters.nodeIssuesByName('n8n Form Trigger').should('not.exist'); + }); +}); diff --git a/packages/cli/src/WebhookHelpers.ts b/packages/cli/src/WebhookHelpers.ts index 2c8d75edaf545..2a1347c19fbe6 100644 --- a/packages/cli/src/WebhookHelpers.ts +++ b/packages/cli/src/WebhookHelpers.ts @@ -38,6 +38,7 @@ import { BINARY_ENCODING, createDeferredPromise, ErrorReporterProxy as ErrorReporter, + FORM_TRIGGER_PATH_IDENTIFIER, LoggerProxy as Logger, NodeHelpers, } from 'n8n-workflow'; @@ -109,7 +110,16 @@ export const webhookRequestHandler = try { response = await webhookManager.executeWebhook(req, res); } catch (error) { - return ResponseHelper.sendErrorResponse(res, error as Error); + if ( + error.errorCode === 404 && + (error.message as string).includes(FORM_TRIGGER_PATH_IDENTIFIER) + ) { + const isTestWebhook = req.originalUrl.includes('webhook-test'); + res.status(404); + return res.render('form-trigger-404', { isTestWebhook }); + } else { + return ResponseHelper.sendErrorResponse(res, error as Error); + } } // Don't respond, if already responded diff --git a/packages/cli/templates/form-trigger-404.handlebars b/packages/cli/templates/form-trigger-404.handlebars new file mode 100644 index 0000000000000..e4118fd810240 --- /dev/null +++ b/packages/cli/templates/form-trigger-404.handlebars @@ -0,0 +1,86 @@ + + +
+ + + + + {{#if isTestWebhook}} +Click the "Test Step" button in your form trigger
+This usually occurs if the n8n workflow serving this form is deactivated or no + longer exist
+This is test version of your form. Use it only for testing your Form Trigger.
++ This usually occurs if the n8n workflow serving this form is deactivated or no + longer exist +
+ {{/if}} +