mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
fix(core): Aborting manual trigger tests should call closeFunction
(#9980)
This commit is contained in:
parent
504bb704d3
commit
6107798516
|
@ -1424,13 +1424,6 @@ export class Workflow {
|
||||||
return { data: null };
|
return { data: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (triggerResponse.manualTriggerFunction !== undefined) {
|
|
||||||
// If a manual trigger function is defined call it and wait till it did run
|
|
||||||
await triggerResponse.manualTriggerFunction();
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await triggerResponse.manualTriggerResponse!;
|
|
||||||
|
|
||||||
let closeFunction;
|
let closeFunction;
|
||||||
if (triggerResponse.closeFunction) {
|
if (triggerResponse.closeFunction) {
|
||||||
// In manual mode we return the trigger closeFunction. That allows it to be called directly
|
// In manual mode we return the trigger closeFunction. That allows it to be called directly
|
||||||
|
@ -1439,8 +1432,18 @@ export class Workflow {
|
||||||
// If we would not be able to wait for it to close would it cause problems with "own" mode as the
|
// If we would not be able to wait for it to close would it cause problems with "own" mode as the
|
||||||
// process would be killed directly after it and so the acknowledge would not have been finished yet.
|
// process would be killed directly after it and so the acknowledge would not have been finished yet.
|
||||||
closeFunction = triggerResponse.closeFunction;
|
closeFunction = triggerResponse.closeFunction;
|
||||||
|
|
||||||
|
// Manual testing of Trigger nodes creates an execution. If the execution is cancelled, `closeFunction` should be called to cleanup any open connections/consumers
|
||||||
|
abortSignal?.addEventListener('abort', closeFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (triggerResponse.manualTriggerFunction !== undefined) {
|
||||||
|
// If a manual trigger function is defined call it and wait till it did run
|
||||||
|
await triggerResponse.manualTriggerFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await triggerResponse.manualTriggerResponse!;
|
||||||
|
|
||||||
if (response.length === 0) {
|
if (response.length === 0) {
|
||||||
return { data: null, closeFunction };
|
return { data: null, closeFunction };
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,18 @@ import type {
|
||||||
IBinaryKeyData,
|
IBinaryKeyData,
|
||||||
IConnections,
|
IConnections,
|
||||||
IDataObject,
|
IDataObject,
|
||||||
|
IExecuteData,
|
||||||
INode,
|
INode,
|
||||||
|
INodeExecuteFunctions,
|
||||||
INodeExecutionData,
|
INodeExecutionData,
|
||||||
INodeParameters,
|
INodeParameters,
|
||||||
INodeType,
|
INodeType,
|
||||||
INodeTypeDescription,
|
INodeTypeDescription,
|
||||||
INodeTypes,
|
INodeTypes,
|
||||||
IRunExecutionData,
|
IRunExecutionData,
|
||||||
|
ITriggerFunctions,
|
||||||
|
ITriggerResponse,
|
||||||
|
IWorkflowExecuteAdditionalData,
|
||||||
NodeParameterValueType,
|
NodeParameterValueType,
|
||||||
} from '@/Interfaces';
|
} from '@/Interfaces';
|
||||||
import { Workflow, type WorkflowParameters } from '@/Workflow';
|
import { Workflow, type WorkflowParameters } from '@/Workflow';
|
||||||
|
@ -2015,4 +2020,67 @@ describe('Workflow', () => {
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('runNode', () => {
|
||||||
|
const nodeTypes = mock<INodeTypes>();
|
||||||
|
const triggerNode = mock<INode>();
|
||||||
|
const triggerResponse = mock<ITriggerResponse>({
|
||||||
|
closeFunction: jest.fn(),
|
||||||
|
// This node should never trigger, or return
|
||||||
|
manualTriggerFunction: async () => await new Promise(() => {}),
|
||||||
|
});
|
||||||
|
const triggerNodeType = mock<INodeType>({
|
||||||
|
description: {
|
||||||
|
properties: [],
|
||||||
|
},
|
||||||
|
execute: undefined,
|
||||||
|
poll: undefined,
|
||||||
|
webhook: undefined,
|
||||||
|
async trigger(this: ITriggerFunctions) {
|
||||||
|
return triggerResponse;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
nodeTypes.getByNameAndVersion.mockReturnValue(triggerNodeType);
|
||||||
|
|
||||||
|
const workflow = new Workflow({
|
||||||
|
nodeTypes,
|
||||||
|
nodes: [triggerNode],
|
||||||
|
connections: {},
|
||||||
|
active: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const executionData = mock<IExecuteData>();
|
||||||
|
const runExecutionData = mock<IRunExecutionData>();
|
||||||
|
const additionalData = mock<IWorkflowExecuteAdditionalData>();
|
||||||
|
const nodeExecuteFunctions = mock<INodeExecuteFunctions>();
|
||||||
|
const triggerFunctions = mock<ITriggerFunctions>();
|
||||||
|
nodeExecuteFunctions.getExecuteTriggerFunctions.mockReturnValue(triggerFunctions);
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
test('should call closeFunction when manual trigger is aborted', async () => {
|
||||||
|
const runPromise = workflow.runNode(
|
||||||
|
executionData,
|
||||||
|
runExecutionData,
|
||||||
|
0,
|
||||||
|
additionalData,
|
||||||
|
nodeExecuteFunctions,
|
||||||
|
'manual',
|
||||||
|
abortController.signal,
|
||||||
|
);
|
||||||
|
// Yield back to the event-loop to let async parts of `runNode` execute
|
||||||
|
await new Promise((resolve) => setImmediate(resolve));
|
||||||
|
|
||||||
|
let isSettled = false;
|
||||||
|
void runPromise.then(() => {
|
||||||
|
isSettled = true;
|
||||||
|
});
|
||||||
|
expect(isSettled).toBe(false);
|
||||||
|
expect(abortController.signal.aborted).toBe(false);
|
||||||
|
expect(triggerResponse.closeFunction).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
abortController.abort();
|
||||||
|
expect(triggerResponse.closeFunction).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue