From 6ec6b5197ae97eb86496effd458fcc0b9b223ef3 Mon Sep 17 00:00:00 2001 From: Michael Kret <88898367+michael-radency@users.noreply.github.com> Date: Thu, 10 Oct 2024 08:00:55 +0300 Subject: [PATCH] fix(n8n Trigger Node): Merge with Workflow Trigger node (#11174) --- .../nodes/N8nTrigger/N8nTrigger.node.ts | 28 ++++- .../nodes/N8nTrigger/test/trigger.test.ts | 109 ++++++++++++++++++ .../WorkflowTrigger/WorkflowTrigger.node.ts | 8 ++ 3 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 packages/nodes-base/nodes/N8nTrigger/test/trigger.test.ts diff --git a/packages/nodes-base/nodes/N8nTrigger/N8nTrigger.node.ts b/packages/nodes-base/nodes/N8nTrigger/N8nTrigger.node.ts index b2b82c2842..4224381e1e 100644 --- a/packages/nodes-base/nodes/N8nTrigger/N8nTrigger.node.ts +++ b/packages/nodes-base/nodes/N8nTrigger/N8nTrigger.node.ts @@ -6,7 +6,7 @@ import type { } from 'n8n-workflow'; import { NodeConnectionType } from 'n8n-workflow'; -type eventType = 'Instance started' | undefined; +type eventType = 'Instance started' | 'Workflow activated' | 'Workflow updated' | undefined; export class N8nTrigger implements INodeType { description: INodeTypeDescription = { @@ -30,26 +30,46 @@ export class N8nTrigger implements INodeType { type: 'multiOptions', required: true, default: [], - description: - 'Specifies under which conditions an execution should happen: Instance started: Triggers when this n8n instance is started or re-started', + description: `Specifies under which conditions an execution should happen: + `, options: [ + { + name: 'Active Workflow Updated', + value: 'update', + description: 'Triggers when this workflow is updated', + }, { name: 'Instance Started', value: 'init', description: 'Triggers when this n8n instance is started or re-started', }, + { + name: 'Workflow Activated', + value: 'activate', + description: 'Triggers when this workflow is activated', + }, ], }, ], }; async trigger(this: ITriggerFunctions): Promise { - const events = this.getNodeParameter('events', []) as string[]; + const events = (this.getNodeParameter('events') as string[]) || []; const activationMode = this.getActivationMode(); if (events.includes(activationMode)) { let event: eventType; + if (activationMode === 'activate') { + event = 'Workflow activated'; + } + if (activationMode === 'update') { + event = 'Workflow updated'; + } if (activationMode === 'init') { event = 'Instance started'; } diff --git a/packages/nodes-base/nodes/N8nTrigger/test/trigger.test.ts b/packages/nodes-base/nodes/N8nTrigger/test/trigger.test.ts new file mode 100644 index 0000000000..43e49554ac --- /dev/null +++ b/packages/nodes-base/nodes/N8nTrigger/test/trigger.test.ts @@ -0,0 +1,109 @@ +/* eslint-disable n8n-nodes-base/node-filename-against-convention */ +import { N8nTrigger } from '../N8nTrigger.node'; + +describe('N8nTrigger', () => { + let n8nTrigger: N8nTrigger; + let mockTriggerFunctions: any; + + beforeEach(() => { + n8nTrigger = new N8nTrigger(); + + // Mock trigger functions + mockTriggerFunctions = { + emit: jest.fn(), + getNodeParameter: jest.fn(), + getActivationMode: jest.fn(), + getWorkflow: jest.fn(() => ({ id: 'test-workflow-id' })), + helpers: { + returnJsonArray: jest.fn((data) => data), + }, + }; + }); + + describe('trigger', () => { + it('should emit event when activation mode matches selected events', async () => { + mockTriggerFunctions.getNodeParameter.mockReturnValue(['activate']); + mockTriggerFunctions.getActivationMode.mockReturnValue('activate'); + + await n8nTrigger.trigger.call(mockTriggerFunctions); + + expect(mockTriggerFunctions.emit).toHaveBeenCalledWith([ + [ + { + event: 'Workflow activated', + timestamp: expect.any(String), + workflow_id: 'test-workflow-id', + }, + ], + ]); + }); + + it('should not emit event when activation mode does not match selected events', async () => { + mockTriggerFunctions.getNodeParameter.mockReturnValue(['update']); + mockTriggerFunctions.getActivationMode.mockReturnValue('activate'); + + await n8nTrigger.trigger.call(mockTriggerFunctions); + + expect(mockTriggerFunctions.emit).not.toHaveBeenCalled(); + }); + + it('should return manual trigger function', async () => { + const result = await n8nTrigger.trigger.call(mockTriggerFunctions); + + expect(result).toHaveProperty('manualTriggerFunction'); + expect(typeof result.manualTriggerFunction).toBe('function'); + }); + + it('should emit correct event for instance started', async () => { + mockTriggerFunctions.getNodeParameter.mockReturnValue(['init']); + mockTriggerFunctions.getActivationMode.mockReturnValue('init'); + + await n8nTrigger.trigger.call(mockTriggerFunctions); + + expect(mockTriggerFunctions.emit).toHaveBeenCalledWith([ + [ + { + event: 'Instance started', + timestamp: expect.any(String), + workflow_id: 'test-workflow-id', + }, + ], + ]); + }); + + it('should emit correct event for workflow updated', async () => { + mockTriggerFunctions.getNodeParameter.mockReturnValue(['update']); + mockTriggerFunctions.getActivationMode.mockReturnValue('update'); + + await n8nTrigger.trigger.call(mockTriggerFunctions); + + expect(mockTriggerFunctions.emit).toHaveBeenCalledWith([ + [ + { + event: 'Workflow updated', + timestamp: expect.any(String), + workflow_id: 'test-workflow-id', + }, + ], + ]); + }); + }); + + describe('description', () => { + it('should have correct properties', () => { + expect(n8nTrigger.description).toMatchObject({ + displayName: 'n8n Trigger', + name: 'n8nTrigger', + group: ['trigger'], + version: 1, + }); + }); + + it('should have required properties configuration', () => { + const eventsProperty = n8nTrigger.description.properties.find((p) => p.name === 'events'); + expect(eventsProperty).toBeDefined(); + expect(eventsProperty?.required).toBe(true); + expect(eventsProperty?.type).toBe('multiOptions'); + }); + }); +}); diff --git a/packages/nodes-base/nodes/WorkflowTrigger/WorkflowTrigger.node.ts b/packages/nodes-base/nodes/WorkflowTrigger/WorkflowTrigger.node.ts index 7c6a2babf1..8b67094865 100644 --- a/packages/nodes-base/nodes/WorkflowTrigger/WorkflowTrigger.node.ts +++ b/packages/nodes-base/nodes/WorkflowTrigger/WorkflowTrigger.node.ts @@ -12,6 +12,7 @@ type activationType = 'activate' | 'update'; export class WorkflowTrigger implements INodeType { description: INodeTypeDescription = { displayName: 'Workflow Trigger', + hidden: true, name: 'workflowTrigger', icon: 'fa:network-wired', iconColor: 'orange-red', @@ -28,6 +29,13 @@ export class WorkflowTrigger implements INodeType { inputs: [], outputs: [NodeConnectionType.Main], properties: [ + { + displayName: + "This node is deprecated and would not be updated in the future. Please use 'n8n Trigger' node instead.", + name: 'oldVersionNotice', + type: 'notice', + default: '', + }, { displayName: 'Events', name: 'events',