UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

1,112 lines • 88.9 kB
/** * DevExtreme (esm/__internal/scheduler/appointment_popup/appointment_popup.integration.test.js) * Version: 25.2.8 * Build date: Mon Jun 08 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ import { afterEach, beforeEach, describe, expect, it, jest } from "@jest/globals"; import dateLocalization from "../../../common/core/localization/date"; import { CustomStore } from "../../../common/data/custom_store"; import $ from "../../../core/renderer"; import { toMilliseconds } from "../../utils/toMilliseconds"; import fx from "../../../common/core/animation/fx"; import { createScheduler } from "../__tests__/__mock__/create_scheduler"; import { setupSchedulerTestEnvironment } from "../__tests__/__mock__/m_mock_scheduler"; import { DEFAULT_SCHEDULER_OPTIONS } from "../utils/options/constants"; const CLASSES = { icon: "dx-scheduler-form-icon", hidden: "dx-hidden", scheduler: "dx-scheduler", mainGroupHidden: "dx-scheduler-form-main-group-hidden", recurrenceGroupHidden: "dx-scheduler-form-recurrence-group-hidden" }; const recurringAppointment = { text: "recurring-app", startDate: new Date(2017, 4, 1, 9, 30), endDate: new Date(2017, 4, 1, 11), recurrenceRule: "FREQ=DAILY;COUNT=5" }; const commonAppointment = { text: "common-app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11) }; const disabledAppointment = { text: "disabled-app", startDate: new Date(2017, 4, 22, 9, 30), endDate: new Date(2017, 4, 22, 11, 30), disabled: true }; const allDayAppointment = { text: "all-day-app", startDate: new Date(2017, 4, 1), endDate: new Date(2017, 4, 1), allDay: true }; const getDefaultConfig = () => ({ dataSource: [], views: ["month"], currentView: "month", currentDate: new Date(2017, 4, 25), firstDayOfWeek: 1, startDayHour: 9, height: 600, width: 600 }); describe("Appointment Form", () => { beforeEach(() => { fx.off = true; setupSchedulerTestEnvironment({ height: 600 }) }); afterEach(() => { const $scheduler = $(document.querySelector(`.${CLASSES.scheduler}`)); $scheduler.dxScheduler("dispose"); document.body.innerHTML = ""; fx.off = false; jest.useRealTimers() }); describe("Changes saving/canceling", () => { it("should update appointment on save button click", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, commonAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.setInputValue("subjectEditor", "New Subject"); POM.popup.saveButton.click(); await Promise.resolve(); expect(dataSource.items()[0]).toMatchObject(Object.assign({}, commonAppointment, { text: "New Subject" })) }); it("should not update appointment on cancel button click", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, commonAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.setInputValue("subjectEditor", "New Subject"); POM.popup.cancelButton.click(); expect(dataSource.items()[0]).toMatchObject(commonAppointment) }); it("should update recurring appointment on save button click in recurrence form", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, recurringAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.editSeriesButton.click(); POM.popup.setInputValue("subjectEditor", "New Subject"); POM.popup.recurrenceSettingsButton.click(); POM.popup.saveButton.click(); await Promise.resolve(); expect(dataSource.items()[0]).toMatchObject(Object.assign({}, recurringAppointment, { text: "New Subject" })) }); it("should not update recurring appointment on cancel button click in recurrence form", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, recurringAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.editSeriesButton.click(); POM.popup.setInputValue("subjectEditor", "New Subject"); POM.popup.recurrenceSettingsButton.click(); POM.popup.cancelButton.click(); expect(dataSource.items()[0]).toMatchObject(recurringAppointment) }); it("should update appointment recurrence rule changes on save button click", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, commonAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.selectRepeatValue("daily"); POM.popup.saveButton.click(); await Promise.resolve(); expect(dataSource.items()[0]).toMatchObject(Object.assign({}, commonAppointment, { recurrenceRule: "FREQ=DAILY" })) }); it("should not update appointment recurrence rule changes on cancel button click", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, commonAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.selectRepeatValue("daily"); POM.popup.cancelButton.click(); expect(dataSource.items()[0]).toMatchObject(commonAppointment) }); it("should not update recurrence rule on save button click if recurrence rule was not changed", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, recurringAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.editSeriesButton.click(); POM.popup.saveButton.click(); await Promise.resolve(); expect(dataSource.items()[0]).toMatchObject(recurringAppointment) }); it("should update recurrence rule on save button click if repeat editor value was set to never", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, recurringAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.editSeriesButton.click(); POM.popup.selectRepeatValue("never"); POM.popup.saveButton.click(); await Promise.resolve(); expect(dataSource.items()[0]).toMatchObject(Object.assign({}, recurringAppointment, { recurrenceRule: "" })) }); it("should update appointment when data source is a custom store", async () => { const appointment = Object.assign({}, commonAppointment, { id: 0 }); const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: { store: { type: "array", key: "id", data: [appointment] } } })); scheduler.showAppointmentPopup(appointment); POM.popup.setInputValue("subjectEditor", "Updated subject"); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const items = scheduler.getDataSource().items(); expect(items).toHaveLength(1); expect(items[0]).toMatchObject(Object.assign({}, appointment, { text: "Updated subject" })) }); it("should create appointment when data source is a custom store", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: { store: { type: "array", key: "id", data: [] } } })); scheduler.showAppointmentPopup(); POM.popup.setInputValue("subjectEditor", "New subject"); POM.popup.setInputValue("startDateEditor", new Date(2017, 4, 25, 9, 0)); POM.popup.setInputValue("startTimeEditor", new Date(2017, 4, 25, 9, 0)); POM.popup.setInputValue("endDateEditor", new Date(2017, 4, 25, 10, 0)); POM.popup.setInputValue("endTimeEditor", new Date(2017, 4, 25, 10, 0)); POM.popup.setInputValue("descriptionEditor", "New appointment description"); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const items = scheduler.getDataSource().items(); expect(items).toHaveLength(1); expect(items[0]).toMatchObject({ text: "New subject", startDate: new Date(2017, 4, 25, 9, 0), endDate: new Date(2017, 4, 25, 10, 0), description: "New appointment description" }) }); it("should update resource value on save button click", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), roomId: 1 }], resources: [{ fieldExpr: "roomId", dataSource: [{ text: "Room 1", id: 1, color: "#00af2c" }, { text: "Room 2", id: 2, color: "#56ca85" }, { text: "Room 3", id: 3, color: "#8ecd3c" }] }] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); POM.popup.setInputValue("roomId", 2); POM.popup.saveButton.click(); await Promise.resolve(); expect(dataSource.items()[0].roomId).toBe(2) }); it("should create separate appointment when saving single appointment from series", async () => { const appointment = { text: "recurring-app", startDate: "2017-05-01T09:30:00.000Z", endDate: "2017-05-01T11:00:00.000Z", recurrenceRule: "FREQ=DAILY;COUNT=5" }; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, appointment)] })); const dataSource = scheduler.getDataSource(); POM.openPopupByDblClick("recurring-app"); POM.popup.editAppointmentButton.click(); POM.popup.setInputValue("subjectEditor", "single appointment"); scheduler.hideAppointmentPopup(true); await Promise.resolve(); expect(dataSource.items()).toHaveLength(2); expect(dataSource.items()[0]).toEqual(Object.assign({}, appointment, { recurrenceException: "20170501T093000Z" })); expect(dataSource.items()[1]).toEqual(Object.assign({}, appointment, { text: "single appointment", recurrenceRule: "", allDay: false })) }) }); describe("Validation", () => { it("should close popup on save when startDateEditor is empty in recurrence form", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(getDefaultConfig()); scheduler.showAppointmentPopup(Object.assign({}, commonAppointment)); POM.popup.setInputValue("startDateEditor", null); POM.popup.selectRepeatValue("daily"); expect(POM.popup.getInputValue("recurrenceStartDateEditor")).toBe("5/9/2017"); POM.popup.saveButton.click(); await Promise.resolve(); expect(POM.isPopupVisible()).toBe(false) }) }); describe("State", () => { it("should have correct editor values when opening for empty date cell - 1", async () => { const { POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { currentView: "week" })); POM.dblClickDateTableCell(0, 0); expect(POM.popup.getInputValue("subjectEditor")).toBe(""); expect(POM.popup.getInputValue("startDateEditor")).toBe("5/22/2017"); expect(POM.popup.getInputValue("startTimeEditor")).toBe("9:00 AM"); expect(POM.popup.getInputValue("endDateEditor")).toBe("5/22/2017"); expect(POM.popup.getInputValue("endTimeEditor")).toBe("9:30 AM"); expect(POM.popup.getInputValue("allDayEditor")).toBe("false"); expect(POM.popup.getInputValue("descriptionEditor")).toBe("") }); it("should have correct editor values when opening for empty date cell - 2", async () => { const { POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { currentView: "week" })); POM.dblClickDateTableCell(1, 1); expect(POM.popup.getInputValue("subjectEditor")).toBe(""); expect(POM.popup.getInputValue("startDateEditor")).toBe("5/23/2017"); expect(POM.popup.getInputValue("startTimeEditor")).toBe("9:30 AM"); expect(POM.popup.getInputValue("endDateEditor")).toBe("5/23/2017"); expect(POM.popup.getInputValue("endTimeEditor")).toBe("10:00 AM"); expect(POM.popup.getInputValue("allDayEditor")).toBe("false"); expect(POM.popup.getInputValue("descriptionEditor")).toBe("") }); it("should have correct editor values when opening for empty all day cell", async () => { const { POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { currentView: "week" })); POM.dblClickAllDayTableCell(1); expect(POM.popup.getInputValue("subjectEditor")).toBe(""); expect(POM.popup.getInputValue("startDateEditor")).toBe("5/23/2017"); expect(POM.popup.isInputVisible("startTimeEditor")).toBe(false); expect(POM.popup.getInputValue("endDateEditor")).toBe("5/23/2017"); expect(POM.popup.isInputVisible("endTimeEditor")).toBe(false); expect(POM.popup.getInputValue("allDayEditor")).toBe("true"); expect(POM.popup.getInputValue("descriptionEditor")).toBe("") }) }); describe("Readonly state", () => { it("form should be readonly when editing.allowUpdating is false", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: false } })); scheduler.showAppointmentPopup(Object.assign({}, commonAppointment)); expect(POM.popup.dxForm.option("readOnly")).toBe(true) }); it("form should not be readonly when editing.allowUpdating is false and adding a new appointment", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: false, allowAdding: true } })); scheduler.showAppointmentPopup(Object.assign({}, commonAppointment), true); expect(POM.popup.dxForm.option("readOnly")).toBe(false) }); it("form should be readonly after adding new appointment if editing.allowUpdating is false", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: false, allowAdding: true } })); const dataSource = scheduler.getDataSource(); scheduler.showAppointmentPopup(Object.assign({}, commonAppointment), true); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); expect(POM.popup.dxForm.option("readOnly")).toBe(true) }); it("form should be readonly when appointment is disabled", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [Object.assign({}, disabledAppointment)] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); expect(POM.popup.dxForm.option("readOnly")).toBe(true) }) }); describe("startDate/endDate editors behavior", () => { it.each([ ["startDateEditor", "startTimeEditor"], ["endDateEditor", "endTimeEditor"], ["startTimeEditor", "startDateEditor"], ["endTimeEditor", "endDateEditor"] ])("when %s value is set to null, %s value should not be null", async (dateEditorName, timeEditorName) => { const { scheduler: scheduler, POM: POM } = await createScheduler(getDefaultConfig()); scheduler.showAppointmentPopup(Object.assign({}, commonAppointment)); POM.popup.setInputValue(dateEditorName, null); expect(POM.popup.getInputValue(timeEditorName)).not.toBeNull() }) }); describe.each([ ["Field expressions", "customField"], ["Nested field expressions", "nested.customField"] ])("%s", exprValue => { it.each([ ["textExpr", "subjectEditor", "qwerty"], ["allDayExpr", "allDayEditor", true], ["startDateTimeZoneExpr", "startDateTimeZoneEditor", "Pacific/Midway"], ["endDateTimeZoneExpr", "endDateTimeZoneEditor", "Pacific/Midway"], ["descriptionExpr", "descriptionEditor", "qwerty"] ])("should update correct field if %s is defined", async (fieldExpr, editorName, value) => { const defaultField = DEFAULT_SCHEDULER_OPTIONS[fieldExpr]; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: true, allowTimeZoneEditing: true }, [fieldExpr]: exprValue })); scheduler.showAppointmentPopup(); POM.popup.setInputValue(editorName, value); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const customFieldValue = scheduler.option(`dataSource[0].${exprValue}`); const defaultFieldValue = scheduler.option(`dataSource[0].${defaultField}`); expect(customFieldValue).toBe(value); expect(defaultFieldValue).toBeUndefined() }); it.each([ ["startDateExpr", "startDateEditor", "startTimeEditor"], ["endDateExpr", "endDateEditor", "endTimeEditor"] ])("should update correct field if %s is defined", async (fieldExpr, dateEditorName, timeEditorName) => { const value = new Date(2017, 4, 9, 9, 30); const defaultField = DEFAULT_SCHEDULER_OPTIONS[fieldExpr]; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: true, allowTimeZoneEditing: true }, [fieldExpr]: exprValue })); scheduler.showAppointmentPopup(); POM.popup.setInputValue(dateEditorName, value); POM.popup.setInputValue(timeEditorName, value); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const customFieldValue = scheduler.option(`dataSource[0].${exprValue}`); const defaultFieldValue = scheduler.option(`dataSource[0].${defaultField}`); expect(customFieldValue).toEqual(new Date(value)); expect(defaultFieldValue).toBeUndefined() }); it("should update correct field if recurrenceRuleExpr is defined", async () => { const fieldExpr = "recurrenceRuleExpr"; const defaultField = DEFAULT_SCHEDULER_OPTIONS.recurrenceRuleExpr; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: true, allowTimeZoneEditing: true }, [fieldExpr]: exprValue })); scheduler.showAppointmentPopup(); POM.popup.selectRepeatValue("daily"); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const customFieldValue = scheduler.option(`dataSource[0].${exprValue}`); const defaultFieldValue = scheduler.option(`dataSource[0].${defaultField}`); expect(customFieldValue).toBe("FREQ=DAILY"); expect(defaultFieldValue).toBeUndefined() }); it("should update correct resource field if fieldExpr for resource is defined", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: true, allowTimeZoneEditing: true }, resources: [{ fieldExpr: exprValue, allowMultiple: false, dataSource: [{ text: "Room 1", id: 1, color: "#00af2c" }, { text: "Room 2", id: 2, color: "#56ca85" }, { text: "Room 3", id: 3, color: "#8ecd3c" }] }] })); scheduler.showAppointmentPopup(); POM.popup.setInputValue(exprValue, 2); scheduler.hideAppointmentPopup(true); await Promise.resolve(); const customFieldValue = scheduler.option(`dataSource[0].${exprValue}`); const defaultFieldValue = scheduler.option("dataSource[0].roomId"); expect(customFieldValue).toBe(2); expect(defaultFieldValue).toBeUndefined() }) }); describe("allDay switch", () => { it("should set correct dates when switching on then off in day view", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { currentView: "day" })); scheduler.showAppointmentPopup(commonAppointment); POM.popup.getInput("allDayEditor").click(); POM.popup.getInput("allDayEditor").click(); expect(POM.popup.getInputValue("startDateEditor")).toBe("5/9/2017"); expect(POM.popup.getInputValue("startTimeEditor")).toBe("9:00 AM"); expect(POM.popup.getInputValue("endDateEditor")).toBe("5/9/2017"); expect(POM.popup.getInputValue("endTimeEditor")).toBe("9:30 AM") }); it("should set correct dates when switching on then off in month view", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { currentView: "month" })); scheduler.showAppointmentPopup(commonAppointment); POM.popup.getInput("allDayEditor").click(); POM.popup.getInput("allDayEditor").click(); expect(POM.popup.getInputValue("startDateEditor")).toBe("5/9/2017"); expect(POM.popup.getInputValue("startTimeEditor")).toBe("9:00 AM"); expect(POM.popup.getInputValue("endDateEditor")).toBe("5/10/2017"); expect(POM.popup.getInputValue("endTimeEditor")).toBe("12:00 AM") }) }); describe("Timezone Editors", () => { it("should have correct timezone editors values", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowUpdating: true, allowTimeZoneEditing: true } })); scheduler.showAppointmentPopup({ text: "Watercolor Landscape", startDate: new Date("2020-06-01T17:30:00.000Z"), endDate: new Date("2020-06-01T19:00:00.000Z"), startDateTimeZone: "Etc/GMT+10", endDateTimeZone: "US/Alaska" }); expect(POM.popup.getInputValue("startDateTimeZoneEditor")).toBe("Etc/GMT+10"); expect(POM.popup.getInputValue("endDateTimeZoneEditor")).toBe("US/Alaska") }); it("should be shown when editing.allowTimeZoneEditing is true", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowTimeZoneEditing: true } })); scheduler.showAppointmentPopup(commonAppointment); expect(POM.popup.isInputVisible("startDateTimeZoneEditor")).toBeTruthy(); expect(POM.popup.isInputVisible("endDateTimeZoneEditor")).toBeTruthy() }); it("should be hidden when editing.allowTimeZoneEditing is false", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowTimeZoneEditing: false } })); scheduler.showAppointmentPopup(commonAppointment); expect(POM.popup.isInputVisible("startDateTimeZoneEditor")).toBeFalsy(); expect(POM.popup.isInputVisible("endDateTimeZoneEditor")).toBeFalsy() }); it("change of startTimeZone value should trigger endTimeZone value change", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowTimeZoneEditing: true } })); scheduler.showAppointmentPopup(commonAppointment); POM.popup.setInputValue("startDateTimeZoneEditor", "America/Los_Angeles"); expect(POM.popup.getInputValue("startDateTimeZoneEditor")).toBe("America/Los_Angeles"); expect(POM.popup.getInputValue("endDateTimeZoneEditor")).toBe("America/Los_Angeles") }); it("change of endTimeZone value should not trigger startTimeZone value change", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { allowTimeZoneEditing: true } })); scheduler.showAppointmentPopup(commonAppointment); POM.popup.setInputValue("startDateTimeZoneEditor", "America/Los_Angeles"); POM.popup.setInputValue("endDateTimeZoneEditor", "America/New_York"); expect(POM.popup.getInputValue("startDateTimeZoneEditor")).toBe("America/Los_Angeles"); expect(POM.popup.getInputValue("endDateTimeZoneEditor")).toBe("America/New_York") }) }); describe("Resources", () => { afterEach(() => { jest.useRealTimers() }); it("should have correct resource editor value", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), roomId: 2 }], resources: [{ fieldExpr: "roomId", dataSource: [{ text: "Room 1", id: 1, color: "#00af2c" }, { text: "Room 2", id: 2, color: "#56ca85" }, { text: "Room 3", id: 3, color: "#8ecd3c" }] }] })); const dataSource = scheduler.getDataSource(); const item = dataSource.items()[0]; scheduler.showAppointmentPopup(item); expect(POM.popup.getInputValue("roomId")).toBe("Room 2") }); it("should create resourceEditorsGroup when resources have no custom icons", async () => { var _resourcesGroup$items; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { resources: [{ fieldExpr: "roomId" }, { fieldExpr: "ownerId" }] })); scheduler.showAppointmentPopup(); const resourcesGroup = POM.popup.dxForm.itemOption("mainGroup.resourcesGroup"); expect(resourcesGroup).toBeDefined(); expect(null === resourcesGroup || void 0 === resourcesGroup || null === (_resourcesGroup$items = resourcesGroup.items) || void 0 === _resourcesGroup$items ? void 0 : _resourcesGroup$items.length).toBe(2); expect(null === resourcesGroup || void 0 === resourcesGroup ? void 0 : resourcesGroup.items).toEqual(expect.arrayContaining([expect.objectContaining({ name: "resourcesGroupIcon" }), expect.objectContaining({ name: "resourceEditorsGroup", itemType: "group", items: expect.arrayContaining([expect.objectContaining({ name: "roomIdEditor" }), expect.objectContaining({ name: "ownerIdEditor" })]) })])) }); it("should create individual resource groups when resources have custom icons", async () => { var _resourcesGroup$items2; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { resources: [{ fieldExpr: "roomId", icon: "home" }, { fieldExpr: "ownerId", icon: "user" }] })); scheduler.showAppointmentPopup(); const resourcesGroup = POM.popup.dxForm.itemOption("mainGroup.resourcesGroup"); expect(resourcesGroup).toBeDefined(); expect(null === resourcesGroup || void 0 === resourcesGroup || null === (_resourcesGroup$items2 = resourcesGroup.items) || void 0 === _resourcesGroup$items2 ? void 0 : _resourcesGroup$items2.length).toBe(2); expect(null === resourcesGroup || void 0 === resourcesGroup ? void 0 : resourcesGroup.items).toEqual(expect.arrayContaining([expect.objectContaining({ name: "roomIdGroup", itemType: "group", items: expect.arrayContaining([expect.objectContaining({ name: "roomIdIcon" }), expect.objectContaining({ name: "roomIdEditor" })]) }), expect.objectContaining({ name: "ownerIdGroup", itemType: "group", items: expect.arrayContaining([expect.objectContaining({ name: "ownerIdIcon" }), expect.objectContaining({ name: "ownerIdEditor" })]) })])) }); it("should render FontAwesome icon with correct CSS classes (T1322161)", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), roomId: 1 }], resources: [{ fieldExpr: "roomId", icon: "fas fa-home", dataSource: [{ text: "Room 1", id: 1 }, { text: "Room 2", id: 2 }] }] })); const dataSource = scheduler.getDataSource(); const appointment = dataSource.items()[0]; scheduler.showAppointmentPopup(appointment); const { resourceIcon: resourceIcon } = POM.popup; expect(resourceIcon.classList.contains("fas")).toBe(true); expect(resourceIcon.classList.contains("fa-home")).toBe(true) }); it("should create dxTagBox for resource with multiple selection", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), ownerId: [1, 2] }], resources: [{ fieldExpr: "ownerId", allowMultiple: true, dataSource: [{ text: "Owner 1", id: 1 }, { text: "Owner 2", id: 2 }, { text: "Owner 3", id: 3 }] }] })); const dataSource = scheduler.getDataSource(); const appointment = dataSource.items()[0]; scheduler.showAppointmentPopup(appointment); const resourceEditor = POM.popup.dxForm.getEditor("ownerId"); expect(resourceEditor.NAME).toBe("dxTagBox"); expect(resourceEditor.option("value")).toEqual([1, 2]) }); it("should create dxSelectBox for resource with single selection", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), ownerId: 2 }], resources: [{ fieldExpr: "ownerId", allowMultiple: false, dataSource: [{ text: "Owner 1", id: 1 }, { text: "Owner 2", id: 2 }, { text: "Owner 3", id: 3 }] }] })); const dataSource = scheduler.getDataSource(); const appointment = dataSource.items()[0]; scheduler.showAppointmentPopup(appointment); const resourceEditor = POM.popup.dxForm.getEditor("ownerId"); expect(resourceEditor.NAME).toBe("dxSelectBox"); expect(resourceEditor.option("value")).toEqual(2) }); it("should load resource dataSource only once", async () => { const resourceDataSource = new CustomStore({ load: () => [{ text: "Owner 1", id: 1 }, { text: "Owner 2", id: 2 }, { text: "Owner 3", id: 3 }], byKey: () => {} }); const loadSpy = jest.spyOn(resourceDataSource, "load"); const byKeySpy = jest.spyOn(resourceDataSource, "byKey"); const { scheduler: scheduler } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), ownerId: [2] }], resources: [{ allowMultiple: true, fieldExpr: "ownerId", dataSource: resourceDataSource }] })); const dataSource = scheduler.getDataSource(); const appointment = dataSource.items()[0]; expect(loadSpy).toHaveBeenCalledTimes(1); scheduler.showAppointmentPopup(appointment); expect(loadSpy).toHaveBeenCalledTimes(1); expect(byKeySpy).toHaveBeenCalledTimes(0) }); it("should not trigger extra CustomStore load on second popup open", async () => { const loadFn = jest.fn().mockImplementation(() => Promise.resolve([{ text: "Owner 1", id: 1 }, { text: "Owner 2", id: 2 }])); const resourceDataSource = new CustomStore({ load: loadFn, byKey: () => {} }); const { scheduler: scheduler } = await createScheduler(Object.assign({}, getDefaultConfig(), { dataSource: [{ text: "Resource test app", startDate: new Date(2017, 4, 9, 9, 30), endDate: new Date(2017, 4, 9, 11), ownerId: 1 }], resources: [{ fieldExpr: "ownerId", dataSource: resourceDataSource }] })); jest.useFakeTimers(); const appointment = scheduler.getDataSource().items()[0]; scheduler.showAppointmentPopup(appointment); scheduler.hideAppointmentPopup(false); scheduler.showAppointmentPopup(appointment); await jest.runAllTimersAsync(); expect(loadFn).toHaveBeenCalledTimes(1) }); it("should recreate appointment form synchronously when resources option changes", async () => { const { scheduler: scheduler } = await createScheduler(Object.assign({}, getDefaultConfig(), { resources: [{ fieldExpr: "roomId", dataSource: [{ id: 1, text: "Room 1" }] }] })); const formBefore = scheduler.appointmentForm; scheduler.option("resources", [{ fieldExpr: "ownerId", dataSource: [{ id: 1, text: "Owner 1" }] }]); const formAfter = scheduler.appointmentForm; expect(formAfter).not.toBe(formBefore); expect(formAfter.config.resourceManager).toBe(scheduler.resourceManager) }) }); describe("firstDayOfWeek", () => { beforeEach(() => { jest.spyOn(dateLocalization, "firstDayOfWeekIndex").mockReturnValue(3) }); afterEach(() => { jest.restoreAllMocks() }); it("should pass value from localization firstDayOfWeek to calendars when option is not set", async () => { const { POM: POM, scheduler: scheduler } = await createScheduler(Object.assign({}, getDefaultConfig(), { firstDayOfWeek: void 0 })); scheduler.showAppointmentPopup(commonAppointment); const startDateEditor = POM.popup.dxForm.getEditor("startDateEditor"); expect(startDateEditor).toBeDefined(); expect(null === startDateEditor || void 0 === startDateEditor ? void 0 : startDateEditor.option("calendarOptions.firstDayOfWeek")).toBe(3) }) }); describe("Icons", () => { describe("Subject icon", () => { it("has default color when appointment has no resources", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(getDefaultConfig()); scheduler.showAppointmentPopup(commonAppointment); const $icon = $(POM.popup.subjectIcon); expect($icon.css("color")).toBe("") }); it("has default color when showAppointmentPopup is called without data", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(getDefaultConfig()); scheduler.showAppointmentPopup(); const $icon = $(POM.popup.subjectIcon); expect($icon.css("color")).toBe("") }); it("has resource color when appointment has resource", async () => { const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { resources: [{ fieldExpr: "roomId", dataSource: [{ id: 1, text: "Room 1", color: "rgb(255, 0, 0)" }, { id: 2, text: "Room 2", color: "rgb(0, 0, 255)" }] }] })); scheduler.showAppointmentPopup(Object.assign({}, commonAppointment, { roomId: 1 })); await new Promise(process.nextTick); const $icon = $(POM.popup.subjectIcon); expect($icon.css("color")).toBe("rgb(255, 0, 0)"); POM.popup.setInputValue("roomId", 2); await new Promise(process.nextTick); expect($icon.css("color")).toBe("rgb(0, 0, 255)") }) }); describe("Resource icons", () => { it.each([{ iconsShowMode: "both", visibleMain: true, visibleRecurrence: true }, { iconsShowMode: "main", visibleMain: true, visibleRecurrence: false }, { iconsShowMode: "recurrence", visibleMain: false, visibleRecurrence: true }, { iconsShowMode: "none", visibleMain: false, visibleRecurrence: false }])("should shown icons correctly when iconsShowMode is '$iconsShowMode'", async _ref => { let { iconsShowMode: iconsShowMode, visibleMain: visibleMain, visibleRecurrence: visibleRecurrence } = _ref; const { scheduler: scheduler, POM: POM } = await createScheduler(Object.assign({}, getDefaultConfig(), { editing: { form: { iconsShowMode: iconsShowMode } } })); scheduler.showAppointmentPopup(commonAppointment); const mainFormIcons = POM.popup.mainGroup.querySelectorAll(`.${CLASSES.icon}`); const recurrenceFormIcons = POM.popup.recurrenceGroup.querySelectorAll(`.${CLASSES.icon}`); expect(mainFormIcons.length).toBe(visibleMain ? 4 : 0); expect(recurrenceFormIcons.length).toBe(visibleRecurrence ? 3 : 0) }) }) }); describe("Callbacks", () => { describe("OnAppointmentFormOpening", () => { it("should be called when showing appointment popup", async () => { const onAppointment