From 8ffd3167d58d30f087fd31010e6f79f1398d8f49 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Fri, 21 Feb 2025 18:44:09 +0200 Subject: [PATCH] fix(core): Fix resuming executions on test webhooks from Wait forms (#13410) --- .../webhooks/__tests__/waiting-forms.test.ts | 41 +++++++++++++++---- packages/cli/src/webhooks/waiting-forms.ts | 6 +++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/webhooks/__tests__/waiting-forms.test.ts b/packages/cli/src/webhooks/__tests__/waiting-forms.test.ts index f342095b77..0ae8d5f7d8 100644 --- a/packages/cli/src/webhooks/__tests__/waiting-forms.test.ts +++ b/packages/cli/src/webhooks/__tests__/waiting-forms.test.ts @@ -1,12 +1,16 @@ +import type express from 'express'; import { mock } from 'jest-mock-extended'; import { FORM_NODE_TYPE, type Workflow } from 'n8n-workflow'; import type { ExecutionRepository } from '@/databases/repositories/execution.repository'; import { WaitingForms } from '@/webhooks/waiting-forms'; +import type { IExecutionResponse } from '../../interfaces'; +import type { WaitingWebhookRequest } from '../webhook.types'; + describe('WaitingForms', () => { const executionRepository = mock(); - const waitingWebhooks = new WaitingForms(mock(), mock(), executionRepository, mock()); + const waitingForms = new WaitingForms(mock(), mock(), executionRepository, mock()); beforeEach(() => { jest.restoreAllMocks(); @@ -27,7 +31,7 @@ describe('WaitingForms', () => { }, }); - const result = waitingWebhooks.findCompletionPage(workflow, {}, 'Form1'); + const result = waitingForms.findCompletionPage(workflow, {}, 'Form1'); expect(result).toBe('Form1'); }); @@ -45,7 +49,7 @@ describe('WaitingForms', () => { }, }); - const result = waitingWebhooks.findCompletionPage(workflow, {}, 'Form1'); + const result = waitingForms.findCompletionPage(workflow, {}, 'Form1'); expect(result).toBeUndefined(); }); @@ -61,7 +65,7 @@ describe('WaitingForms', () => { }, }); - const result = waitingWebhooks.findCompletionPage(workflow, {}, 'NonForm'); + const result = waitingForms.findCompletionPage(workflow, {}, 'NonForm'); expect(result).toBeUndefined(); }); @@ -79,7 +83,7 @@ describe('WaitingForms', () => { }, }); - const result = waitingWebhooks.findCompletionPage(workflow, {}, 'Form1'); + const result = waitingForms.findCompletionPage(workflow, {}, 'Form1'); expect(result).toBeUndefined(); }); @@ -121,7 +125,7 @@ describe('WaitingForms', () => { Form3: [], }; - const result = waitingWebhooks.findCompletionPage(workflow, runData, 'LastNode'); + const result = waitingForms.findCompletionPage(workflow, runData, 'LastNode'); expect(result).toBe('Form3'); }); @@ -151,7 +155,7 @@ describe('WaitingForms', () => { }, }); - const result = waitingWebhooks.findCompletionPage(workflow, {}, 'LastNode'); + const result = waitingForms.findCompletionPage(workflow, {}, 'LastNode'); expect(result).toBeUndefined(); }); @@ -192,8 +196,29 @@ describe('WaitingForms', () => { Form2: [], }; - const result = waitingWebhooks.findCompletionPage(workflow, runData, 'LastNode'); + const result = waitingForms.findCompletionPage(workflow, runData, 'LastNode'); expect(result).toBe('Form2'); }); + + it('should mark as test form webhook when execution mode is manual', async () => { + jest + // @ts-expect-error Protected method + .spyOn(waitingForms, 'getWebhookExecutionData') + // @ts-expect-error Protected method + .mockResolvedValue(mock()); + + const execution = mock({ + finished: false, + mode: 'manual', + data: { + resultData: { lastNodeExecuted: 'someNode', error: undefined }, + }, + }); + executionRepository.findSingleExecution.mockResolvedValue(execution); + + await waitingForms.executeWebhook(mock(), mock()); + + expect(execution.data.isTestWebhook).toBe(true); + }); }); }); diff --git a/packages/cli/src/webhooks/waiting-forms.ts b/packages/cli/src/webhooks/waiting-forms.ts index 0c291dee39..2c8a65afe0 100644 --- a/packages/cli/src/webhooks/waiting-forms.ts +++ b/packages/cli/src/webhooks/waiting-forms.ts @@ -116,6 +116,12 @@ export class WaitingForms extends WaitingWebhooks { } } + /** + * A manual execution resumed by a webhook call needs to be marked as such + * so workers in scaling mode reuse the existing execution data. + */ + if (execution.mode === 'manual') execution.data.isTestWebhook = true; + return await this.getWebhookExecutionData({ execution, req,