diff --git a/packages/nodes-base/nodes/Wait/Wait.node.ts b/packages/nodes-base/nodes/Wait/Wait.node.ts index b737b9f265..56ca638141 100644 --- a/packages/nodes-base/nodes/Wait/Wait.node.ts +++ b/packages/nodes-base/nodes/Wait/Wait.node.ts @@ -14,6 +14,7 @@ import { NodeOperationError, } from 'n8n-workflow'; +import { validateWaitAmount, validateWaitUnit } from './validation'; import { updateDisplayOptions } from '../../utils/utilities'; import { formDescription, @@ -47,6 +48,7 @@ const toWaitAmount: INodeProperties = { }, default: 1, description: 'The time to wait', + validateType: 'number', }; const unitSelector: INodeProperties = { @@ -487,9 +489,24 @@ export class Wait extends Webhook { let waitTill: Date; if (resume === 'timeInterval') { - const unit = context.getNodeParameter('unit', 0) as string; + const unit = context.getNodeParameter('unit', 0); + + if (!validateWaitUnit(unit)) { + throw new NodeOperationError( + context.getNode(), + "Invalid wait unit. Valid units are 'seconds', 'minutes', 'hours', or 'days'.", + ); + } + + let waitAmount = context.getNodeParameter('amount', 0); + + if (!validateWaitAmount(waitAmount)) { + throw new NodeOperationError( + context.getNode(), + 'Invalid wait amount. It must be a positive number.', + ); + } - let waitAmount = context.getNodeParameter('amount', 0) as number; if (unit === 'minutes') { waitAmount *= 60; } @@ -514,7 +531,7 @@ export class Wait extends Webhook { } catch (e) { throw new NodeOperationError( context.getNode(), - '[Wait node] Cannot put execution to wait because `dateTime` parameter is not a valid date. Please pick a specific date and time to wait until.', + 'Cannot put execution to wait because `dateTime` parameter is not a valid date. Please pick a specific date and time to wait until.', ); } } diff --git a/packages/nodes-base/nodes/Wait/test/Wait.node.test.ts b/packages/nodes-base/nodes/Wait/test/Wait.node.test.ts index 60e094c7d4..49a41e9700 100644 --- a/packages/nodes-base/nodes/Wait/test/Wait.node.test.ts +++ b/packages/nodes-base/nodes/Wait/test/Wait.node.test.ts @@ -12,7 +12,7 @@ describe('Execute Wait Node', () => { beforeAll(() => { timer = setInterval(() => jest.advanceTimersByTime(1000), 10); - jest.useFakeTimers(); + jest.useFakeTimers().setSystemTime(new Date('2025-01-01')); }); afterAll(() => { @@ -67,5 +67,71 @@ describe('Execute Wait Node', () => { }, ); + describe('Validation', () => { + describe('Time interval', () => { + it.each([ + { + unit: 'seconds', + amount: 300, + expectedWaitTill: () => DateTime.now().plus({ seconds: 300 }).toJSDate(), + }, + { + unit: 'minutes', + amount: 2, + expectedWaitTill: () => DateTime.now().plus({ minutes: 2 }).toJSDate(), + }, + { + unit: 'hours', + amount: 1, + expectedWaitTill: () => DateTime.now().plus({ hours: 1 }).toJSDate(), + }, + { + unit: 'days', + amount: 10, + expectedWaitTill: () => DateTime.now().plus({ days: 10 }).toJSDate(), + }, + { + unit: 'seconds', + amount: -10, + error: 'Invalid wait amount. It must be a positive number.', + }, + { + unit: 'years', + amount: 10, + error: "Invalid wait unit. Valid units are 'seconds', 'minutes', 'hours', or 'days'.", + }, + { + unit: 'minutes', + amount: 'test', + error: 'Invalid wait amount. It must be a positive number.', + }, + ])( + 'Validate wait unit: $unit, amount: $amount', + async ({ unit, amount, expectedWaitTill, error }) => { + const putExecutionToWaitSpy = jest.fn(); + const waitNode = new Wait(); + const executeFunctionsMock = mock({ + getNodeParameter: jest.fn().mockImplementation((paramName: string) => { + if (paramName === 'resume') return 'timeInterval'; + if (paramName === 'amount') return amount; + if (paramName === 'unit') return unit; + }), + getTimezone: jest.fn().mockReturnValue('UTC'), + putExecutionToWait: putExecutionToWaitSpy, + getInputData: jest.fn(), + getNode: jest.fn(), + }); + + if (!error) { + await expect(waitNode.execute(executeFunctionsMock)).resolves.not.toThrow(); + expect(putExecutionToWaitSpy).toHaveBeenCalledWith(expectedWaitTill?.()); + } else { + await expect(waitNode.execute(executeFunctionsMock)).rejects.toThrowError(error); + } + }, + ); + }); + }); + new NodeTestHarness().setupTests(); }); diff --git a/packages/nodes-base/nodes/Wait/validation.ts b/packages/nodes-base/nodes/Wait/validation.ts new file mode 100644 index 0000000000..860da48ee7 --- /dev/null +++ b/packages/nodes-base/nodes/Wait/validation.ts @@ -0,0 +1,8 @@ +export function validateWaitAmount(amount: unknown): amount is number { + return typeof amount === 'number' && amount > 0; +} + +export type WaitUnit = 'seconds' | 'minutes' | 'hours' | 'days'; +export function validateWaitUnit(unit: unknown): unit is WaitUnit { + return typeof unit === 'string' && ['seconds', 'minutes', 'hours', 'days'].includes(unit); +}