mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-16 17:46:45 +00:00
feat(core): Link 'Error Trigger' nodes to the parent execution that errored (#16016)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import type { User } from '@n8n/db';
|
import type { GlobalConfig } from '@n8n/config';
|
||||||
|
import type { Project, User, WorkflowEntity, WorkflowRepository } from '@n8n/db';
|
||||||
import { mock } from 'jest-mock-extended';
|
import { mock } from 'jest-mock-extended';
|
||||||
import {
|
import {
|
||||||
NodeConnectionTypes,
|
NodeConnectionTypes,
|
||||||
@@ -7,8 +8,10 @@ import {
|
|||||||
type INodeType,
|
type INodeType,
|
||||||
type IWorkflowBase,
|
type IWorkflowBase,
|
||||||
type IWorkflowExecuteAdditionalData,
|
type IWorkflowExecuteAdditionalData,
|
||||||
|
type ExecutionError,
|
||||||
} from 'n8n-workflow';
|
} from 'n8n-workflow';
|
||||||
|
|
||||||
|
import type { IWorkflowErrorData } from '@/interfaces';
|
||||||
import type { NodeTypes } from '@/node-types';
|
import type { NodeTypes } from '@/node-types';
|
||||||
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
import * as WorkflowExecuteAdditionalData from '@/workflow-execute-additional-data';
|
||||||
import type { WorkflowRunner } from '@/workflow-runner';
|
import type { WorkflowRunner } from '@/workflow-runner';
|
||||||
@@ -490,6 +493,113 @@ describe('WorkflowExecutionService', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('executeErrorWorkflow()', () => {
|
||||||
|
test('should call `WorkflowRunner.run()` with correct parameters', async () => {
|
||||||
|
const workflowErrorData: IWorkflowErrorData = {
|
||||||
|
workflow: { id: 'workflow-id', name: 'Test Workflow' },
|
||||||
|
execution: {
|
||||||
|
id: 'execution-id',
|
||||||
|
mode: 'manual',
|
||||||
|
error: new Error('Test error') as ExecutionError,
|
||||||
|
lastNodeExecuted: 'Node with error',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const workflowRunnerMock = mock<WorkflowRunner>();
|
||||||
|
workflowRunnerMock.run.mockResolvedValue('fake-execution-id');
|
||||||
|
|
||||||
|
const errorTriggerType = 'n8n-nodes-base.errorTrigger';
|
||||||
|
const globalConfig = mock<GlobalConfig>({
|
||||||
|
nodes: {
|
||||||
|
errorTriggerType,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const errorTriggerNode: INode = {
|
||||||
|
id: 'error-trigger-node-id',
|
||||||
|
name: 'Error Trigger',
|
||||||
|
type: errorTriggerType,
|
||||||
|
typeVersion: 1,
|
||||||
|
position: [0, 0],
|
||||||
|
parameters: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const errorWorkflow = mock<WorkflowEntity>({
|
||||||
|
id: 'error-workflow-id',
|
||||||
|
name: 'Error Workflow',
|
||||||
|
active: false,
|
||||||
|
isArchived: false,
|
||||||
|
pinData: {},
|
||||||
|
nodes: [errorTriggerNode],
|
||||||
|
connections: {},
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const workflowRepositoryMock = mock<WorkflowRepository>();
|
||||||
|
workflowRepositoryMock.findOneBy.mockResolvedValue(errorWorkflow);
|
||||||
|
|
||||||
|
const service = new WorkflowExecutionService(
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
workflowRepositoryMock,
|
||||||
|
nodeTypes,
|
||||||
|
mock(),
|
||||||
|
workflowRunnerMock,
|
||||||
|
globalConfig,
|
||||||
|
mock(),
|
||||||
|
mock(),
|
||||||
|
);
|
||||||
|
|
||||||
|
await service.executeErrorWorkflow(
|
||||||
|
'error-workflow-id',
|
||||||
|
workflowErrorData,
|
||||||
|
mock<Project>({ id: 'project-id' }),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(workflowRunnerMock.run).toHaveBeenCalledTimes(1);
|
||||||
|
expect(workflowRunnerMock.run).toHaveBeenCalledWith({
|
||||||
|
executionMode: 'error',
|
||||||
|
executionData: {
|
||||||
|
executionData: {
|
||||||
|
contextData: {},
|
||||||
|
metadata: {},
|
||||||
|
nodeExecutionStack: [
|
||||||
|
{
|
||||||
|
node: errorTriggerNode,
|
||||||
|
data: {
|
||||||
|
main: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
json: workflowErrorData,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
source: null,
|
||||||
|
metadata: {
|
||||||
|
parentExecution: {
|
||||||
|
executionId: 'execution-id',
|
||||||
|
workflowId: 'workflow-id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
waitingExecution: {},
|
||||||
|
waitingExecutionSource: {},
|
||||||
|
},
|
||||||
|
resultData: {
|
||||||
|
runData: {},
|
||||||
|
},
|
||||||
|
startData: {},
|
||||||
|
},
|
||||||
|
workflowData: errorWorkflow,
|
||||||
|
projectId: 'project-id',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function createMainConnection(targetNode: string, sourceNode: string): IConnections {
|
function createMainConnection(targetNode: string, sourceNode: string): IConnections {
|
||||||
|
|||||||
@@ -320,6 +320,14 @@ export class WorkflowExecutionService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const parentExecution =
|
||||||
|
workflowErrorData.execution?.id && workflowErrorData.workflow?.id
|
||||||
|
? {
|
||||||
|
executionId: workflowErrorData.execution.id,
|
||||||
|
workflowId: workflowErrorData.workflow.id,
|
||||||
|
}
|
||||||
|
: undefined;
|
||||||
|
|
||||||
// Can execute without webhook so go on
|
// Can execute without webhook so go on
|
||||||
// Initialize the data of the webhook node
|
// Initialize the data of the webhook node
|
||||||
const nodeExecutionStack: IExecuteData[] = [];
|
const nodeExecutionStack: IExecuteData[] = [];
|
||||||
@@ -335,6 +343,11 @@ export class WorkflowExecutionService {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
source: null,
|
source: null,
|
||||||
|
...(parentExecution && {
|
||||||
|
metadata: {
|
||||||
|
parentExecution,
|
||||||
|
},
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const runExecutionData: IRunExecutionData = {
|
const runExecutionData: IRunExecutionData = {
|
||||||
|
|||||||
Reference in New Issue
Block a user