From 948aced4a1ed3539233dc1ac6168f259a57a4528 Mon Sep 17 00:00:00 2001 From: Michael Kret Date: Mon, 6 Jan 2025 10:12:42 +0200 Subject: [PATCH] review update --- .../Google/Calendar/CalendarDescription.ts | 10 ++- .../nodes/Google/Calendar/EventDescription.ts | 10 ++- .../nodes/Google/Calendar/GenericFunctions.ts | 6 ++ .../Google/Calendar/GoogleCalendar.node.ts | 12 ++- .../test/node/calendar.availability.test.ts | 74 ------------------- .../Calendar/test/node/event.create.test.ts | 73 ------------------ 6 files changed, 23 insertions(+), 162 deletions(-) delete mode 100644 packages/nodes-base/nodes/Google/Calendar/test/node/calendar.availability.test.ts delete mode 100644 packages/nodes-base/nodes/Google/Calendar/test/node/event.create.test.ts diff --git a/packages/nodes-base/nodes/Google/Calendar/CalendarDescription.ts b/packages/nodes-base/nodes/Google/Calendar/CalendarDescription.ts index f172f976c8..d768222003 100644 --- a/packages/nodes-base/nodes/Google/Calendar/CalendarDescription.ts +++ b/packages/nodes-base/nodes/Google/Calendar/CalendarDescription.ts @@ -86,8 +86,9 @@ export const calendarFields: INodeProperties[] = [ resource: ['calendar'], }, }, - default: '', - description: 'Start of the interval, if not specified will default to now', + default: '={{ $now.toISO() }}', + description: + 'Start of the interval, use expression to set a date, or switch to fixed mode to choose date from widget', }, { displayName: 'End Time', @@ -100,8 +101,9 @@ export const calendarFields: INodeProperties[] = [ resource: ['calendar'], }, }, - default: '', - description: 'End of the interval, if not specified will default to Start Time plus 1 hour', + default: "={{ $now.plus(1, 'hour').toISO() }}", + description: + 'End of the interval, use expression to set a date, or switch to fixed mode to choose date from widget', }, { displayName: 'Options', diff --git a/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts b/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts index d32e55cdf4..65e92bf909 100644 --- a/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts +++ b/packages/nodes-base/nodes/Google/Calendar/EventDescription.ts @@ -114,8 +114,9 @@ export const eventFields: INodeProperties[] = [ resource: ['event'], }, }, - default: '', - description: 'Start time of the event, if not specified will default to now', + default: '={{ $now.toISO() }}', + description: + 'Start time of the event, use expression to set a date, or switch to fixed mode to choose date from widget', }, { displayName: 'End', @@ -128,8 +129,9 @@ export const eventFields: INodeProperties[] = [ resource: ['event'], }, }, - default: '', - description: 'End time of the event, if not specified will default to start time plus 1 hour', + default: "={{ $now.plus(1, 'hour').toISO() }}", + description: + 'End time of the event, use expression to set a date, or switch to fixed mode to choose date from widget', }, { displayName: 'Use Default Reminders', diff --git a/packages/nodes-base/nodes/Google/Calendar/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Calendar/GenericFunctions.ts index f440efaee9..2ca092d4f8 100644 --- a/packages/nodes-base/nodes/Google/Calendar/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Calendar/GenericFunctions.ts @@ -1,3 +1,4 @@ +import { DateTime } from 'luxon'; import moment from 'moment-timezone'; import type { IDataObject, @@ -193,3 +194,8 @@ export function addTimezoneToDate(date: string, timezone: string) { if (hasTimezone(date)) return date; return moment.tz(date, timezone).utc().format(); } + +export function dateTimeToIso(date: T): string { + if (date instanceof DateTime) return date.toISO(); + return date as string; +} diff --git a/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts b/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts index ef1c5ad689..edc4498a89 100644 --- a/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts +++ b/packages/nodes-base/nodes/Google/Calendar/GoogleCalendar.node.ts @@ -18,6 +18,7 @@ import type { IEvent } from './EventInterface'; import { addNextOccurrence, addTimezoneToDate, + dateTimeToIso, encodeURIComponentOnce, getCalendars, getTimezones, @@ -148,10 +149,8 @@ export class GoogleCalendar implements INodeType { const calendarId = decodeURIComponent( this.getNodeParameter('calendar', i, '', { extractValue: true }) as string, ); - const timeMin = (this.getNodeParameter('timeMin', i) as string) || moment().format(); - const timeMax = - (this.getNodeParameter('timeMax', i) as string) || - moment(timeMin).add(1, 'hour').format(); + const timeMin = dateTimeToIso(this.getNodeParameter('timeMin', i)); + const timeMax = dateTimeToIso(this.getNodeParameter('timeMax', i)); const options = this.getNodeParameter('options', i); const outputFormat = options.outputFormat || 'availability'; const tz = this.getNodeParameter('options.timezone', i, '', { @@ -202,9 +201,8 @@ export class GoogleCalendar implements INodeType { const calendarId = encodeURIComponentOnce( this.getNodeParameter('calendar', i, '', { extractValue: true }) as string, ); - const start = (this.getNodeParameter('start', i) as string) || moment().format(); - const end = - (this.getNodeParameter('end', i) as string) || moment(start).add(1, 'hour').format(); + const start = dateTimeToIso(this.getNodeParameter('start', i)); + const end = dateTimeToIso(this.getNodeParameter('end', i)); const useDefaultReminders = this.getNodeParameter('useDefaultReminders', i) as boolean; const additionalFields = this.getNodeParameter('additionalFields', i); diff --git a/packages/nodes-base/nodes/Google/Calendar/test/node/calendar.availability.test.ts b/packages/nodes-base/nodes/Google/Calendar/test/node/calendar.availability.test.ts deleted file mode 100644 index 8e75ef2c7a..0000000000 --- a/packages/nodes-base/nodes/Google/Calendar/test/node/calendar.availability.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { MockProxy } from 'jest-mock-extended'; -import { mock } from 'jest-mock-extended'; -import type { INode, IExecuteFunctions } from 'n8n-workflow'; - -import * as genericFunctions from '../../GenericFunctions'; -import { GoogleCalendar } from '../../GoogleCalendar.node'; - -let googleApiRequestArgs: any[] = []; -const CALENDAR_ID = 'myCalendar'; - -jest.mock('../../GenericFunctions', () => ({ - getTimezones: jest.fn(), - googleApiRequest: jest.fn(async (...args: any[]) => { - googleApiRequestArgs = args; - return { calendars: { [CALENDAR_ID]: { busy: [] } } }; - }), - googleApiRequestAllItems: jest.fn(), - addTimezoneToDate: jest.fn(), - addNextOccurrence: jest.fn(), - encodeURIComponentOnce: jest.fn(), -})); - -describe('RespondToWebhook Node', () => { - let googleCalendar: GoogleCalendar; - let mockExecuteFunctions: MockProxy; - - beforeEach(() => { - googleCalendar = new GoogleCalendar(); - mockExecuteFunctions = mock({ - getInputData: jest.fn(), - getNode: jest.fn(), - getNodeParameter: jest.fn(), - getTimezone: jest.fn(), - helpers: { - constructExecutionMetaData: jest.fn().mockReturnValue([]), - }, - }); - }); - - afterEach(() => { - googleApiRequestArgs = []; - jest.clearAllMocks(); - }); - - describe('Google Calendar > Calendar > Availability', () => { - it('should not have invalid timeMin and timeMax date', async () => { - //pre loop setup - mockExecuteFunctions.getInputData.mockReturnValue([{ json: {} }]); - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('calendar'); - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('availability'); - mockExecuteFunctions.getTimezone.mockReturnValueOnce('Europe/Berlin'); - mockExecuteFunctions.getNode.mockReturnValue(mock({ typeVersion: 1.1 })); - //operation - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(CALENDAR_ID); // calendar - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(''); // timeMin, not set - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(''); // timeMax, not set - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({}); // options - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(''); // options.timezone, default to timezone - - await googleCalendar.execute.call(mockExecuteFunctions); - - expect(genericFunctions.googleApiRequest).toHaveBeenCalledTimes(1); - - const body = googleApiRequestArgs[2] as { - timeMin: string; - timeMax: string; - }; - - expect(body).toBeDefined(); - expect(body.timeMin).not.toEqual('Invalid Date'); - expect(body.timeMax).not.toEqual('Invalid Date'); - }); - }); -}); diff --git a/packages/nodes-base/nodes/Google/Calendar/test/node/event.create.test.ts b/packages/nodes-base/nodes/Google/Calendar/test/node/event.create.test.ts deleted file mode 100644 index 4641e75182..0000000000 --- a/packages/nodes-base/nodes/Google/Calendar/test/node/event.create.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { MockProxy } from 'jest-mock-extended'; -import { mock } from 'jest-mock-extended'; -import type { INode, IExecuteFunctions } from 'n8n-workflow'; - -import * as genericFunctions from '../../GenericFunctions'; -import { GoogleCalendar } from '../../GoogleCalendar.node'; - -let googleApiRequestArgs: any[] = []; - -jest.mock('../../GenericFunctions', () => ({ - getTimezones: jest.fn(), - googleApiRequest: jest.fn(async (...args: any[]) => { - googleApiRequestArgs = args; - return {}; - }), - googleApiRequestAllItems: jest.fn(), - addTimezoneToDate: jest.fn(), - addNextOccurrence: jest.fn(), - encodeURIComponentOnce: jest.fn(), -})); - -describe('RespondToWebhook Node', () => { - let googleCalendar: GoogleCalendar; - let mockExecuteFunctions: MockProxy; - - beforeEach(() => { - googleCalendar = new GoogleCalendar(); - mockExecuteFunctions = mock({ - getInputData: jest.fn(), - getNode: jest.fn(), - getNodeParameter: jest.fn(), - getTimezone: jest.fn(), - helpers: { - constructExecutionMetaData: jest.fn().mockReturnValue([]), - }, - }); - }); - - afterEach(() => { - googleApiRequestArgs = []; - jest.clearAllMocks(); - }); - - describe('Google Calendar > Event > Create', () => { - it('should not have invalid start and end date', async () => { - //pre loop setup - mockExecuteFunctions.getInputData.mockReturnValue([{ json: {} }]); - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('event'); - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('create'); - mockExecuteFunctions.getTimezone.mockReturnValueOnce('Europe/Berlin'); - mockExecuteFunctions.getNode.mockReturnValue(mock({ typeVersion: 1.1 })); - //operation - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce('myCalendar'); - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(''); // start, not set - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(''); // end, not set - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce(true); // useDefaultReminders - mockExecuteFunctions.getNodeParameter.mockReturnValueOnce({}); // additionalFields - - await googleCalendar.execute.call(mockExecuteFunctions); - - expect(genericFunctions.googleApiRequest).toHaveBeenCalledTimes(1); - - const body = googleApiRequestArgs[2] as { - start: { dateTime: string }; - end: { dateTime: string }; - }; - - expect(body).toBeDefined(); - expect(body.start.dateTime).not.toEqual('Invalid Date'); - expect(body.end.dateTime).not.toEqual('Invalid Date'); - }); - }); -});