mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
fix(core): Prefer triggers with run data during partial executions (#14691)
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { IConnections, INode, INodeType, INodeTypes, IPinData } from 'n8n-workflow';
|
||||
import type { IConnections, INode, INodeType, INodeTypes, IPinData, IRunData } from 'n8n-workflow';
|
||||
import { Workflow } from 'n8n-workflow';
|
||||
|
||||
import { toIConnections } from './helpers';
|
||||
import { createNodeData, toIConnections, toITaskData } from './helpers';
|
||||
import { DirectedGraph } from '../directed-graph';
|
||||
import { findTriggerForPartialExecution } from '../find-trigger-for-partial-execution';
|
||||
|
||||
describe('findTriggerForPartialExecution', () => {
|
||||
@@ -188,7 +189,7 @@ describe('findTriggerForPartialExecution', () => {
|
||||
'$description',
|
||||
({ nodes, connections, destinationNodeName, expectedTrigger, pinData }) => {
|
||||
const workflow = createMockWorkflow(nodes, toIConnections(connections), pinData);
|
||||
expect(findTriggerForPartialExecution(workflow, destinationNodeName)).toBe(
|
||||
expect(findTriggerForPartialExecution(workflow, destinationNodeName, {})).toBe(
|
||||
expectedTrigger,
|
||||
);
|
||||
},
|
||||
@@ -199,19 +200,39 @@ describe('findTriggerForPartialExecution', () => {
|
||||
describe('Error and Edge Case Handling', () => {
|
||||
it('should handle non-existent destination node gracefully', () => {
|
||||
const workflow = createMockWorkflow([], {});
|
||||
expect(findTriggerForPartialExecution(workflow, 'NonExistentNode')).toBeUndefined();
|
||||
expect(findTriggerForPartialExecution(workflow, 'NonExistentNode', {})).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle empty workflow', () => {
|
||||
const workflow = createMockWorkflow([], {});
|
||||
expect(findTriggerForPartialExecution(workflow, '')).toBeUndefined();
|
||||
expect(findTriggerForPartialExecution(workflow, '', {})).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle workflow with no connections', () => {
|
||||
const workflow = createMockWorkflow([manualTriggerNode], {});
|
||||
expect(findTriggerForPartialExecution(workflow, manualTriggerNode.name)).toBe(
|
||||
expect(findTriggerForPartialExecution(workflow, manualTriggerNode.name, {})).toBe(
|
||||
manualTriggerNode,
|
||||
);
|
||||
});
|
||||
|
||||
it('should prefer triggers that have run data', () => {
|
||||
// ARRANGE
|
||||
const trigger1 = createNodeData({ name: 'trigger1', type: 'n8n-nodes-base.manualTrigger' });
|
||||
const trigger2 = createNodeData({ name: 'trigger2', type: 'n8n-nodes-base.manualTrigger' });
|
||||
const node = createNodeData({ name: 'node' });
|
||||
const workflow = new DirectedGraph()
|
||||
.addNodes(trigger1, trigger2, node)
|
||||
.addConnections({ from: trigger1, to: node }, { from: trigger2, to: node })
|
||||
.toWorkflow({ name: '', active: false, nodeTypes });
|
||||
const runData: IRunData = {
|
||||
[trigger1.name]: [toITaskData([{ data: { nodeName: 'trigger1' } }])],
|
||||
};
|
||||
|
||||
// ACT
|
||||
const chosenTrigger = findTriggerForPartialExecution(workflow, node.name, runData);
|
||||
|
||||
// ASSERT
|
||||
expect(chosenTrigger).toBe(trigger1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as assert from 'assert/strict';
|
||||
import type { INode, INodeType, Workflow } from 'n8n-workflow';
|
||||
import type { INode, INodeType, IRunData, Workflow } from 'n8n-workflow';
|
||||
|
||||
const isTriggerNode = (nodeType: INodeType) => nodeType.description.group.includes('trigger');
|
||||
|
||||
@@ -29,6 +29,7 @@ function findAllParentTriggers(workflow: Workflow, destinationNodeName: string)
|
||||
export function findTriggerForPartialExecution(
|
||||
workflow: Workflow,
|
||||
destinationNodeName: string,
|
||||
runData: IRunData,
|
||||
): INode | undefined {
|
||||
// First, check if the destination node itself is a trigger
|
||||
const destinationNode = workflow.getNode(destinationNodeName);
|
||||
@@ -48,6 +49,13 @@ export function findTriggerForPartialExecution(
|
||||
(trigger) => !trigger.disabled,
|
||||
);
|
||||
|
||||
// prefer triggers that have run data
|
||||
for (const trigger of parentTriggers) {
|
||||
if (runData[trigger.name]) {
|
||||
return trigger;
|
||||
}
|
||||
}
|
||||
|
||||
// Prioritize webhook triggers with pinned-data
|
||||
const pinnedTriggers = parentTriggers
|
||||
// TODO: add the other filters here from `findAllPinnedActivators`, see
|
||||
|
||||
@@ -394,7 +394,7 @@ export class WorkflowExecute {
|
||||
}
|
||||
|
||||
// 1. Find the Trigger
|
||||
const trigger = findTriggerForPartialExecution(workflow, destinationNodeName);
|
||||
const trigger = findTriggerForPartialExecution(workflow, destinationNodeName, runData);
|
||||
if (trigger === undefined) {
|
||||
throw new UserError('Connect a trigger to run this node');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user