devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
1,112 lines • 88.9 kB
JavaScript
/**
* 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