From b4e6bc0927c2bdb7ac4800ae60f3d87d99266782 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 21 May 2026 19:39:11 -0300 Subject: [PATCH 1/8] Scheduler - Migrate popup state test to isolated environment --- .../__mock__/create_appointment_popup.ts | 46 ++++++++++++++----- .../appointment_popup.integration.test.ts | 14 ------ .../appointment_popup.test.ts | 14 ++++++ 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts index 748721be9376..f83c503b2246 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts @@ -69,6 +69,11 @@ interface CreateAppointmentPopupOptions { updateAppointment?: jest.Mock; } +interface ReopenOptions { + appointmentData?: Record; + firstDayOfWeek?: number; +} + interface CreateAppointmentPopupResult { container: HTMLDivElement; popup: AppointmentPopup; @@ -80,6 +85,7 @@ interface CreateAppointmentPopupResult { focus: jest.Mock; onSave: jest.Mock<(appointment: Record) => PromiseLike>; }; + reopen: (opts?: ReopenOptions) => Promise<{ POM: PopupModel }>; dispose: () => void; } @@ -163,21 +169,36 @@ export const createAppointmentPopup = async ( const title = options.title ?? 'New Appointment'; const readOnly = options.readOnly ?? false; - popup.show(appointmentData, { onSave, title, readOnly }); - await new Promise(process.nextTick); + const overlaySelector = `.dx-overlay-wrapper.${APPOINTMENT_POPUP_CLASS}`; + + const showAndQuery = async ( + data: Record, + ): Promise => { + popup.show(data, { onSave, title, readOnly }); + await new Promise(process.nextTick); - const selector = `.dx-overlay-wrapper.${APPOINTMENT_POPUP_CLASS}`; - const overlayWrapper = document.querySelector( - selector, - ) as HTMLDivElement; + const wrapper = document.querySelector(overlaySelector) as HTMLDivElement; - if (!overlayWrapper) { - throw new Error( - 'AppointmentPopup overlay wrapper not found in DOM', - ); - } + if (!wrapper) { + throw new Error('AppointmentPopup overlay wrapper not found in DOM'); + } - const POM = new PopupModel(overlayWrapper); + return new PopupModel(wrapper); + }; + + const POM = await showAndQuery(appointmentData); + + const reopen = async ( + reopenOpts: ReopenOptions = {}, + ): Promise<{ POM: PopupModel }> => { + if (reopenOpts.firstDayOfWeek !== undefined) { + formConfig.firstDayOfWeek = reopenOpts.firstDayOfWeek as DayOfWeek; + } + + const data = reopenOpts.appointmentData ?? appointmentData; + + return { POM: await showAndQuery(data) }; + }; const dispose = (): void => { popup.dispose(); @@ -197,6 +218,7 @@ export const createAppointmentPopup = async ( focus, onSave, }, + reopen, dispose, }; }; diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts index 8278e2c5afd0..73589af95e16 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts @@ -391,20 +391,6 @@ describe('Appointment Form', () => { }); describe('State', () => { - it('should create a new form instance on each popup opening', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - const firstFormInstance = POM.popup.dxForm; - - POM.popup.cancelButton.click(); - - scheduler.showAppointmentPopup(commonAppointment); - const secondFormInstance = POM.popup.dxForm; - - expect(secondFormInstance).not.toBe(firstFormInstance); - }); - it('should have correct editor values when opening for empty date cell - 1', async () => { const { POM } = await createScheduler({ ...getDefaultConfig(), diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index 8b9f4bfd9798..ac0baaf54095 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -149,4 +149,18 @@ describe('Isolated AppointmentPopup environment', () => { expect.objectContaining({ text: 'Single occurrence' }), ); }); + + describe('State', () => { + it('should create a new dxForm instance on each popup opening', async () => { + const { POM, reopen } = await createAppointmentPopup(); + const firstFormInstance = POM.dxForm; + + POM.cancelButton.click(); + + const { POM: POM2 } = await reopen(); + const secondFormInstance = POM2.dxForm; + + expect(secondFormInstance).not.toBe(firstFormInstance); + }); + }); }); From 426d4e3ab3313a3ad112ea59179a7130cfeae0b9 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 21 May 2026 19:45:08 -0300 Subject: [PATCH 2/8] Scheduler - Migrate popup allDay switch tests to isolated environment --- .../appointment_popup.integration.test.ts | 86 ------------------- .../appointment_popup.test.ts | 85 ++++++++++++++++++ 2 files changed, 85 insertions(+), 86 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts index 73589af95e16..a4b8b2078094 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts @@ -764,58 +764,6 @@ describe('Appointment Form', () => { }); describe('allDay switch', () => { - it('should be turned on when opening allDay appointment', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(allDayAppointment); - - expect(POM.popup.getInputValue('allDayEditor')).toBe('true'); - }); - - it('should be turned off when opening non-allDay appointment', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - - expect(POM.popup.getInputValue('allDayEditor')).toBe('false'); - }); - - it('should hide time editors when switched on', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - - expect(POM.popup.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('startTimeEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('endTimeEditor')).toBeTruthy(); - - POM.popup.getInput('allDayEditor').click(); - - expect(POM.popup.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('startTimeEditor')).toBeFalsy(); - expect(POM.popup.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('endTimeEditor')).toBeFalsy(); - }); - - it('should show time editors when switched off', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(allDayAppointment); - - expect(POM.popup.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('startTimeEditor')).toBeFalsy(); - expect(POM.popup.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('endTimeEditor')).toBeFalsy(); - - POM.popup.getInput('allDayEditor').click(); - - expect(POM.popup.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('startTimeEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.popup.isInputVisible('endTimeEditor')).toBeTruthy(); - }); - it('should set correct dates when switching on then off in day view', async () => { const { scheduler, POM } = await createScheduler({ ...getDefaultConfig(), @@ -833,23 +781,6 @@ describe('Appointment Form', () => { expect(POM.popup.getInputValue('endTimeEditor')).toBe('9:30 AM'); }); - it('should set correct dates when switching off then on in day view', async () => { - const { scheduler, POM } = await createScheduler({ - ...getDefaultConfig(), - currentView: 'day', - }); - - scheduler.showAppointmentPopup(allDayAppointment); - - POM.popup.getInput('allDayEditor').click(); - POM.popup.getInput('allDayEditor').click(); - - expect(POM.popup.getInputValue('startDateEditor')).toBe('5/1/2017'); - expect(POM.popup.isInputVisible('startTimeEditor')).toBeFalsy(); - expect(POM.popup.getInputValue('endDateEditor')).toBe('5/1/2017'); - expect(POM.popup.isInputVisible('endTimeEditor')).toBeFalsy(); - }); - it('should set correct dates when switching on then off in month view', async () => { const { scheduler, POM } = await createScheduler({ ...getDefaultConfig(), @@ -866,23 +797,6 @@ describe('Appointment Form', () => { expect(POM.popup.getInputValue('endDateEditor')).toBe('5/10/2017'); expect(POM.popup.getInputValue('endTimeEditor')).toBe('12:00 AM'); }); - - it('should set correct dates when switching off then on in month view', async () => { - const { scheduler, POM } = await createScheduler({ - ...getDefaultConfig(), - currentView: 'month', - }); - - scheduler.showAppointmentPopup(allDayAppointment); - - POM.popup.getInput('allDayEditor').click(); - POM.popup.getInput('allDayEditor').click(); - - expect(POM.popup.getInputValue('startDateEditor')).toBe('5/1/2017'); - expect(POM.popup.isInputVisible('startTimeEditor')).toBeFalsy(); - expect(POM.popup.getInputValue('endDateEditor')).toBe('5/1/2017'); - expect(POM.popup.isInputVisible('endTimeEditor')).toBeFalsy(); - }); }); describe('Timezone Editors', () => { diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index ac0baaf54095..a70e94dd98b6 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -163,4 +163,89 @@ describe('Isolated AppointmentPopup environment', () => { expect(secondFormInstance).not.toBe(firstFormInstance); }); }); + + describe('allDay switch', () => { + const commonAppointment = { + text: 'common-app', + startDate: new Date(2017, 4, 9, 9, 30), + endDate: new Date(2017, 4, 9, 11), + }; + const allDayAppointment = { + text: 'all-day-app', + startDate: new Date(2017, 4, 1), + endDate: new Date(2017, 4, 1), + allDay: true, + }; + + it('should be turned on when opening allDay appointment', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: allDayAppointment }); + + expect(POM.getInputValue('allDayEditor')).toBe('true'); + }); + + it('should be turned off when opening non-allDay appointment', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment }); + + expect(POM.getInputValue('allDayEditor')).toBe('false'); + }); + + it('should hide time editors when switched on', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment }); + + expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('startTimeEditor')).toBeTruthy(); + expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('endTimeEditor')).toBeTruthy(); + + POM.getInput('allDayEditor').click(); + + expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('startTimeEditor')).toBeFalsy(); + expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('endTimeEditor')).toBeFalsy(); + }); + + it('should show time editors when switched off', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: allDayAppointment }); + + expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('startTimeEditor')).toBeFalsy(); + expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('endTimeEditor')).toBeFalsy(); + + POM.getInput('allDayEditor').click(); + + expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('startTimeEditor')).toBeTruthy(); + expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); + expect(POM.isInputVisible('endTimeEditor')).toBeTruthy(); + }); + + it('should reset start to startDayHour and end via getCalculatedEndDate when switched off', async () => { + const { POM } = await createAppointmentPopup({ + appointmentData: commonAppointment, + startDayHour: 9, + }); + + POM.getInput('allDayEditor').click(); + POM.getInput('allDayEditor').click(); + + expect(POM.getInputValue('startDateEditor')).toBe('5/9/2017'); + expect(POM.getInputValue('startTimeEditor')).toBe('9:00 AM'); + expect(POM.getInputValue('endDateEditor')).toBe('5/9/2017'); + expect(POM.getInputValue('endTimeEditor')).toBe('10:00 AM'); + }); + + it('should reset to date-only values when switched on after toggling off', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: allDayAppointment }); + + POM.getInput('allDayEditor').click(); + POM.getInput('allDayEditor').click(); + + expect(POM.getInputValue('startDateEditor')).toBe('5/1/2017'); + expect(POM.isInputVisible('startTimeEditor')).toBeFalsy(); + expect(POM.getInputValue('endDateEditor')).toBe('5/1/2017'); + expect(POM.isInputVisible('endTimeEditor')).toBeFalsy(); + }); + }); }); From 64e20ebc27f2bfafaec553ff848e40d7cb3559ed Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 21 May 2026 19:52:50 -0300 Subject: [PATCH 3/8] Scheduler - Migrate popup startDate and endDate editor tests to isolated environment --- .../__mock__/create_appointment_popup.ts | 5 +- .../appointment_popup.integration.test.ts | 123 ------------------ .../appointment_popup.test.ts | 88 +++++++++++++ 3 files changed, 91 insertions(+), 125 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts index f83c503b2246..75a6ef203bcc 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts @@ -4,12 +4,12 @@ import $ from '@js/core/renderer'; // eslint-disable-next-line devextreme-custom/no-deferred import { Deferred } from '@js/core/utils/deferred'; -import { mockTimeZoneCalculator } from '../../__mock__/timezone_calculator.mock'; import { AppointmentForm } from '../../appointment_popup/form'; import { APPOINTMENT_POPUP_CLASS, AppointmentPopup, } from '../../appointment_popup/popup'; +import { createTimeZoneCalculator } from '../../r1/timezone_calculator/utils'; import { AppointmentDataAccessor, } from '../../utils/data_accessor/appointment_data_accessor'; @@ -61,6 +61,7 @@ interface CreateAppointmentPopupOptions { editing?: Record; firstDayOfWeek?: number; startDayHour?: number; + timeZone?: string; onAppointmentFormOpening?: (...args: unknown[]) => void; onSave?: jest.Mock<(appointment: Record) => PromiseLike>; title?: string; @@ -110,7 +111,7 @@ export const createAppointmentPopup = async ( const dataAccessors = new AppointmentDataAccessor(DEFAULT_FIELDS, false); const resourceManager = new ResourceManager([]); - const timeZoneCalculator = mockTimeZoneCalculator; + const timeZoneCalculator = createTimeZoneCalculator(options.timeZone ?? ''); const editing = { ...DEFAULT_EDITING, ...options.editing }; const addAppointment = options.addAppointment diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts index a4b8b2078094..92b028a88664 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts @@ -513,129 +513,6 @@ describe('Appointment Form', () => { expect(POM.popup.getInputValue(timeEditorName)).not.toBeNull(); }); - - it('should update endDate when startDate is changed to a value greater than endDate', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - - POM.popup.setInputValue('startDateEditor', new Date(2017, 4, 10)); - - expect(POM.popup.getInputValue('startTimeEditor')).toEqual('9:30 AM'); - expect(POM.popup.getInputValue('endDateEditor')).toEqual('5/10/2017'); - expect(POM.popup.getInputValue('endTimeEditor')).toEqual('11:00 AM'); - }); - - it('should update endDate when startTime is changed to a value greater than endDate time', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - - POM.popup.setInputValue('startTimeEditor', new Date(2017, 4, 9, 12)); - - expect(POM.popup.getInputValue('startDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('endDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('endTimeEditor')).toEqual('1:30 PM'); - }); - - it('should update startDate when endDate is changed to a value less than startDate', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - - POM.popup.setInputValue('endDateEditor', new Date(2017, 4, 8)); - - expect(POM.popup.getInputValue('startDateEditor')).toEqual('5/8/2017'); - expect(POM.popup.getInputValue('startTimeEditor')).toEqual('9:30 AM'); - expect(POM.popup.getInputValue('endTimeEditor')).toEqual('11:00 AM'); - }); - - it('should update startDate when endTime is changed to a value less than startDate time', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - POM.popup.setInputValue('endTimeEditor', new Date(2017, 4, 9, 9, 0)); - - expect(POM.popup.getInputValue('startDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('startTimeEditor')).toEqual('7:30 AM'); - expect(POM.popup.getInputValue('endDateEditor')).toEqual('5/9/2017'); - }); - - it('should not update endDate when startDate is changed to a value less than endDate', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - POM.popup.setInputValue('startDateEditor', new Date(2017, 4, 8)); - - expect(POM.popup.getInputValue('startTimeEditor')).toEqual('9:30 AM'); - expect(POM.popup.getInputValue('endDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('endTimeEditor')).toEqual('11:00 AM'); - }); - - it('should not update endDate when startTime is changed to a value less than endDate time', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - POM.popup.setInputValue('startTimeEditor', new Date(2017, 4, 9, 10, 0)); - - expect(POM.popup.getInputValue('startDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('endDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('endTimeEditor')).toEqual('11:00 AM'); - }); - - it('should not update startDate when endDate is changed to a value greater than startDate', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - POM.popup.setInputValue('endDateEditor', new Date(2017, 4, 10)); - - expect(POM.popup.getInputValue('startDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('startTimeEditor')).toEqual('9:30 AM'); - expect(POM.popup.getInputValue('endTimeEditor')).toEqual('11:00 AM'); - }); - - it('should not update startDate when endTime is changed to a value greater than startDate time', async () => { - const { scheduler, POM } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup({ - text: 'test app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }); - POM.popup.setInputValue('endTimeEditor', new Date(2017, 4, 9, 12)); - - expect(POM.popup.getInputValue('startDateEditor')).toEqual('5/9/2017'); - expect(POM.popup.getInputValue('startTimeEditor')).toEqual('9:30 AM'); - expect(POM.popup.getInputValue('endDateEditor')).toEqual('5/9/2017'); - }); }); describe.each([ diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index a70e94dd98b6..8eb580dbaeb0 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -248,4 +248,92 @@ describe('Isolated AppointmentPopup environment', () => { expect(POM.isInputVisible('endTimeEditor')).toBeFalsy(); }); }); + + describe('startDate/endDate editors behavior', () => { + const testAppointment = { + text: 'test app', + startDate: new Date(2017, 4, 9, 9, 30), + endDate: new Date(2017, 4, 9, 11), + }; + + it('should update endDate when startDate is changed to a value greater than endDate', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('startDateEditor', new Date(2017, 4, 10)); + + expect(POM.getInputValue('startTimeEditor')).toEqual('9:30 AM'); + expect(POM.getInputValue('endDateEditor')).toEqual('5/10/2017'); + expect(POM.getInputValue('endTimeEditor')).toEqual('11:00 AM'); + }); + + it('should update endDate when startTime is changed to a value greater than endDate time', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('startTimeEditor', new Date(2017, 4, 9, 12)); + + expect(POM.getInputValue('startDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('endTimeEditor')).toEqual('1:30 PM'); + }); + + it('should update startDate when endDate is changed to a value less than startDate', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('endDateEditor', new Date(2017, 4, 8)); + + expect(POM.getInputValue('startDateEditor')).toEqual('5/8/2017'); + expect(POM.getInputValue('startTimeEditor')).toEqual('9:30 AM'); + expect(POM.getInputValue('endTimeEditor')).toEqual('11:00 AM'); + }); + + it('should update startDate when endTime is changed to a value less than startDate time', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('endTimeEditor', new Date(2017, 4, 9, 9, 0)); + + expect(POM.getInputValue('startDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('startTimeEditor')).toEqual('7:30 AM'); + expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); + }); + + it('should not update endDate when startDate is changed to a value less than endDate', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('startDateEditor', new Date(2017, 4, 8)); + + expect(POM.getInputValue('startTimeEditor')).toEqual('9:30 AM'); + expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('endTimeEditor')).toEqual('11:00 AM'); + }); + + it('should not update endDate when startTime is changed to a value less than endDate time', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('startTimeEditor', new Date(2017, 4, 9, 10, 0)); + + expect(POM.getInputValue('startDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('endTimeEditor')).toEqual('11:00 AM'); + }); + + it('should not update startDate when endDate is changed to a value greater than startDate', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('endDateEditor', new Date(2017, 4, 10)); + + expect(POM.getInputValue('startDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('startTimeEditor')).toEqual('9:30 AM'); + expect(POM.getInputValue('endTimeEditor')).toEqual('11:00 AM'); + }); + + it('should not update startDate when endTime is changed to a value greater than startDate time', async () => { + const { POM } = await createAppointmentPopup({ appointmentData: testAppointment }); + + POM.setInputValue('endTimeEditor', new Date(2017, 4, 9, 12)); + + expect(POM.getInputValue('startDateEditor')).toEqual('5/9/2017'); + expect(POM.getInputValue('startTimeEditor')).toEqual('9:30 AM'); + expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); + }); + }); }); From ac7bf1867be16b4605ce75c5752173d2bf358310 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 21 May 2026 19:55:57 -0300 Subject: [PATCH 4/8] Scheduler - Migrate popup firstDayOfWeek tests to isolated environment --- .../appointment_popup.integration.test.ts | 75 ------------------- .../appointment_popup.test.ts | 75 +++++++++++++++++++ 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts index 92b028a88664..1fed4785105a 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.integration.test.ts @@ -1504,81 +1504,6 @@ describe('Appointment Form', () => { jest.restoreAllMocks(); }); - it('should apply firstDayOfWeek to week day buttons', async () => { - const { POM, scheduler } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - POM.popup.selectRepeatValue('weekly'); - - const dayButtonsMonday = $(POM.popup.recurrenceWeekDayButtons).find('.dx-button'); - expect(dayButtonsMonday.text()).toBe('MTWTFSS'); - - scheduler.hideAppointmentPopup(); - scheduler.option('firstDayOfWeek', 0); - - scheduler.showAppointmentPopup(commonAppointment); - POM.popup.selectRepeatValue('weekly'); - - const dayButtonsSunday = $(POM.popup.recurrenceWeekDayButtons).find('.dx-button'); - expect(dayButtonsSunday.text()).toBe('SMTWTFS'); - }); - - it('should apply firstDayOfWeek to recurrence form startDate calendar', async () => { - const { POM, scheduler } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - POM.popup.selectRepeatValue('weekly'); - - const recurrenceStartDateEditor = POM.popup.dxForm.getEditor('recurrenceStartDateEditor'); - expect(recurrenceStartDateEditor).toBeDefined(); - expect(recurrenceStartDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); - - scheduler.option('firstDayOfWeek', 0); - - scheduler.showAppointmentPopup(commonAppointment); - POM.popup.selectRepeatValue('weekly'); - - const recurrenceStartDateEditorAfter = POM.popup.dxForm.getEditor('recurrenceStartDateEditor'); - expect(recurrenceStartDateEditorAfter).toBeDefined(); - expect(recurrenceStartDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); - }); - - it('should apply firstDayOfWeek to startDate calendar', async () => { - const { POM, scheduler } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - - const startDateEditor = POM.popup.dxForm.getEditor('startDateEditor'); - expect(startDateEditor).toBeDefined(); - expect(startDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); - - scheduler.option('firstDayOfWeek', 0); - - scheduler.showAppointmentPopup(commonAppointment); - - const startDateEditorAfter = POM.popup.dxForm.getEditor('startDateEditor'); - expect(startDateEditorAfter).toBeDefined(); - expect(startDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); - }); - - it('should apply firstDayOfWeek to endDate calendar', async () => { - const { POM, scheduler } = await createScheduler(getDefaultConfig()); - - scheduler.showAppointmentPopup(commonAppointment); - - const endDateEditor = POM.popup.dxForm.getEditor('endDateEditor'); - expect(endDateEditor).toBeDefined(); - expect(endDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); - - scheduler.option('firstDayOfWeek', 0); - - scheduler.showAppointmentPopup(commonAppointment); - - const endDateEditorAfter = POM.popup.dxForm.getEditor('endDateEditor'); - expect(endDateEditorAfter).toBeDefined(); - expect(endDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); - }); - it('should pass value from localization firstDayOfWeek to calendars when option is not set', async () => { const { POM, scheduler } = await createScheduler({ ...getDefaultConfig(), diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index 8eb580dbaeb0..bd425e92bc5c 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -3,6 +3,7 @@ import { } from '@jest/globals'; import fx from '../../../common/core/animation/fx'; +import $ from '../../../core/renderer'; import { createAppointmentPopup, disposeAppointmentPopups, @@ -336,4 +337,78 @@ describe('Isolated AppointmentPopup environment', () => { expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); }); }); + + describe('firstDayOfWeek', () => { + const commonAppointment = { + text: 'common-app', + startDate: new Date(2017, 4, 9, 9, 30), + endDate: new Date(2017, 4, 9, 11), + }; + + it('should apply firstDayOfWeek to week day buttons', async () => { + const { POM, reopen } = await createAppointmentPopup({ + appointmentData: commonAppointment, + firstDayOfWeek: 1, + }); + + POM.selectRepeatValue('weekly'); + const dayButtonsMonday = $(POM.recurrenceWeekDayButtons).find('.dx-button'); + expect(dayButtonsMonday.text()).toBe('MTWTFSS'); + + const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); + POM2.selectRepeatValue('weekly'); + const dayButtonsSunday = $(POM2.recurrenceWeekDayButtons).find('.dx-button'); + expect(dayButtonsSunday.text()).toBe('SMTWTFS'); + }); + + it('should apply firstDayOfWeek to recurrence form startDate calendar', async () => { + const { POM, reopen } = await createAppointmentPopup({ + appointmentData: commonAppointment, + firstDayOfWeek: 1, + }); + + POM.selectRepeatValue('weekly'); + const recurrenceStartDateEditor = POM.dxForm.getEditor('recurrenceStartDateEditor'); + expect(recurrenceStartDateEditor).toBeDefined(); + expect(recurrenceStartDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); + + const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); + POM2.selectRepeatValue('weekly'); + const recurrenceStartDateEditorAfter = POM2.dxForm.getEditor('recurrenceStartDateEditor'); + expect(recurrenceStartDateEditorAfter).toBeDefined(); + expect(recurrenceStartDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); + }); + + it('should apply firstDayOfWeek to startDate calendar', async () => { + const { POM, reopen } = await createAppointmentPopup({ + appointmentData: commonAppointment, + firstDayOfWeek: 1, + }); + + const startDateEditor = POM.dxForm.getEditor('startDateEditor'); + expect(startDateEditor).toBeDefined(); + expect(startDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); + + const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); + const startDateEditorAfter = POM2.dxForm.getEditor('startDateEditor'); + expect(startDateEditorAfter).toBeDefined(); + expect(startDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); + }); + + it('should apply firstDayOfWeek to endDate calendar', async () => { + const { POM, reopen } = await createAppointmentPopup({ + appointmentData: commonAppointment, + firstDayOfWeek: 1, + }); + + const endDateEditor = POM.dxForm.getEditor('endDateEditor'); + expect(endDateEditor).toBeDefined(); + expect(endDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); + + const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); + const endDateEditorAfter = POM2.dxForm.getEditor('endDateEditor'); + expect(endDateEditorAfter).toBeDefined(); + expect(endDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); + }); + }); }); From 31d42ac37781b9be66ee7f46f121e201c7edc6c8 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 21 May 2026 20:33:09 -0300 Subject: [PATCH 5/8] Scheduler - Drop reopen pattern and simplify popup tests --- .../__mock__/create_appointment_popup.ts | 23 +-- .../appointment_popup.test.ts | 147 ++++++++---------- 2 files changed, 71 insertions(+), 99 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts index 75a6ef203bcc..c1abb2a372d9 100644 --- a/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts +++ b/packages/devextreme/js/__internal/scheduler/__tests__/__mock__/create_appointment_popup.ts @@ -41,6 +41,8 @@ const DEFAULT_EDITING = { allowDragging: true, }; +const NO_TIMEZONE = ''; + const DEFAULT_APPOINTMENT = { text: 'Test Appointment', startDate: new Date(2021, 3, 26, 9, 30), @@ -70,11 +72,6 @@ interface CreateAppointmentPopupOptions { updateAppointment?: jest.Mock; } -interface ReopenOptions { - appointmentData?: Record; - firstDayOfWeek?: number; -} - interface CreateAppointmentPopupResult { container: HTMLDivElement; popup: AppointmentPopup; @@ -86,7 +83,6 @@ interface CreateAppointmentPopupResult { focus: jest.Mock; onSave: jest.Mock<(appointment: Record) => PromiseLike>; }; - reopen: (opts?: ReopenOptions) => Promise<{ POM: PopupModel }>; dispose: () => void; } @@ -111,7 +107,7 @@ export const createAppointmentPopup = async ( const dataAccessors = new AppointmentDataAccessor(DEFAULT_FIELDS, false); const resourceManager = new ResourceManager([]); - const timeZoneCalculator = createTimeZoneCalculator(options.timeZone ?? ''); + const timeZoneCalculator = createTimeZoneCalculator(options.timeZone ?? NO_TIMEZONE); const editing = { ...DEFAULT_EDITING, ...options.editing }; const addAppointment = options.addAppointment @@ -189,18 +185,6 @@ export const createAppointmentPopup = async ( const POM = await showAndQuery(appointmentData); - const reopen = async ( - reopenOpts: ReopenOptions = {}, - ): Promise<{ POM: PopupModel }> => { - if (reopenOpts.firstDayOfWeek !== undefined) { - formConfig.firstDayOfWeek = reopenOpts.firstDayOfWeek as DayOfWeek; - } - - const data = reopenOpts.appointmentData ?? appointmentData; - - return { POM: await showAndQuery(data) }; - }; - const dispose = (): void => { popup.dispose(); container.remove(); @@ -219,7 +203,6 @@ export const createAppointmentPopup = async ( focus, onSave, }, - reopen, dispose, }; }; diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index bd425e92bc5c..b87b2102f915 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -111,10 +111,14 @@ describe('Isolated AppointmentPopup environment', () => { it('should hide popup on Cancel click', async () => { const { popup, POM } = await createAppointmentPopup(); + const visibleBefore = popup.visible; - expect(popup.visible).toBe(true); POM.cancelButton.click(); - expect(popup.visible).toBe(false); + + const visibleAfter = popup.visible; + + expect(visibleBefore).toBe(true); + expect(visibleAfter).toBe(false); }); it('should support composite onSave for exclude-from-series scenario', async () => { @@ -151,20 +155,6 @@ describe('Isolated AppointmentPopup environment', () => { ); }); - describe('State', () => { - it('should create a new dxForm instance on each popup opening', async () => { - const { POM, reopen } = await createAppointmentPopup(); - const firstFormInstance = POM.dxForm; - - POM.cancelButton.click(); - - const { POM: POM2 } = await reopen(); - const secondFormInstance = POM2.dxForm; - - expect(secondFormInstance).not.toBe(firstFormInstance); - }); - }); - describe('allDay switch', () => { const commonAppointment = { text: 'common-app', @@ -193,33 +183,51 @@ describe('Isolated AppointmentPopup environment', () => { it('should hide time editors when switched on', async () => { const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment }); - expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('startTimeEditor')).toBeTruthy(); - expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('endTimeEditor')).toBeTruthy(); + const startDateVisibleBefore = POM.isInputVisible('startDateEditor'); + const startTimeVisibleBefore = POM.isInputVisible('startTimeEditor'); + const endDateVisibleBefore = POM.isInputVisible('endDateEditor'); + const endTimeVisibleBefore = POM.isInputVisible('endTimeEditor'); POM.getInput('allDayEditor').click(); - expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('startTimeEditor')).toBeFalsy(); - expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('endTimeEditor')).toBeFalsy(); + const startDateVisibleAfter = POM.isInputVisible('startDateEditor'); + const startTimeVisibleAfter = POM.isInputVisible('startTimeEditor'); + const endDateVisibleAfter = POM.isInputVisible('endDateEditor'); + const endTimeVisibleAfter = POM.isInputVisible('endTimeEditor'); + + expect(startDateVisibleBefore).toBeTruthy(); + expect(startTimeVisibleBefore).toBeTruthy(); + expect(endDateVisibleBefore).toBeTruthy(); + expect(endTimeVisibleBefore).toBeTruthy(); + expect(startDateVisibleAfter).toBeTruthy(); + expect(startTimeVisibleAfter).toBeFalsy(); + expect(endDateVisibleAfter).toBeTruthy(); + expect(endTimeVisibleAfter).toBeFalsy(); }); it('should show time editors when switched off', async () => { const { POM } = await createAppointmentPopup({ appointmentData: allDayAppointment }); - expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('startTimeEditor')).toBeFalsy(); - expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('endTimeEditor')).toBeFalsy(); + const startDateVisibleBefore = POM.isInputVisible('startDateEditor'); + const startTimeVisibleBefore = POM.isInputVisible('startTimeEditor'); + const endDateVisibleBefore = POM.isInputVisible('endDateEditor'); + const endTimeVisibleBefore = POM.isInputVisible('endTimeEditor'); POM.getInput('allDayEditor').click(); - expect(POM.isInputVisible('startDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('startTimeEditor')).toBeTruthy(); - expect(POM.isInputVisible('endDateEditor')).toBeTruthy(); - expect(POM.isInputVisible('endTimeEditor')).toBeTruthy(); + const startDateVisibleAfter = POM.isInputVisible('startDateEditor'); + const startTimeVisibleAfter = POM.isInputVisible('startTimeEditor'); + const endDateVisibleAfter = POM.isInputVisible('endDateEditor'); + const endTimeVisibleAfter = POM.isInputVisible('endTimeEditor'); + + expect(startDateVisibleBefore).toBeTruthy(); + expect(startTimeVisibleBefore).toBeFalsy(); + expect(endDateVisibleBefore).toBeTruthy(); + expect(endTimeVisibleBefore).toBeFalsy(); + expect(startDateVisibleAfter).toBeTruthy(); + expect(startTimeVisibleAfter).toBeTruthy(); + expect(endDateVisibleAfter).toBeTruthy(); + expect(endTimeVisibleAfter).toBeTruthy(); }); it('should reset start to startDayHour and end via getCalculatedEndDate when switched off', async () => { @@ -345,70 +353,51 @@ describe('Isolated AppointmentPopup environment', () => { endDate: new Date(2017, 4, 9, 11), }; - it('should apply firstDayOfWeek to week day buttons', async () => { - const { POM, reopen } = await createAppointmentPopup({ + it.each([ + { firstDayOfWeek: 1, expected: 'MTWTFSS' }, + { firstDayOfWeek: 0, expected: 'SMTWTFS' }, + ])('should render week day buttons in $expected order when firstDayOfWeek=$firstDayOfWeek', async ({ firstDayOfWeek, expected }) => { + const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment, - firstDayOfWeek: 1, + firstDayOfWeek, }); POM.selectRepeatValue('weekly'); - const dayButtonsMonday = $(POM.recurrenceWeekDayButtons).find('.dx-button'); - expect(dayButtonsMonday.text()).toBe('MTWTFSS'); - const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); - POM2.selectRepeatValue('weekly'); - const dayButtonsSunday = $(POM2.recurrenceWeekDayButtons).find('.dx-button'); - expect(dayButtonsSunday.text()).toBe('SMTWTFS'); + const dayButtonsText = $(POM.recurrenceWeekDayButtons).find('.dx-button').text(); + expect(dayButtonsText).toBe(expected); }); - it('should apply firstDayOfWeek to recurrence form startDate calendar', async () => { - const { POM, reopen } = await createAppointmentPopup({ + it.each([ + { editorName: 'recurrenceStartDateEditor' as const, firstDayOfWeek: 1 }, + { editorName: 'recurrenceStartDateEditor' as const, firstDayOfWeek: 0 }, + ])('should apply firstDayOfWeek=$firstDayOfWeek to $editorName calendar', async ({ editorName, firstDayOfWeek }) => { + const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment, - firstDayOfWeek: 1, + firstDayOfWeek, }); POM.selectRepeatValue('weekly'); - const recurrenceStartDateEditor = POM.dxForm.getEditor('recurrenceStartDateEditor'); - expect(recurrenceStartDateEditor).toBeDefined(); - expect(recurrenceStartDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); - - const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); - POM2.selectRepeatValue('weekly'); - const recurrenceStartDateEditorAfter = POM2.dxForm.getEditor('recurrenceStartDateEditor'); - expect(recurrenceStartDateEditorAfter).toBeDefined(); - expect(recurrenceStartDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); - }); - - it('should apply firstDayOfWeek to startDate calendar', async () => { - const { POM, reopen } = await createAppointmentPopup({ - appointmentData: commonAppointment, - firstDayOfWeek: 1, - }); - - const startDateEditor = POM.dxForm.getEditor('startDateEditor'); - expect(startDateEditor).toBeDefined(); - expect(startDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); - const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); - const startDateEditorAfter = POM2.dxForm.getEditor('startDateEditor'); - expect(startDateEditorAfter).toBeDefined(); - expect(startDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); + const editor = POM.dxForm.getEditor(editorName); + expect(editor).toBeDefined(); + expect(editor?.option('calendarOptions.firstDayOfWeek')).toBe(firstDayOfWeek); }); - it('should apply firstDayOfWeek to endDate calendar', async () => { - const { POM, reopen } = await createAppointmentPopup({ + it.each([ + { editorName: 'startDateEditor' as const, firstDayOfWeek: 1 }, + { editorName: 'startDateEditor' as const, firstDayOfWeek: 0 }, + { editorName: 'endDateEditor' as const, firstDayOfWeek: 1 }, + { editorName: 'endDateEditor' as const, firstDayOfWeek: 0 }, + ])('should apply firstDayOfWeek=$firstDayOfWeek to $editorName calendar', async ({ editorName, firstDayOfWeek }) => { + const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment, - firstDayOfWeek: 1, + firstDayOfWeek, }); - const endDateEditor = POM.dxForm.getEditor('endDateEditor'); - expect(endDateEditor).toBeDefined(); - expect(endDateEditor?.option('calendarOptions.firstDayOfWeek')).toBe(1); - - const { POM: POM2 } = await reopen({ firstDayOfWeek: 0 }); - const endDateEditorAfter = POM2.dxForm.getEditor('endDateEditor'); - expect(endDateEditorAfter).toBeDefined(); - expect(endDateEditorAfter?.option('calendarOptions.firstDayOfWeek')).toBe(0); + const editor = POM.dxForm.getEditor(editorName); + expect(editor).toBeDefined(); + expect(editor?.option('calendarOptions.firstDayOfWeek')).toBe(firstDayOfWeek); }); }); }); From 37709680b22d9134c07ad247cafbf157be3b7c9b Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Thu, 21 May 2026 20:54:58 -0300 Subject: [PATCH 6/8] Scheduler - Drop pass-through propagation tests and trim allDay assertions --- .../appointment_popup.test.ts | 88 ++----------------- 1 file changed, 8 insertions(+), 80 deletions(-) diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index b87b2102f915..0fc7369d63dc 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -3,7 +3,6 @@ import { } from '@jest/globals'; import fx from '../../../common/core/animation/fx'; -import $ from '../../../core/renderer'; import { createAppointmentPopup, disposeAppointmentPopups, @@ -183,51 +182,35 @@ describe('Isolated AppointmentPopup environment', () => { it('should hide time editors when switched on', async () => { const { POM } = await createAppointmentPopup({ appointmentData: commonAppointment }); - const startDateVisibleBefore = POM.isInputVisible('startDateEditor'); const startTimeVisibleBefore = POM.isInputVisible('startTimeEditor'); - const endDateVisibleBefore = POM.isInputVisible('endDateEditor'); const endTimeVisibleBefore = POM.isInputVisible('endTimeEditor'); POM.getInput('allDayEditor').click(); - const startDateVisibleAfter = POM.isInputVisible('startDateEditor'); const startTimeVisibleAfter = POM.isInputVisible('startTimeEditor'); - const endDateVisibleAfter = POM.isInputVisible('endDateEditor'); const endTimeVisibleAfter = POM.isInputVisible('endTimeEditor'); - expect(startDateVisibleBefore).toBeTruthy(); - expect(startTimeVisibleBefore).toBeTruthy(); - expect(endDateVisibleBefore).toBeTruthy(); - expect(endTimeVisibleBefore).toBeTruthy(); - expect(startDateVisibleAfter).toBeTruthy(); - expect(startTimeVisibleAfter).toBeFalsy(); - expect(endDateVisibleAfter).toBeTruthy(); - expect(endTimeVisibleAfter).toBeFalsy(); + expect(startTimeVisibleBefore).toBe(true); + expect(endTimeVisibleBefore).toBe(true); + expect(startTimeVisibleAfter).toBe(false); + expect(endTimeVisibleAfter).toBe(false); }); it('should show time editors when switched off', async () => { const { POM } = await createAppointmentPopup({ appointmentData: allDayAppointment }); - const startDateVisibleBefore = POM.isInputVisible('startDateEditor'); const startTimeVisibleBefore = POM.isInputVisible('startTimeEditor'); - const endDateVisibleBefore = POM.isInputVisible('endDateEditor'); const endTimeVisibleBefore = POM.isInputVisible('endTimeEditor'); POM.getInput('allDayEditor').click(); - const startDateVisibleAfter = POM.isInputVisible('startDateEditor'); const startTimeVisibleAfter = POM.isInputVisible('startTimeEditor'); - const endDateVisibleAfter = POM.isInputVisible('endDateEditor'); const endTimeVisibleAfter = POM.isInputVisible('endTimeEditor'); - expect(startDateVisibleBefore).toBeTruthy(); - expect(startTimeVisibleBefore).toBeFalsy(); - expect(endDateVisibleBefore).toBeTruthy(); - expect(endTimeVisibleBefore).toBeFalsy(); - expect(startDateVisibleAfter).toBeTruthy(); - expect(startTimeVisibleAfter).toBeTruthy(); - expect(endDateVisibleAfter).toBeTruthy(); - expect(endTimeVisibleAfter).toBeTruthy(); + expect(startTimeVisibleBefore).toBe(false); + expect(endTimeVisibleBefore).toBe(false); + expect(startTimeVisibleAfter).toBe(true); + expect(endTimeVisibleAfter).toBe(true); }); it('should reset start to startDayHour and end via getCalculatedEndDate when switched off', async () => { @@ -345,59 +328,4 @@ describe('Isolated AppointmentPopup environment', () => { expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); }); }); - - describe('firstDayOfWeek', () => { - const commonAppointment = { - text: 'common-app', - startDate: new Date(2017, 4, 9, 9, 30), - endDate: new Date(2017, 4, 9, 11), - }; - - it.each([ - { firstDayOfWeek: 1, expected: 'MTWTFSS' }, - { firstDayOfWeek: 0, expected: 'SMTWTFS' }, - ])('should render week day buttons in $expected order when firstDayOfWeek=$firstDayOfWeek', async ({ firstDayOfWeek, expected }) => { - const { POM } = await createAppointmentPopup({ - appointmentData: commonAppointment, - firstDayOfWeek, - }); - - POM.selectRepeatValue('weekly'); - - const dayButtonsText = $(POM.recurrenceWeekDayButtons).find('.dx-button').text(); - expect(dayButtonsText).toBe(expected); - }); - - it.each([ - { editorName: 'recurrenceStartDateEditor' as const, firstDayOfWeek: 1 }, - { editorName: 'recurrenceStartDateEditor' as const, firstDayOfWeek: 0 }, - ])('should apply firstDayOfWeek=$firstDayOfWeek to $editorName calendar', async ({ editorName, firstDayOfWeek }) => { - const { POM } = await createAppointmentPopup({ - appointmentData: commonAppointment, - firstDayOfWeek, - }); - - POM.selectRepeatValue('weekly'); - - const editor = POM.dxForm.getEditor(editorName); - expect(editor).toBeDefined(); - expect(editor?.option('calendarOptions.firstDayOfWeek')).toBe(firstDayOfWeek); - }); - - it.each([ - { editorName: 'startDateEditor' as const, firstDayOfWeek: 1 }, - { editorName: 'startDateEditor' as const, firstDayOfWeek: 0 }, - { editorName: 'endDateEditor' as const, firstDayOfWeek: 1 }, - { editorName: 'endDateEditor' as const, firstDayOfWeek: 0 }, - ])('should apply firstDayOfWeek=$firstDayOfWeek to $editorName calendar', async ({ editorName, firstDayOfWeek }) => { - const { POM } = await createAppointmentPopup({ - appointmentData: commonAppointment, - firstDayOfWeek, - }); - - const editor = POM.dxForm.getEditor(editorName); - expect(editor).toBeDefined(); - expect(editor?.option('calendarOptions.firstDayOfWeek')).toBe(firstDayOfWeek); - }); - }); }); From 6a1cdf2f73b58b99dad31aa94660a7660d46a27a Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 22 May 2026 09:16:17 -0300 Subject: [PATCH 7/8] Scheduler - Add popup firstDayOfWeek propagation test --- .../appointment_popup.test.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index 0fc7369d63dc..9918ea19340e 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -328,4 +328,24 @@ describe('Isolated AppointmentPopup environment', () => { expect(POM.getInputValue('endDateEditor')).toEqual('5/9/2017'); }); }); + + it('should propagate firstDayOfWeek to editor calendars', async () => { + const { POM } = await createAppointmentPopup({ + appointmentData: { + text: 'common-app', + startDate: new Date(2017, 4, 9, 9, 30), + endDate: new Date(2017, 4, 9, 11), + }, + firstDayOfWeek: 1, + }); + POM.selectRepeatValue('weekly'); + + const startDateFDOW = POM.dxForm.getEditor('startDateEditor')?.option('calendarOptions.firstDayOfWeek'); + const endDateFDOW = POM.dxForm.getEditor('endDateEditor')?.option('calendarOptions.firstDayOfWeek'); + const recurrenceStartFDOW = POM.dxForm.getEditor('recurrenceStartDateEditor')?.option('calendarOptions.firstDayOfWeek'); + + expect(startDateFDOW).toBe(1); + expect(endDateFDOW).toBe(1); + expect(recurrenceStartFDOW).toBe(1); + }); }); From 44aa4ec42e8dc5b0376e2035e6ae5a1a231c53a7 Mon Sep 17 00:00:00 2001 From: Aleksey Semikozov Date: Fri, 22 May 2026 10:56:28 -0300 Subject: [PATCH 8/8] Scheduler - Extend firstDayOfWeek propagation test with recurrence week day buttons --- .../scheduler/appointment_popup/appointment_popup.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts index 9918ea19340e..b638a730c170 100644 --- a/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts +++ b/packages/devextreme/js/__internal/scheduler/appointment_popup/appointment_popup.test.ts @@ -329,7 +329,7 @@ describe('Isolated AppointmentPopup environment', () => { }); }); - it('should propagate firstDayOfWeek to editor calendars', async () => { + it('should propagate firstDayOfWeek to editor calendars and recurrence week day buttons', async () => { const { POM } = await createAppointmentPopup({ appointmentData: { text: 'common-app', @@ -343,9 +343,11 @@ describe('Isolated AppointmentPopup environment', () => { const startDateFDOW = POM.dxForm.getEditor('startDateEditor')?.option('calendarOptions.firstDayOfWeek'); const endDateFDOW = POM.dxForm.getEditor('endDateEditor')?.option('calendarOptions.firstDayOfWeek'); const recurrenceStartFDOW = POM.dxForm.getEditor('recurrenceStartDateEditor')?.option('calendarOptions.firstDayOfWeek'); + const weekDayButtonsText = POM.recurrenceWeekDayButtons.textContent; expect(startDateFDOW).toBe(1); expect(endDateFDOW).toBe(1); expect(recurrenceStartFDOW).toBe(1); + expect(weekDayButtonsText).toBe('MTWTFSS'); }); });