import type { Request, Response } from 'express';
import { type MockProxy, mock } from 'jest-mock-extended';
import type {
	IExecuteFunctions,
	INodeProperties,
	IWebhookFunctions,
	IWorkflowSettings,
} from 'n8n-workflow';
import { NodeOperationError, WAIT_INDEFINITELY } from 'n8n-workflow';

import { configureWaitTillDate } from '../configureWaitTillDate.util';
import {
	getSendAndWaitProperties,
	getSendAndWaitConfig,
	createEmail,
	sendAndWaitWebhook,
} from '../utils';

describe('Send and Wait utils tests', () => {
	let mockExecuteFunctions: MockProxy<IExecuteFunctions>;
	let mockWebhookFunctions: MockProxy<IWebhookFunctions>;

	beforeEach(() => {
		mockExecuteFunctions = mock<IExecuteFunctions>();
		mockWebhookFunctions = mock<IWebhookFunctions>();
		mockWebhookFunctions.getWorkflowSettings.mockReturnValue(mock<IWorkflowSettings>({}));
	});

	describe('getSendAndWaitProperties', () => {
		it('should return properties with correct display options', () => {
			const targetProperties: INodeProperties[] = [
				{
					displayName: 'Test Property',
					name: 'testProperty',
					type: 'string',
					default: '',
				},
			];
			const extraOptions: INodeProperties[] = [
				{
					displayName: 'Extra Property',
					name: 'extraProperty',
					type: 'string',
					default: '',
				},
			];

			const result = getSendAndWaitProperties(targetProperties, undefined, undefined, {
				extraOptions,
			});

			expect(result).toEqual(
				expect.arrayContaining([
					expect.objectContaining({
						name: 'options',
						options: expect.arrayContaining([
							expect.objectContaining({
								name: 'extraProperty',
							}),
						]),
					}),
				]),
			);
		});

		it('should include extra options when provided', () => {
			const targetProperties: INodeProperties[] = [
				{
					displayName: 'Test Property',
					name: 'testProperty',
					type: 'string',
					default: '',
				},
			];
			const extraOptions: INodeProperties[] = [
				{
					displayName: 'Extra Property',
					name: 'extraProperty',
					type: 'string',
					default: '',
				},
			];
			const result = getSendAndWaitProperties(targetProperties, undefined, undefined, {
				extraOptions,
			});
			expect(result).toEqual(
				expect.arrayContaining([
					expect.objectContaining({
						displayOptions: {
							show: {
								resource: ['message'],
								operation: ['sendAndWait'],
							},
						},
					}),
				]),
			);
		});
	});

	describe('getSendAndWaitConfig', () => {
		it('should return correct config for single approval', () => {
			mockExecuteFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					message: 'Test message',
					subject: 'Test subject',
					'approvalOptions.values': {
						approvalType: 'single',
						approveLabel: 'Approve',
						buttonApprovalStyle: 'primary',
					},
				};
				return params[parameterName];
			});

			mockExecuteFunctions.getSignedResumeUrl.mockReturnValue(
				'http://localhost/waiting-webhook/nodeID?approved=true&signature=abc',
			);
			const config = getSendAndWaitConfig(mockExecuteFunctions);

			expect(config).toEqual({
				appendAttribution: undefined,
				title: 'Test subject',
				message: 'Test message',
				options: [
					{
						label: 'Approve',
						style: 'primary',
						url: 'http://localhost/waiting-webhook/nodeID?approved=true&signature=abc',
					},
				],
			});
		});

		it('should return correct config for double approval', () => {
			mockExecuteFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					message: 'Test message',
					subject: 'Test subject',
					'approvalOptions.values': {
						approvalType: 'double',
						approveLabel: 'Approve',
						buttonApprovalStyle: 'primary',
						disapproveLabel: 'Reject',
						buttonDisapprovalStyle: 'secondary',
					},
				};
				return params[parameterName];
			});

			mockExecuteFunctions.getSignedResumeUrl.mockReturnValueOnce(
				'http://localhost/waiting-webhook/nodeID?approved=true&signature=abc',
			);
			mockExecuteFunctions.getSignedResumeUrl.mockReturnValueOnce(
				'http://localhost/waiting-webhook/nodeID?approved=false&signature=abc',
			);

			const config = getSendAndWaitConfig(mockExecuteFunctions);

			expect(config.options).toHaveLength(2);
			expect(config.options).toEqual(
				expect.arrayContaining([
					{
						label: 'Reject',
						style: 'secondary',
						url: 'http://localhost/waiting-webhook/nodeID?approved=false&signature=abc',
					},
					{
						label: 'Approve',
						style: 'primary',
						url: 'http://localhost/waiting-webhook/nodeID?approved=true&signature=abc',
					},
				]),
			);
		});
	});

	describe('createEmail', () => {
		beforeEach(() => {
			mockExecuteFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					sendTo: 'test@example.com',
					message: 'Test message',
					subject: 'Test subject',
					'approvalOptions.values': {
						approvalType: 'single',
						approveLabel: 'Approve',
						buttonApprovalStyle: 'primary',
					},
				};
				return params[parameterName];
			});

			mockExecuteFunctions.getSignedResumeUrl.mockReturnValue('http://localhost/testNodeId');
		});

		it('should create a valid email object', () => {
			const email = createEmail(mockExecuteFunctions);

			expect(email).toEqual({
				to: 'test@example.com',
				subject: 'Test subject',
				body: '',
				htmlBody: expect.stringContaining('Test message'),
			});
		});

		it('should throw NodeOperationError for invalid email address', () => {
			mockExecuteFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					sendTo: 'invalid@@email.com',
					message: 'Test message',
					subject: 'Test subject',
					'approvalOptions.values': {
						approvalType: 'single',
					},
				};
				return params[parameterName];
			});

			expect(() => createEmail(mockExecuteFunctions)).toThrow(NodeOperationError);
		});
	});

	describe('sendAndWaitWebhook', () => {
		it('should handle approved webhook', async () => {
			mockWebhookFunctions.getRequestObject.mockReturnValue({
				query: { approved: 'true' },
			} as any);

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result).toEqual({
				webhookResponse: expect.any(String),
				workflowData: [[{ json: { data: { approved: true } } }]],
			});
		});

		it('should handle disapproved webhook', async () => {
			mockWebhookFunctions.getRequestObject.mockReturnValue({
				query: { approved: 'false' },
			} as any);

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result).toEqual({
				webhookResponse: expect.any(String),
				workflowData: [[{ json: { data: { approved: false } } }]],
			});
		});

		it('should handle freeText GET webhook', async () => {
			const mockRender = jest.fn();
			const mockSetHeader = jest.fn();

			mockWebhookFunctions.getRequestObject.mockReturnValue({
				method: 'GET',
			} as any);

			mockWebhookFunctions.getResponseObject.mockReturnValue({
				render: mockRender,
				setHeader: mockSetHeader,
			} as any);

			mockWebhookFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					responseType: 'freeText',
					message: 'Test message',
					options: {},
				};
				return params[parameterName];
			});

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result).toEqual({
				noWebhookResponse: true,
			});

			expect(mockSetHeader).toHaveBeenCalledWith(
				'Content-Security-Policy',
				'sandbox allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols',
			);

			expect(mockRender).toHaveBeenCalledWith('form-trigger', {
				testRun: false,
				formTitle: '',
				formDescription: 'Test message',
				formDescriptionMetadata: 'Test message',
				formSubmittedHeader: 'Got it, thanks',
				formSubmittedText: 'This page can be closed now',
				n8nWebsiteLink: 'https://n8n.io/?utm_source=n8n-internal&utm_medium=form-trigger',
				formFields: [
					{
						id: 'field-0',
						errorId: 'error-field-0',
						label: 'Response',
						inputRequired: 'form-required',
						defaultValue: '',
						isTextarea: true,
					},
				],
				appendAttribution: true,
				buttonLabel: 'Submit',
			});
		});

		it('should handle freeText POST webhook', async () => {
			mockWebhookFunctions.getRequestObject.mockReturnValue({
				method: 'POST',
			} as any);

			mockWebhookFunctions.getBodyData.mockReturnValue({
				data: {
					'field-0': 'test value',
				},
			} as any);

			mockWebhookFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					responseType: 'freeText',
				};
				return params[parameterName];
			});

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result.workflowData).toEqual([[{ json: { data: { text: 'test value' } } }]]);
		});

		it('should handle customForm GET webhook', async () => {
			const mockRender = jest.fn();
			const mockSetHeader = jest.fn();

			mockWebhookFunctions.getRequestObject.mockReturnValue({
				method: 'GET',
			} as any);

			mockWebhookFunctions.getResponseObject.mockReturnValue({
				render: mockRender,
				setHeader: mockSetHeader,
			} as any);

			mockWebhookFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					responseType: 'customForm',
					message: 'Test message',
					defineForm: 'fields',
					'formFields.values': [{ label: 'Field 1', fieldType: 'text', requiredField: true }],
					options: {
						responseFormTitle: 'Test title',
						responseFormDescription: 'Test description',
						responseFormButtonLabel: 'Test button',
						responseFormCustomCss: 'body { background-color: red; }',
					},
				};
				return params[parameterName];
			});

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result).toEqual({
				noWebhookResponse: true,
			});

			expect(mockSetHeader).toHaveBeenCalledWith(
				'Content-Security-Policy',
				'sandbox allow-downloads allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-scripts allow-top-navigation-by-user-activation allow-top-navigation-to-custom-protocols',
			);

			expect(mockRender).toHaveBeenCalledWith('form-trigger', {
				testRun: false,
				formTitle: 'Test title',
				formDescription: 'Test description',
				formDescriptionMetadata: 'Test description',
				formSubmittedHeader: 'Got it, thanks',
				formSubmittedText: 'This page can be closed now',
				n8nWebsiteLink: 'https://n8n.io/?utm_source=n8n-internal&utm_medium=form-trigger',
				formFields: [
					{
						id: 'field-0',
						errorId: 'error-field-0',
						inputRequired: 'form-required',
						defaultValue: '',
						isInput: true,
						type: 'text',
					},
				],
				appendAttribution: true,
				buttonLabel: 'Test button',
				dangerousCustomCss: 'body { background-color: red; }',
			});
		});

		it('should resolve expressions in HTML fields for customForm GET webhook', async () => {
			const mockRender = jest.fn();
			const mockSetHeader = jest.fn();

			mockWebhookFunctions.getRequestObject.mockReturnValue({
				method: 'GET',
			} as any);

			mockWebhookFunctions.getResponseObject.mockReturnValue({
				render: mockRender,
				setHeader: mockSetHeader,
			} as any);

			// Mock evaluateExpression to resolve the expression
			mockWebhookFunctions.evaluateExpression.mockImplementation((expression) => {
				if (expression === '{{ $json.videoUrl }}') {
					return 'https://example.com/video.mp4';
				}
				return expression;
			});

			mockWebhookFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					responseType: 'customForm',
					message: 'Test message',
					defineForm: 'fields',
					'formFields.values': [
						{
							fieldLabel: 'Custom HTML',
							fieldType: 'html',
							// Use <source> tag inside <video> since sanitizeHtml allows src on source, not video
							html: '<video controls><source src="{{ $json.videoUrl }}" type="video/mp4" /></video>',
						},
					],
					options: {},
				};
				return params[parameterName];
			});

			await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(mockRender).toHaveBeenCalledWith(
				'form-trigger',
				expect.objectContaining({
					formFields: expect.arrayContaining([
						expect.objectContaining({
							html: '<video controls><source src="https://example.com/video.mp4" type="video/mp4"></source></video>',
						}),
					]),
				}),
			);
		});

		it('should handle customForm POST webhook', async () => {
			mockWebhookFunctions.getRequestObject.mockReturnValue({
				method: 'POST',
				contentType: 'multipart/form-data',
			} as any);
			mockWebhookFunctions.getNode.mockReturnValue({} as any);

			mockWebhookFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					responseType: 'customForm',
					defineForm: 'fields',
					'formFields.values': [
						{
							fieldLabel: 'test 1',
							fieldType: 'text',
						},
					],
				};
				return params[parameterName];
			});

			mockWebhookFunctions.getBodyData.mockReturnValue({
				data: {
					'field-0': 'test value',
				},
			} as any);

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result.workflowData).toEqual([[{ json: { data: { 'test 1': 'test value' } } }]]);
		});

		it('should return noWebhookResponse if method GET and user-agent is bot', async () => {
			mockWebhookFunctions.getRequestObject.mockReturnValue({
				method: 'GET',
				headers: {
					'user-agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
				},
				query: { approved: 'false' },
			} as any);

			const send = jest.fn();

			mockWebhookFunctions.getResponseObject.mockReturnValue({
				send,
			} as any);

			mockWebhookFunctions.getNodeParameter.mockImplementation((parameterName: string) => {
				const params: { [key: string]: any } = {
					responseType: 'approval',
				};
				return params[parameterName];
			});

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(send).toHaveBeenCalledWith('');
			expect(result).toEqual({ noWebhookResponse: true });
		});

		it('should return noWebhookResponse if user-agent is empty (Microsoft Preview Service)', async () => {
			const send = jest.fn();
			mockWebhookFunctions.getRequestObject.mockReturnValue({
				headers: {},
				query: { approved: 'true' },
			} as unknown as Request);
			mockWebhookFunctions.getResponseObject.mockReturnValue({
				send,
			} as unknown as Response);
			mockWebhookFunctions.getNodeParameter.mockImplementation(
				(parameterName: string, fallbackValue?: any) => {
					const params: Record<string, unknown> = { responseType: 'approval' };
					return params[parameterName] ?? fallbackValue;
				},
			);

			const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

			expect(result).toEqual({ noWebhookResponse: true });
			expect(send).toHaveBeenCalledWith('');
		});

		it.each([
			'SkypeSpaces/1.0',
			'Microsoft Teams/1.0',
			'SkypeUriPreview Preview/1.0',
			'Preview Service/1.0',
		])(
			'should return noWebhookResponse if user-agent contains %s (Microsoft Preview Service)',
			async (userAgent) => {
				const send = jest.fn();
				mockWebhookFunctions.getRequestObject.mockReturnValue({
					headers: { 'user-agent': userAgent },
					query: { approved: 'true' },
				} as unknown as Request);
				mockWebhookFunctions.getResponseObject.mockReturnValue({
					send,
				} as unknown as Response);
				mockWebhookFunctions.getNodeParameter.mockImplementation(
					(parameterName: string, fallbackValue?: any) => {
						const params: Record<string, unknown> = { responseType: 'approval' };
						return params[parameterName] ?? fallbackValue;
					},
				);

				const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

				expect(result).toEqual({ noWebhookResponse: true });
				expect(send).toHaveBeenCalledWith('');
			},
		);

		it.each([
			['freeText' as const, ''],
			['freeText' as const, 'SkypeUriPreview Preview/1.0'],
			['customForm' as const, ''],
			['customForm' as const, 'SkypeUriPreview Preview/1.0'],
		])(
			'should not block Microsoft Preview Service when responseType is %s (user-agent: %s)',
			async (responseType, userAgent) => {
				const mockRender = jest.fn();
				const mockSetHeader = jest.fn();
				mockWebhookFunctions.getRequestObject.mockReturnValue({
					method: 'GET',
					headers: { 'user-agent': userAgent },
					query: {},
				} as unknown as Request);
				mockWebhookFunctions.getResponseObject.mockReturnValue({
					render: mockRender,
					setHeader: mockSetHeader,
				} as unknown as Response);
				const formFieldParams: Record<string, unknown> =
					responseType === 'customForm'
						? {
								defineForm: 'fields',
								'formFields.values': [{ label: 'Field 1', fieldType: 'text', requiredField: true }],
							}
						: {};
				mockWebhookFunctions.getNodeParameter.mockImplementation(
					(parameterName: string, fallbackValue?: any) => {
						const params: Record<string, unknown> = {
							responseType,
							message: 'Test message',
							options: {},
							...formFieldParams,
						};
						return params[parameterName] ?? fallbackValue;
					},
				);

				const result = await sendAndWaitWebhook.call(mockWebhookFunctions);

				expect(result).toEqual({ noWebhookResponse: true });
				expect(mockRender).toHaveBeenCalled();
			},
		);
	});
});

describe('configureWaitTillDate', () => {
	let mockExecuteFunctions: MockProxy<IExecuteFunctions>;

	beforeEach(() => {
		mockExecuteFunctions = mock<IExecuteFunctions>();
	});

	afterEach(() => {
		jest.clearAllMocks();
	});

	it('should return WAIT_INDEFINITELY if limitWaitTime is empty', () => {
		mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({});
		const result = configureWaitTillDate(mockExecuteFunctions);
		expect(result).toBe(WAIT_INDEFINITELY);
	});

	it('should calculate future date correctly for afterTimeInterval with minutes', () => {
		const resumeAmount = 5;
		const resumeUnit = 'minutes';
		mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({
			limitType: 'afterTimeInterval',
			resumeAmount,
			resumeUnit,
		});

		const result = configureWaitTillDate(mockExecuteFunctions);
		const expectedDate = new Date(new Date().getTime() + 5 * 60 * 1000);
		expect(result.getTime()).toBeCloseTo(expectedDate.getTime(), -2); // Allowing 100ms difference
	});

	it('should calculate future date correctly for afterTimeInterval with hours', () => {
		const resumeAmount = 2;
		const resumeUnit = 'hours';
		mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({
			limitType: 'afterTimeInterval',
			resumeAmount,
			resumeUnit,
		});

		const result = configureWaitTillDate(mockExecuteFunctions);
		const expectedDate = new Date(new Date().getTime() + 2 * 60 * 60 * 1000);
		expect(result.getTime()).toBeCloseTo(expectedDate.getTime(), -2);
	});

	it('should calculate future date correctly for afterTimeInterval with days', () => {
		const resumeAmount = 1;
		const resumeUnit = 'days';
		mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({
			limitType: 'afterTimeInterval',
			resumeAmount,
			resumeUnit,
		});

		const result = configureWaitTillDate(mockExecuteFunctions);
		const expectedDate = new Date(new Date().getTime() + 1 * 24 * 60 * 60 * 1000);
		expect(result.getTime()).toBeCloseTo(expectedDate.getTime(), -2);
	});

	it('should return the specified maxDateAndTime for maxDateAndTime limitType', () => {
		const maxDateAndTime = '2023-12-31T23:59:59Z';
		mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({
			limitType: 'maxDateAndTime',
			maxDateAndTime,
		});

		const result = configureWaitTillDate(mockExecuteFunctions);
		expect(result).toEqual(new Date(maxDateAndTime));
	});

	it('should throw NodeOperationError for invalid maxDateAndTime format', () => {
		const invalidMaxDateAndTime = 'invalid-date';
		mockExecuteFunctions.getNodeParameter.mockReturnValue({
			limitType: 'maxDateAndTime',
			maxDateAndTime: invalidMaxDateAndTime,
		});

		expect(() => configureWaitTillDate(mockExecuteFunctions)).toThrow(NodeOperationError);
		expect(() => configureWaitTillDate(mockExecuteFunctions)).toThrow(
			'Could not configure Limit Wait Time',
		);
	});

	it('should throw NodeOperationError for invalid resumeAmount or resumeUnit', () => {
		mockExecuteFunctions.getNodeParameter.mockReturnValue({
			limitType: 'afterTimeInterval',
			resumeAmount: 'invalid',
			resumeUnit: 'minutes',
		});

		expect(() => configureWaitTillDate(mockExecuteFunctions)).toThrow(NodeOperationError);
		expect(() => configureWaitTillDate(mockExecuteFunctions)).toThrow(
			'Could not configure Limit Wait Time',
		);
	});

	it('should return WAIT_INDEFINITELY when limitWaitTime is false', () => {
		mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(false);
		const result = configureWaitTillDate(mockExecuteFunctions, 'root');
		expect(result).toBe(WAIT_INDEFINITELY);
	});

	it('should calculate minutes correctly in root location', () => {
		mockExecuteFunctions.getNodeParameter
			.mockReturnValueOnce(true) // limitWaitTime
			.mockReturnValueOnce('afterTimeInterval') // limitType
			.mockReturnValueOnce(15) // resumeAmount
			.mockReturnValueOnce('minutes'); // resumeUnit

		const result = configureWaitTillDate(mockExecuteFunctions, 'root');
		const expectedDate = new Date(new Date().getTime() + 15 * 60 * 1000);
		expect(result.getTime()).toBeCloseTo(expectedDate.getTime(), -2);
	});

	it('should calculate hours correctly in root location', () => {
		mockExecuteFunctions.getNodeParameter
			.mockReturnValueOnce(true)
			.mockReturnValueOnce('afterTimeInterval')
			.mockReturnValueOnce(3)
			.mockReturnValueOnce('hours');

		const result = configureWaitTillDate(mockExecuteFunctions, 'root');
		const expectedDate = new Date(new Date().getTime() + 3 * 60 * 60 * 1000);
		expect(result.getTime()).toBeCloseTo(expectedDate.getTime(), -2);
	});

	it('should calculate days correctly in root location', () => {
		mockExecuteFunctions.getNodeParameter
			.mockReturnValueOnce(true)
			.mockReturnValueOnce('afterTimeInterval')
			.mockReturnValueOnce(5)
			.mockReturnValueOnce('days');

		const result = configureWaitTillDate(mockExecuteFunctions, 'root');
		const expectedDate = new Date(new Date().getTime() + 5 * 24 * 60 * 60 * 1000);
		expect(result.getTime()).toBeCloseTo(expectedDate.getTime(), -2);
	});

	it('should handle maxDateAndTime in root location', () => {
		const maxDateAndTime = '2024-12-31T23:59:59Z';
		mockExecuteFunctions.getNodeParameter
			.mockReturnValueOnce(true)
			.mockReturnValueOnce('maxDateAndTime')
			.mockReturnValueOnce(maxDateAndTime);

		const result = configureWaitTillDate(mockExecuteFunctions, 'root');
		expect(result).toEqual(new Date(maxDateAndTime));
	});

	it('should throw error for invalid date in root location', () => {
		mockExecuteFunctions.getNodeParameter
			.mockReturnValueOnce(true)
			.mockReturnValueOnce('maxDateAndTime')
			.mockReturnValueOnce('not-a-valid-date');

		expect(() => configureWaitTillDate(mockExecuteFunctions, 'root')).toThrow(NodeOperationError);
	});

	it('should throw error for invalid resumeAmount in root location', () => {
		mockExecuteFunctions.getNodeParameter
			.mockReturnValueOnce(true)
			.mockReturnValueOnce('afterTimeInterval')
			.mockReturnValueOnce('not-a-number')
			.mockReturnValueOnce('minutes');

		expect(() => configureWaitTillDate(mockExecuteFunctions, 'root')).toThrow(NodeOperationError);
	});
});
