Initial commit: Core packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:45 +02:00
commit 12c29a983b
9512 changed files with 8379910 additions and 0 deletions

View file

@ -0,0 +1,170 @@
/** @odoo-module **/
import { CalendarArchParser } from "@web/views/calendar/calendar_arch_parser";
import { FAKE_FIELDS } from "./helpers";
function parseArch(arch, options = {}) {
const parser = new CalendarArchParser();
return parser.parse(arch, { fake: "fields" in options ? options.fields : FAKE_FIELDS }, "fake");
}
function check(assert, paramName, paramValue, expectedName, expectedValue) {
const arch = `<calendar date_start="start_date" ${paramName}="${paramValue}" />`;
const data = parseArch(arch);
assert.strictEqual(data[expectedName], expectedValue);
}
QUnit.module("CalendarView - ArchParser");
QUnit.test("throw if date_start is not set", (assert) => {
assert.throws(() => {
parseArch(`<calendar />`);
});
});
QUnit.test("defaults", (assert) => {
assert.deepEqual(parseArch(`<calendar date_start="start_date" />`), {
canCreate: true,
canDelete: true,
eventLimit: 5,
fieldMapping: {
date_start: "start_date",
},
fieldNames: ["start_date"],
filtersInfo: {},
formViewId: false,
hasEditDialog: false,
hasQuickCreate: true,
isDateHidden: false,
isTimeHidden: false,
popoverFields: {},
scale: "week",
scales: ["day", "week", "month", "year"],
showUnusualDays: false,
});
});
QUnit.test("canCreate", (assert) => {
check(assert, "create", "", "canCreate", true);
check(assert, "create", "true", "canCreate", true);
check(assert, "create", "True", "canCreate", true);
check(assert, "create", "1", "canCreate", true);
check(assert, "create", "false", "canCreate", false);
check(assert, "create", "False", "canCreate", false);
check(assert, "create", "0", "canCreate", false);
});
QUnit.test("canDelete", (assert) => {
check(assert, "delete", "", "canDelete", true);
check(assert, "delete", "true", "canDelete", true);
check(assert, "delete", "True", "canDelete", true);
check(assert, "delete", "1", "canDelete", true);
check(assert, "delete", "false", "canDelete", false);
check(assert, "delete", "False", "canDelete", false);
check(assert, "delete", "0", "canDelete", false);
});
QUnit.test("eventLimit", (assert) => {
check(assert, "event_limit", "2", "eventLimit", 2);
check(assert, "event_limit", "5", "eventLimit", 5);
assert.throws(() => {
parseArch(`<calendar date_start="start_date" event_limit="five" />`);
});
assert.throws(() => {
parseArch(`<calendar date_start="start_date" event_limit="" />`);
});
});
QUnit.test("hasEditDialog", (assert) => {
check(assert, "event_open_popup", "", "hasEditDialog", false);
check(assert, "event_open_popup", "true", "hasEditDialog", true);
check(assert, "event_open_popup", "True", "hasEditDialog", true);
check(assert, "event_open_popup", "1", "hasEditDialog", true);
check(assert, "event_open_popup", "false", "hasEditDialog", false);
check(assert, "event_open_popup", "False", "hasEditDialog", false);
check(assert, "event_open_popup", "0", "hasEditDialog", false);
});
QUnit.test("hasQuickCreate", (assert) => {
check(assert, "quick_add", "", "hasQuickCreate", true);
check(assert, "quick_add", "true", "hasQuickCreate", true);
check(assert, "quick_add", "True", "hasQuickCreate", true);
check(assert, "quick_add", "1", "hasQuickCreate", true);
check(assert, "quick_add", "false", "hasQuickCreate", false);
check(assert, "quick_add", "False", "hasQuickCreate", false);
check(assert, "quick_add", "0", "hasQuickCreate", false);
check(assert, "quick_add", "390", "hasQuickCreate", true);
});
QUnit.test("isDateHidden", (assert) => {
check(assert, "hide_date", "", "isDateHidden", false);
check(assert, "hide_date", "true", "isDateHidden", true);
check(assert, "hide_date", "True", "isDateHidden", true);
check(assert, "hide_date", "1", "isDateHidden", true);
check(assert, "hide_date", "false", "isDateHidden", false);
check(assert, "hide_date", "False", "isDateHidden", false);
check(assert, "hide_date", "0", "isDateHidden", false);
});
QUnit.test("isTimeHidden", (assert) => {
check(assert, "hide_time", "", "isTimeHidden", false);
check(assert, "hide_time", "true", "isTimeHidden", true);
check(assert, "hide_time", "True", "isTimeHidden", true);
check(assert, "hide_time", "1", "isTimeHidden", true);
check(assert, "hide_time", "false", "isTimeHidden", false);
check(assert, "hide_time", "False", "isTimeHidden", false);
check(assert, "hide_time", "0", "isTimeHidden", false);
});
QUnit.test("scale", (assert) => {
check(assert, "mode", "day", "scale", "day");
check(assert, "mode", "week", "scale", "week");
check(assert, "mode", "month", "scale", "month");
check(assert, "mode", "year", "scale", "year");
assert.throws(() => {
parseArch(`<calendar date_start="start_date" mode="other" />`);
});
assert.throws(() => {
parseArch(`<calendar date_start="start_date" mode="" />`);
});
});
QUnit.test("scales", (assert) => {
function check(scales, expectedScales) {
const arch = `<calendar date_start="start_date" scales="${scales}" />`;
const data = parseArch(arch);
assert.deepEqual(data.scales, expectedScales);
}
check("", []);
check("day", ["day"]);
check("day,week", ["day", "week"]);
check("day,week,month", ["day", "week", "month"]);
check("day,week,month,year", ["day", "week", "month", "year"]);
check("week", ["week"]);
check("week,month", ["week", "month"]);
check("week,month,year", ["week", "month", "year"]);
check("month", ["month"]);
check("month,year", ["month", "year"]);
check("year", ["year"]);
check("year,day,month,week", ["year", "day", "month", "week"]);
assert.throws(() => {
parseArch(`<calendar date_start="start_date" scales="month" mode="day" />`);
});
});
QUnit.test("showUnusualDays", (assert) => {
check(assert, "show_unusual_days", "", "showUnusualDays", false);
check(assert, "show_unusual_days", "true", "showUnusualDays", true);
check(assert, "show_unusual_days", "True", "showUnusualDays", true);
check(assert, "show_unusual_days", "1", "showUnusualDays", true);
check(assert, "show_unusual_days", "false", "showUnusualDays", false);
check(assert, "show_unusual_days", "False", "showUnusualDays", false);
check(assert, "show_unusual_days", "0", "showUnusualDays", false);
});

View file

@ -0,0 +1,222 @@
/** @odoo-module **/
import { CalendarCommonPopover } from "@web/views/calendar/calendar_common/calendar_common_popover";
import { click, getFixture } from "../../helpers/utils";
import { makeEnv, makeFakeDate, makeFakeModel, mountComponent } from "./helpers";
let target;
function makeFakeRecord(data = {}) {
return {
id: 5,
title: "Meeting",
isAllDay: false,
start: makeFakeDate(),
end: makeFakeDate().plus({ hours: 3, minutes: 15 }),
colorIndex: 0,
isTimeHidden: false,
rawRecord: {
name: "Meeting",
},
...data,
};
}
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarCommonPopover, env, {
model,
record: makeFakeRecord(),
createRecord() {},
deleteRecord() {},
editRecord() {},
close() {},
...props,
});
}
/** @todo Add tests for fields **/
QUnit.module("CalendarView - CommonPopover", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
});
QUnit.test("mount a CalendarCommonPopover", async (assert) => {
await start({});
assert.containsOnce(target, ".popover-header");
assert.strictEqual(target.querySelector(".popover-header").textContent, "Meeting");
assert.containsN(target, ".list-group", 2);
assert.containsOnce(target, ".list-group.o_cw_popover_fields_secondary");
assert.containsOnce(target, ".card-footer .o_cw_popover_edit");
assert.containsOnce(target, ".card-footer .o_cw_popover_delete");
});
QUnit.test("date duration: is all day and is same day", async (assert) => {
await start({
props: {
record: makeFakeRecord({ isAllDay: true, isTimeHidden: true }),
},
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "July 16, 2021 (All day)");
});
QUnit.test("date duration: is all day and two days duration", async (assert) => {
await start({
props: {
record: makeFakeRecord({
end: makeFakeDate().plus({ days: 1 }),
isAllDay: true,
isTimeHidden: true,
}),
},
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "July 16-17, 2021 (2 days)");
});
QUnit.test("time duration: 1 hour diff", async (assert) => {
await start({
props: {
record: makeFakeRecord({ end: makeFakeDate().plus({ hours: 1 }) }),
},
model: { isDateHidden: true },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "08:00 - 09:00 (1 hour)");
});
QUnit.test("time duration: 2 hours diff", async (assert) => {
await start({
props: {
record: makeFakeRecord({ end: makeFakeDate().plus({ hours: 2 }) }),
},
model: { isDateHidden: true },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "08:00 - 10:00 (2 hours)");
});
QUnit.test("time duration: 1 minute diff", async (assert) => {
await start({
props: {
record: makeFakeRecord({ end: makeFakeDate().plus({ minutes: 1 }) }),
},
model: { isDateHidden: true },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "08:00 - 08:01 (1 minute)");
});
QUnit.test("time duration: 2 minutes diff", async (assert) => {
await start({
props: {
record: makeFakeRecord({ end: makeFakeDate().plus({ minutes: 2 }) }),
},
model: { isDateHidden: true },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "08:00 - 08:02 (2 minutes)");
});
QUnit.test("time duration: 3 hours and 15 minutes diff", async (assert) => {
await start({
model: { isDateHidden: true },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "08:00 - 11:15 (3 hours, 15 minutes)");
});
QUnit.test("isDateHidden is true", async (assert) => {
await start({
model: { isDateHidden: true },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "08:00 - 11:15 (3 hours, 15 minutes)");
});
QUnit.test("isDateHidden is false", async (assert) => {
await start({
model: { isDateHidden: false },
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(
dateTimeLabels,
"July 16, 2021 08:00 - 11:15 (3 hours, 15 minutes)"
);
});
QUnit.test("isTimeHidden is true", async (assert) => {
await start({
props: {
record: makeFakeRecord({ isTimeHidden: true }),
},
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(dateTimeLabels, "July 16, 2021");
});
QUnit.test("isTimeHidden is false", async (assert) => {
await start({
props: {
record: makeFakeRecord({ isTimeHidden: false }),
},
});
const dateTimeGroup = target.querySelector(`.list-group`);
const dateTimeLabels = dateTimeGroup.textContent.replace(/\s+/g, " ").trim();
assert.strictEqual(
dateTimeLabels,
"July 16, 2021 08:00 - 11:15 (3 hours, 15 minutes)"
);
});
QUnit.test("canDelete is true", async (assert) => {
await start({
model: { canDelete: true },
});
assert.containsOnce(target, ".o_cw_popover_delete");
});
QUnit.test("canDelete is false", async (assert) => {
await start({
model: { canDelete: false },
});
assert.containsNone(target, ".o_cw_popover_delete");
});
QUnit.test("click on delete button", async (assert) => {
assert.expect(2);
await start({
model: { canDelete: true },
props: {
deleteRecord: () => assert.step("delete"),
},
});
await click(target, ".o_cw_popover_delete");
assert.verifySteps(["delete"]);
});
QUnit.test("click on edit button", async (assert) => {
assert.expect(2);
await start({
props: {
editRecord: () => assert.step("edit"),
},
});
await click(target, ".o_cw_popover_edit");
assert.verifySteps(["edit"]);
});
});

View file

@ -0,0 +1,162 @@
/** @odoo-module **/
import { browser } from "@web/core/browser/browser";
import { CalendarCommonRenderer } from "@web/views/calendar/calendar_common/calendar_common_renderer";
import { getFixture, patchWithCleanup } from "../../helpers/utils";
import {
makeEnv,
makeFakeModel,
mountComponent,
clickAllDaySlot,
selectTimeRange,
clickEvent,
makeFakeDate,
} from "./helpers";
let target;
function makeFakePopoverService(add) {
return { start: () => ({ add }) };
}
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarCommonRenderer, env, {
model,
createRecord() {},
deleteRecord() {},
editRecord() {},
displayName: "Plop",
...props,
});
}
QUnit.module("CalendarView - CommonRenderer", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
});
QUnit.test("mount a CalendarCommonRenderer", async (assert) => {
await start({});
assert.containsOnce(target, ".o_calendar_widget.fc");
});
QUnit.test("Day: mount a CalendarCommonRenderer", async (assert) => {
await start({ model: { scale: "day" } });
assert.containsOnce(target, ".o_calendar_widget.fc .fc-timeGridDay-view");
});
QUnit.test("Week: mount a CalendarCommonRenderer", async (assert) => {
await start({ model: { scale: "week" } });
assert.containsOnce(target, ".o_calendar_widget.fc .fc-timeGridWeek-view");
});
QUnit.test("Month: mount a CalendarCommonRenderer", async (assert) => {
await start({ model: { scale: "month" } });
assert.containsOnce(target, ".o_calendar_widget.fc .fc-dayGridMonth-view");
});
QUnit.test("Day: check week number", async (assert) => {
await start({ model: { scale: "day" } });
assert.containsOnce(target, ".fc-week-number");
assert.strictEqual(target.querySelector(".fc-week-number").textContent, "Week 28");
});
QUnit.test("Day: check date", async (assert) => {
await start({ model: { scale: "day" } });
assert.containsOnce(target, ".fc-day-header");
assert.strictEqual(target.querySelector(".fc-day-header").textContent, "July 16, 2021");
});
QUnit.test("Day: click all day slot", async (assert) => {
patchWithCleanup(browser, {
setTimeout: (fn) => fn(),
clearTimeout() {},
});
await start({
model: { scale: "day" },
props: {
createRecord(record) {
const date = makeFakeDate().startOf("day");
assert.ok(record.isAllDay);
assert.strictEqual(record.start.valueOf(), date.valueOf());
assert.step("create");
},
},
});
await clickAllDaySlot(target, "2021-07-16");
assert.verifySteps(["create"]);
});
QUnit.test("Day: select range", async (assert) => {
await start({
model: { scale: "day" },
props: {
createRecord(record) {
assert.notOk(record.isAllDay);
assert.strictEqual(
record.start.valueOf(),
luxon.DateTime.local(2021, 7, 16, 8, 0).valueOf()
);
assert.strictEqual(
record.end.valueOf(),
luxon.DateTime.local(2021, 7, 16, 10, 0).valueOf()
);
assert.step("create");
},
},
});
await selectTimeRange(target, "2021-07-16 08:00:00", "2021-07-16 10:00:00");
assert.verifySteps(["create"]);
});
QUnit.test("Day: check event", async (assert) => {
await start({ model: { scale: "day" } });
assert.containsOnce(target, ".o_event");
assert.hasAttrValue(target.querySelector(".o_event"), "data-event-id", "1");
});
QUnit.test("Day: click on event", async (assert) => {
assert.expect(1);
patchWithCleanup(browser, {
setTimeout: (fn) => fn(),
clearTimeout() {},
});
await start({
model: { scale: "day" },
services: {
popover: makeFakePopoverService((target, _, props) => {
assert.strictEqual(props.record.id, 1);
return () => {};
}),
},
});
await clickEvent(target, 1);
});
QUnit.test("Week: check week number", async (assert) => {
await start({ model: { scale: "week" } });
assert.containsOnce(target, ".fc-week-number");
assert.strictEqual(target.querySelector(".fc-week-number").textContent, "Week 28");
});
QUnit.test("Week: check dates", async (assert) => {
await start({ model: { scale: "week" } });
assert.containsN(target, ".fc-day-header", 7);
const dates = ["Sun 11", "Mon 12", "Tue 13", "Wed 14", "Thu 15", "Fri 16", "Sat 17"];
const els = target.querySelectorAll(".fc-day-header");
for (let i = 0; i < els.length; i++) {
assert.strictEqual(els[i].textContent, dates[i]);
}
});
});

View file

@ -0,0 +1,124 @@
/** @odoo-module **/
import { CalendarDatePicker } from "@web/views/calendar/date_picker/calendar_date_picker";
import { click, getFixture, patchDate } from "../../helpers/utils";
import { makeEnv, makeFakeModel, mountComponent } from "./helpers";
let target;
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarDatePicker, env, {
model,
...props,
});
}
QUnit.module("CalendarView - DatePicker", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
patchDate(2021, 7, 14, 8, 0, 0);
});
QUnit.test("Mount a CalendarDatePicker", async (assert) => {
await start({ model: { scale: "day" } });
assert.containsOnce(target, ".o_calendar_mini.hasDatepicker");
assert.strictEqual(target.querySelector(".o_selected_range").textContent, "16");
assert.containsOnce(target, `[data-month="6"][data-year="2021"] .o_selected_range`);
assert.strictEqual(target.querySelector(".ui-datepicker-month").textContent, "Jul");
assert.strictEqual(target.querySelector(".ui-datepicker-year").textContent, "2021");
assert.strictEqual(target.querySelector("thead").textContent, "SMTWTFS");
});
QUnit.test("Scale: init with day", async (assert) => {
await start({ model: { scale: "day" } });
assert.containsOnce(target, ".o_selected_range");
assert.containsOnce(target, "a.o_selected_range");
assert.strictEqual(target.querySelector(".o_selected_range").textContent, "16");
});
QUnit.test("Scale: init with week", async (assert) => {
await start({ model: { scale: "week" } });
assert.containsOnce(target, ".o_selected_range");
assert.containsOnce(target, "tr.o_selected_range");
assert.hasClass(target.querySelector("tr.o_selected_range"), "o_color");
assert.strictEqual(target.querySelector(".o_selected_range").textContent, "11121314151617");
});
QUnit.test("Scale: init with month", async (assert) => {
await start({ model: { scale: "month" } });
assert.containsN(target, "td.o_selected_range", 35);
});
QUnit.test("Scale: init with year", async (assert) => {
await start({ model: { scale: "year" } });
assert.containsN(target, "td.o_selected_range", 35);
});
QUnit.test("First day: 0 = Sunday", async (assert) => {
await start({ model: { scale: "day", firstDayOfWeek: 0 } });
assert.strictEqual(target.querySelector("thead").textContent, "SMTWTFS");
});
QUnit.test("First day: 1 = Monday", async (assert) => {
await start({ model: { scale: "day", firstDayOfWeek: 1 } });
assert.strictEqual(target.querySelector("thead").textContent, "MTWTFSS");
});
QUnit.test("Click on active day should change scale : day -> month", async (assert) => {
assert.expect(2);
await start({
model: {
scale: "day",
load(params) {
assert.strictEqual(params.scale, "month");
assert.ok(params.date.equals(luxon.DateTime.local(2021, 7, 16)));
},
},
});
await click(target, ".ui-state-active");
});
QUnit.test("Click on active day should change scale : month -> week", async (assert) => {
assert.expect(2);
await start({
model: {
scale: "month",
load(params) {
assert.strictEqual(params.scale, "week");
assert.ok(params.date.equals(luxon.DateTime.local(2021, 7, 16)));
},
},
});
await click(target, ".ui-state-active");
});
QUnit.test("Click on active day should change scale : week -> day", async (assert) => {
assert.expect(2);
await start({
model: {
scale: "week",
load(params) {
assert.strictEqual(params.scale, "day");
assert.ok(params.date.equals(luxon.DateTime.local(2021, 7, 16)));
},
},
});
await click(target, ".ui-state-active");
});
QUnit.test("Scale: today is correctly highlighted", async (assert) => {
patchDate(2021, 6, 4, 8, 0, 0);
await start({ model: { scale: "month" } });
assert.containsOnce(target, ".ui-datepicker-today");
assert.strictEqual(target.querySelector(".ui-datepicker-today").textContent, "4");
});
});

View file

@ -0,0 +1,213 @@
/** @odoo-module **/
import { CalendarFilterPanel } from "@web/views/calendar/filter_panel/calendar_filter_panel";
import { click, getFixture, triggerEvent } from "../../helpers/utils";
import { makeEnv, makeFakeModel, mountComponent } from "./helpers";
let target;
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarFilterPanel, env, {
model,
...props,
});
}
QUnit.module("CalendarView - FilterPanel", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
});
QUnit.test("render filter panel", async (assert) => {
await start({});
assert.containsN(target, ".o_calendar_filter", 2);
const sections = target.querySelectorAll(".o_calendar_filter");
let header = sections[0].querySelector(".o_cw_filter_label");
assert.strictEqual(header.textContent, "Attendees");
assert.containsN(sections[0], ".o_calendar_filter_item", 4);
header = sections[1].querySelector(".o_cw_filter_label");
assert.strictEqual(header.textContent, "Users");
assert.containsN(sections[1], ".o_calendar_filter_item", 2);
});
QUnit.test("filters are correctly sorted", async (assert) => {
await start({});
assert.containsN(target, ".o_calendar_filter", 2);
const sections = target.querySelectorAll(".o_calendar_filter");
let header = sections[0].querySelector(".o_cw_filter_label");
assert.strictEqual(header.textContent, "Attendees");
assert.containsN(sections[0], ".o_calendar_filter_item", 4);
assert.strictEqual(
sections[0].textContent.trim(),
"AttendeesMitchell AdminMarc DemoBrandon FreemanEverybody's calendar"
);
header = sections[1].querySelector(".o_cw_filter_label");
assert.strictEqual(header.textContent, "Users");
assert.containsN(sections[1], ".o_calendar_filter_item", 2);
assert.strictEqual(sections[1].textContent.trim(), "UsersMarc DemoBrandon Freeman");
});
QUnit.test("section can collapse", async (assert) => {
await start({});
const section = target.querySelectorAll(".o_calendar_filter")[0];
assert.containsOnce(section, ".o_cw_filter_collapse_icon");
assert.containsN(section, ".o_calendar_filter_item", 4);
await click(section, ".o_cw_filter_label");
assert.containsNone(section, ".o_calendar_filter_item");
await click(section, ".o_cw_filter_label");
assert.containsN(section, ".o_calendar_filter_item", 4);
});
QUnit.test("section cannot collapse", async (assert) => {
await start({});
const section = target.querySelectorAll(".o_calendar_filter")[1];
assert.containsNone(section, ".o_cw_filter_label > i");
assert.doesNotHaveClass(section, "o_calendar_filter-collapsed");
assert.containsN(section, ".o_calendar_filter_item", 2);
await click(section, ".o_cw_filter_label");
assert.doesNotHaveClass(section, "o_calendar_filter-collapsed");
assert.containsN(section, ".o_calendar_filter_item", 2);
});
QUnit.test("filters can have avatar", async (assert) => {
await start({});
const section = target.querySelectorAll(".o_calendar_filter")[0];
const filters = section.querySelectorAll(".o_calendar_filter_item");
assert.containsN(section, ".o_cw_filter_avatar", 4);
assert.containsN(section, "img.o_cw_filter_avatar", 3);
assert.containsOnce(section, "i.o_cw_filter_avatar");
assert.hasAttrValue(
filters[0].querySelector(".o_cw_filter_avatar"),
"data-src",
"/web/image/res.partner/3/avatar_128"
);
assert.hasAttrValue(
filters[1].querySelector(".o_cw_filter_avatar"),
"data-src",
"/web/image/res.partner/6/avatar_128"
);
assert.hasAttrValue(
filters[2].querySelector(".o_cw_filter_avatar"),
"data-src",
"/web/image/res.partner/4/avatar_128"
);
});
QUnit.test("filters cannot have avatar", async (assert) => {
await start({});
const section = target.querySelectorAll(".o_calendar_filter")[1];
assert.containsN(section, ".o_calendar_filter_item", 2);
assert.containsNone(section, ".o_cw_filter_avatar");
});
QUnit.test("filter can have remove button", async (assert) => {
await start({});
const section = target.querySelectorAll(".o_calendar_filter")[0];
const filters = section.querySelectorAll(".o_calendar_filter_item");
assert.containsN(section, ".o_calendar_filter_item", 4);
assert.containsN(section, ".o_calendar_filter_item .o_remove", 2);
assert.containsNone(filters[0], ".o_remove");
assert.containsOnce(filters[1], ".o_remove");
assert.containsOnce(filters[2], ".o_remove");
assert.containsNone(filters[3], ".o_remove");
});
QUnit.test("click on remove button", async (assert) => {
assert.expect(3);
await start({
model: {
unlinkFilter(fieldName, recordId) {
assert.step(`${fieldName} ${recordId}`);
},
},
});
const section = target.querySelectorAll(".o_calendar_filter")[0];
const filters = section.querySelectorAll(".o_calendar_filter_item");
await click(filters[1], ".o_calendar_filter_item .o_remove");
await click(filters[2], ".o_calendar_filter_item .o_remove");
assert.verifySteps(["partner_ids 2", "partner_ids 1"]);
});
QUnit.test("click on filter", async (assert) => {
assert.expect(6);
await start({
model: {
updateFilters(fieldName, args) {
assert.step(`${fieldName} ${Object.keys(args)[0]} ${Object.values(args)[0]}`);
},
},
});
const section = target.querySelectorAll(".o_calendar_filter")[0];
const filters = section.querySelectorAll(".o_calendar_filter_item");
await click(filters[0], "input");
await click(filters[1], "input");
await click(filters[2], "input");
await click(filters[3], "input");
await click(filters[3], "input");
assert.verifySteps([
"partner_ids 3 false",
"partner_ids 6 true",
"partner_ids 4 false",
"partner_ids all true",
"partner_ids all false",
]);
});
QUnit.test("hover filter opens tooltip", async (assert) => {
await start({
services: {
popover: {
start: () => ({
add: (target, _, props) => {
assert.step(props.filter.label);
assert.step("" + props.filter.hasAvatar);
assert.step("" + props.filter.value);
return () => {
assert.step("popOver Closed");
};
},
}),
},
},
});
const section = target.querySelectorAll(".o_calendar_filter")[0];
const filters = section.querySelectorAll(".o_calendar_filter_item");
await triggerEvent(filters[0], null, "mouseenter");
assert.verifySteps(["Mitchell Admin", "true", "3"]);
await triggerEvent(filters[0], null, "mouseleave");
assert.verifySteps(["popOver Closed"]);
await triggerEvent(filters[3], null, "mouseenter");
assert.verifySteps([]);
await triggerEvent(filters[3], null, "mouseleave");
assert.verifySteps([]);
});
});

View file

@ -0,0 +1,131 @@
/** @odoo-module **/
import { CalendarQuickCreate } from "@web/views/calendar/quick_create/calendar_quick_create";
import { click, getFixture } from "../../helpers/utils";
import { makeEnv, makeFakeModel, mountComponent } from "./helpers";
let target;
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
env.dialogData = {
isActive: true,
close() {},
};
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarQuickCreate, env, {
model,
record: {},
close() {},
editRecord() {},
...props,
});
}
QUnit.module("CalendarView - QuickCreate", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
});
QUnit.test("mount a CalendarQuickCreate", async (assert) => {
await start({});
assert.containsOnce(target, ".o-calendar-quick-create");
assert.containsOnce(target, ".o_dialog .modal-sm");
assert.strictEqual(target.querySelector(".modal-title").textContent, "New Event");
assert.strictEqual(target.querySelector(`input[name="title"]`), document.activeElement);
assert.containsOnce(target, ".o-calendar-quick-create--create-btn");
assert.containsOnce(target, ".o-calendar-quick-create--edit-btn");
assert.containsOnce(target, ".o-calendar-quick-create--cancel-btn");
});
QUnit.test("click on create button", async (assert) => {
assert.expect(2);
await start({
props: {
close: () => assert.step("close"),
},
model: {
createRecord: () => assert.step("create"),
},
});
await click(target, ".o-calendar-quick-create--create-btn");
assert.verifySteps([]);
assert.hasClass(target.querySelector("input[name=title]"), "o_field_invalid");
});
QUnit.test("click on create button (with name)", async (assert) => {
assert.expect(4);
await start({
props: {
close: () => assert.step("close"),
},
model: {
createRecord(record) {
assert.step("create");
assert.strictEqual(record.title, "TEST");
},
},
});
const input = target.querySelector(".o-calendar-quick-create--input");
input.value = "TEST";
await click(target, ".o-calendar-quick-create--create-btn");
assert.verifySteps(["create", "close"]);
});
QUnit.test("click on edit button", async (assert) => {
assert.expect(3);
await start({
props: {
close: () => assert.step("close"),
editRecord: () => assert.step("edit"),
},
});
await click(target, ".o-calendar-quick-create--edit-btn");
assert.verifySteps(["edit", "close"]);
});
QUnit.test("click on edit button (with name)", async (assert) => {
assert.expect(4);
await start({
props: {
close: () => assert.step("close"),
editRecord(record) {
assert.step("edit");
assert.strictEqual(record.title, "TEST");
},
},
});
const input = target.querySelector(".o-calendar-quick-create--input");
input.value = "TEST";
await click(target, ".o-calendar-quick-create--edit-btn");
assert.verifySteps(["edit", "close"]);
});
QUnit.test("click on cancel button", async (assert) => {
assert.expect(2);
await start({
props: {
close: () => assert.step("close"),
},
});
await click(target, ".o-calendar-quick-create--cancel-btn");
assert.verifySteps(["close"]);
});
QUnit.test("check default title", async (assert) => {
assert.expect(1);
await start({
props: {
title: "Example Title",
},
});
const input = target.querySelector(".o-calendar-quick-create--input");
assert.strictEqual(input.value, "Example Title");
});
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,120 @@
/** @odoo-module **/
import { CalendarYearPopover } from "@web/views/calendar/calendar_year/calendar_year_popover";
import { click, getFixture } from "../../helpers/utils";
import { mountComponent, makeEnv, makeFakeModel, makeFakeRecords, makeFakeDate } from "./helpers";
let target, fakePopoverRecords;
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarYearPopover, env, {
model,
date: makeFakeDate(),
records: fakePopoverRecords,
createRecord() {},
deleteRecord() {},
editRecord() {},
close() {},
...props,
});
}
QUnit.module("CalendarView - YearPopover", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
fakePopoverRecords = [
{
id: 1,
start: makeFakeDate(),
end: makeFakeDate(),
isAllDay: true,
title: "R1",
},
{
id: 2,
start: makeFakeDate().set({ hours: 14 }),
end: makeFakeDate().set({ hours: 16 }),
isAllDay: false,
title: "R2",
},
{
id: 3,
start: makeFakeDate().minus({ days: 1 }),
end: makeFakeDate().plus({ days: 1 }),
isAllDay: true,
title: "R3",
},
{
id: 4,
start: makeFakeDate().minus({ days: 3 }),
end: makeFakeDate().plus({ days: 1 }),
isAllDay: true,
title: "R4",
},
{
id: 5,
start: makeFakeDate().minus({ days: 1 }),
end: makeFakeDate().plus({ days: 3 }),
isAllDay: true,
title: "R5",
},
];
});
QUnit.test("canCreate is true", async (assert) => {
await start({ model: { canCreate: true } });
assert.containsOnce(target, ".o_cw_popover_create");
});
QUnit.test("canCreate is false", async (assert) => {
await start({ model: { canCreate: false } });
assert.containsNone(target, ".o_cw_popover_create");
});
QUnit.test("click on create button", async (assert) => {
assert.expect(3);
await start({
props: {
createRecord: () => assert.step("create"),
},
model: { canCreate: true },
});
assert.containsOnce(target, ".o_cw_popover_create");
await click(target, ".o_cw_popover_create");
assert.verifySteps(["create"]);
});
QUnit.test("group records", async (assert) => {
await start({});
assert.containsN(target, ".o_cw_body > div", 5);
assert.containsN(target, ".o_cw_body > a", 5);
const sectionTitles = target.querySelectorAll(".o_cw_body > div");
assert.strictEqual(sectionTitles[0].textContent.trim(), "July 16, 2021");
assert.strictEqual(sectionTitles[1].textContent.trim(), "July 13-17, 2021");
assert.strictEqual(sectionTitles[2].textContent.trim(), "July 15-17, 2021");
assert.strictEqual(sectionTitles[3].textContent.trim(), "July 15-19, 2021");
assert.strictEqual(
target.querySelector(".o_cw_body").textContent.trim(),
"July 16, 2021R114:00 R2July 13-17, 2021R4July 15-17, 2021R3July 15-19, 2021R5 Create"
);
});
QUnit.test("click on record", async (assert) => {
assert.expect(3);
await start({
props: {
records: [makeFakeRecords()[3]],
editRecord: () => assert.step("edit"),
},
});
assert.containsOnce(target, ".o_cw_body > a");
await click(target, ".o_cw_body > a");
assert.verifySteps(["edit"]);
});
});

View file

@ -0,0 +1,154 @@
/** @odoo-module **/
import { browser } from "@web/core/browser/browser";
import { CalendarYearRenderer } from "@web/views/calendar/calendar_year/calendar_year_renderer";
import { getFixture, patchTimeZone, patchWithCleanup } from "../../helpers/utils";
import { clickDate, mountComponent, selectDateRange, makeEnv, makeFakeModel } from "./helpers";
let target;
async function start(params = {}) {
const { services, props, model: modelParams } = params;
const env = await makeEnv(services);
const model = makeFakeModel(modelParams);
return await mountComponent(CalendarYearRenderer, env, {
model,
createRecord() {},
deleteRecord() {},
editRecord() {},
...props,
});
}
QUnit.module("CalendarView - YearRenderer", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
});
QUnit.test("mount a CalendarYearRenderer", async (assert) => {
await start({});
assert.containsN(target, ".fc-month-container", 12);
const monthHeaders = target.querySelectorAll(".fc-header-toolbar .fc-center");
// check "title format"
assert.strictEqual(monthHeaders.length, 12);
const monthTitles = [
"Jan 2021",
"Feb 2021",
"Mar 2021",
"Apr 2021",
"May 2021",
"Jun 2021",
"Jul 2021",
"Aug 2021",
"Sep 2021",
"Oct 2021",
"Nov 2021",
"Dec 2021",
];
for (let i = 0; i < 12; i++) {
assert.strictEqual(monthHeaders[i].textContent, monthTitles[i]);
}
const dayHeaders = target
.querySelector(".fc-month-container")
.querySelectorAll(".fc-day-header");
// check day header format
assert.strictEqual(dayHeaders.length, 7);
const dayTitles = ["S", "M", "T", "W", "T", "F", "S"];
for (let i = 0; i < 7; i++) {
assert.strictEqual(dayHeaders[i].textContent, dayTitles[i]);
}
// check showNonCurrentDates
assert.containsN(target, ".fc-day-number", 365);
});
QUnit.test("display events", async (assert) => {
patchWithCleanup(browser, {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
await start({
props: {
createRecord(record) {
assert.step(`${record.start.toISODate()} allDay:${record.isAllDay} no event`);
},
},
services: {
popover: {
start: () => ({
add: (target, _, props) => {
assert.step(`${props.date.toISODate()} ${props.records[0].title}`);
return () => {};
},
}),
},
},
});
await clickDate(target, "2021-07-15");
assert.verifySteps(["2021-07-15 allDay:true no event"]);
await clickDate(target, "2021-07-16");
assert.verifySteps(["2021-07-16 1 day, all day in July"]);
await clickDate(target, "2021-07-17");
assert.verifySteps(["2021-07-17 allDay:true no event"]);
await clickDate(target, "2021-07-18");
assert.verifySteps(["2021-07-18 3 days, all day in July"]);
await clickDate(target, "2021-07-19");
assert.verifySteps(["2021-07-19 3 days, all day in July"]);
await clickDate(target, "2021-07-20");
assert.verifySteps(["2021-07-20 3 days, all day in July"]);
await clickDate(target, "2021-07-21");
assert.verifySteps(["2021-07-21 allDay:true no event"]);
await clickDate(target, "2021-06-28");
assert.verifySteps(["2021-06-28 allDay:true no event"]);
await clickDate(target, "2021-06-29");
assert.verifySteps(["2021-06-29 Over June and July"]);
await clickDate(target, "2021-06-30");
assert.verifySteps(["2021-06-30 Over June and July"]);
await clickDate(target, "2021-07-01");
assert.verifySteps(["2021-07-01 Over June and July"]);
await clickDate(target, "2021-07-02");
assert.verifySteps(["2021-07-02 Over June and July"]);
await clickDate(target, "2021-07-03");
assert.verifySteps(["2021-07-03 Over June and July"]);
await clickDate(target, "2021-07-04");
assert.verifySteps(["2021-07-04 allDay:true no event"]);
});
QUnit.test("select a range of date", async (assert) => {
assert.expect(3);
await start({
props: {
createRecord(record) {
assert.ok(record.isAllDay);
assert.ok(record.start.equals(luxon.DateTime.local(2021, 7, 2, 0, 0, 0, 0)));
assert.ok(record.end.equals(luxon.DateTime.local(2021, 7, 5, 0, 0, 0, 0)));
},
},
});
await selectDateRange(target, "2021-07-02", "2021-07-05");
});
QUnit.test("display correct column header for days, independent of the timezone", async (assert) => {
// Regression test: when the system tz is somewhere in a negative GMT (in our example Alaska)
// the day headers of a months were incorrectly set. (S S M T W T F) instead of (S M T W T F S)
// if the first day of the week is Sunday.
patchTimeZone(-540); // UTC-9 = Alaska
await start({});
const dayHeaders = target
.querySelector(".fc-month-container")
.querySelectorAll(".fc-day-header");
assert.deepEqual([...dayHeaders].map((el) => el.textContent), ["S", "M", "T", "W", "T", "F", "S"]);
});
});

View file

@ -0,0 +1,536 @@
/** @odoo-module **/
import { uiService } from "@web/core/ui/ui_service";
import { registry } from "@web/core/registry";
import { clearRegistryWithCleanup, makeTestEnv } from "../../helpers/mock_env";
import { click, getFixture, mount, nextTick, triggerEvent } from "../../helpers/utils";
import { setupViewRegistries } from "@web/../tests/views/helpers";
export function makeEnv(services = {}) {
clearRegistryWithCleanup(registry.category("main_components"));
setupViewRegistries();
services = Object.assign(
{
ui: uiService,
},
services
);
for (const [key, service] of Object.entries(services)) {
registry.category("services").add(key, service, { force: true });
}
return makeTestEnv({
config: {
setDisplayName: () => {},
},
});
}
//------------------------------------------------------------------------------
export async function mountComponent(C, env, props) {
const target = getFixture();
return await mount(C, target, { env, props });
}
//------------------------------------------------------------------------------
export function makeFakeDate() {
return luxon.DateTime.local(2021, 7, 16, 8, 0, 0, 0);
}
export function makeFakeRecords() {
return {
1: {
id: 1,
title: "1 day, all day in July",
start: makeFakeDate(),
isAllDay: true,
end: makeFakeDate(),
},
2: {
id: 2,
title: "3 days, all day in July",
start: makeFakeDate().plus({ days: 2 }),
isAllDay: true,
end: makeFakeDate().plus({ days: 4 }),
},
3: {
id: 3,
title: "1 day, all day in June",
start: makeFakeDate().plus({ months: -1 }),
isAllDay: true,
end: makeFakeDate().plus({ months: -1 }),
},
4: {
id: 4,
title: "3 days, all day in June",
start: makeFakeDate().plus({ months: -1, days: 2 }),
isAllDay: true,
end: makeFakeDate().plus({ months: -1, days: 4 }),
},
5: {
id: 5,
title: "Over June and July",
start: makeFakeDate().startOf("month").plus({ days: -2 }),
isAllDay: true,
end: makeFakeDate().startOf("month").plus({ days: 2 }),
},
};
}
export const FAKE_FILTER_SECTIONS = [
{
label: "Attendees",
fieldName: "partner_ids",
avatar: {
model: "res.partner",
field: "avatar_128",
},
hasAvatar: true,
write: {
model: "filter_partner",
field: "partner_id",
},
canCollapse: true,
canAddFilter: true,
filters: [
{
type: "user",
label: "Mitchell Admin",
active: true,
value: 3,
colorIndex: 3,
recordId: null,
canRemove: false,
hasAvatar: true,
},
{
type: "all",
label: "Everybody's calendar",
active: false,
value: "all",
colorIndex: null,
recordId: null,
canRemove: false,
hasAvatar: false,
},
{
type: "record",
label: "Brandon Freeman",
active: true,
value: 4,
colorIndex: 4,
recordId: 1,
canRemove: true,
hasAvatar: true,
},
{
type: "record",
label: "Marc Demo",
active: false,
value: 6,
colorIndex: 6,
recordId: 2,
canRemove: true,
hasAvatar: true,
},
],
},
{
label: "Users",
fieldName: "user_id",
avatar: {
model: null,
field: null,
},
hasAvatar: false,
write: {
model: null,
field: null,
},
canCollapse: false,
canAddFilter: false,
filters: [
{
type: "record",
label: "Brandon Freeman",
active: false,
value: 1,
colorIndex: false,
recordId: null,
canRemove: true,
hasAvatar: true,
},
{
type: "record",
label: "Marc Demo",
active: false,
value: 2,
colorIndex: false,
recordId: null,
canRemove: true,
hasAvatar: true,
},
],
},
];
export const FAKE_FIELDS = {
id: { string: "Id", type: "integer" },
user_id: { string: "User", type: "many2one", relation: "user", default: -1 },
partner_id: {
string: "Partner",
type: "many2one",
relation: "partner",
related: "user_id.partner_id",
default: 1,
},
name: { string: "Name", type: "char" },
start_date: { string: "Start Date", type: "date" },
stop_date: { string: "Stop Date", type: "date" },
start: { string: "Start Datetime", type: "datetime" },
stop: { string: "Stop Datetime", type: "datetime" },
delay: { string: "Delay", type: "float" },
allday: { string: "Is All Day", type: "boolean" },
partner_ids: {
string: "Attendees",
type: "one2many",
relation: "partner",
default: [[6, 0, [1]]],
},
type: { string: "Type", type: "integer" },
event_type_id: { string: "Event Type", type: "many2one", relation: "event_type" },
color: { string: "Color", type: "integer", related: "event_type_id.color" },
};
function makeFakeModelState() {
return {
canCreate: true,
canDelete: true,
canEdit: true,
date: makeFakeDate(),
fieldMapping: {
date_start: "start_date",
date_stop: "stop_date",
date_delay: "delay",
all_day: "allday",
color: "color",
},
fieldNames: ["start_date", "stop_date", "color", "delay", "allday", "user_id"],
fields: FAKE_FIELDS,
filterSections: FAKE_FILTER_SECTIONS,
firstDayOfWeek: 0,
isDateHidden: false,
isTimeHidden: false,
hasAllDaySlot: true,
hasEditDialog: false,
hasQuickCreate: false,
popoverFields: {
name: { rawAttrs: {}, options: {} },
},
rangeEnd: makeFakeDate().endOf("month"),
rangeStart: makeFakeDate().startOf("month"),
records: makeFakeRecords(),
resModel: "event",
scale: "month",
scales: ["day", "week", "month", "year"],
unusualDays: [],
};
}
export function makeFakeModel(state = {}) {
return {
...makeFakeModelState(),
load() {},
createFilter() {},
createRecord() {},
unlinkFilter() {},
unlinkRecord() {},
updateFilter() {},
updateRecord() {},
...state,
};
}
// DOM Utils
//------------------------------------------------------------------------------
async function scrollTo(el, scrollParam) {
el.scrollIntoView(scrollParam);
await new Promise(window.requestAnimationFrame);
}
export function findPickedDate(target) {
return target.querySelector(".ui-datepicker-current-day");
}
export async function pickDate(target, date) {
const [year, month, day] = date.split("-");
const iMonth = parseInt(month, 10) - 1;
const iDay = parseInt(day, 10) - 1;
const el = target.querySelectorAll(
`.ui-datepicker-calendar td[data-year="${year}"][data-month="${iMonth}"]`
)[iDay];
el.scrollIntoView();
await click(el);
}
function findAllDaySlot(target, date) {
return target.querySelector(`.fc-day-grid .fc-day[data-date="${date}"]`);
}
export function findDateCell(target, date) {
return target.querySelector(`.fc-day-top[data-date="${date}"]`);
}
export function findEvent(target, eventId) {
return target.querySelector(`.o_event[data-event-id="${eventId}"]`);
}
function findDateCol(target, date) {
return target.querySelector(`.fc-day-header[data-date="${date}"]`);
}
export function findTimeRow(target, time) {
return target.querySelector(`.fc-slats [data-time="${time}"] .fc-widget-content`);
}
async function triggerEventForCalendar(el, type, position = {}) {
const rect = el.getBoundingClientRect();
const x = position.x || rect.x + rect.width / 2;
const y = position.y || rect.y + rect.height / 2;
const attrs = {
which: 1,
clientX: x,
clientY: y,
};
await triggerEvent(el, null, type, attrs);
}
export async function clickAllDaySlot(target, date) {
const el = findAllDaySlot(target, date);
await scrollTo(el);
await triggerEventForCalendar(el, "mousedown");
await triggerEventForCalendar(el, "mouseup");
await nextTick();
}
export async function clickDate(target, date) {
const el = findDateCell(target, date);
await scrollTo(el);
await triggerEventForCalendar(el, "mousedown");
await triggerEventForCalendar(el, "mouseup");
await nextTick();
}
export async function clickEvent(target, eventId) {
const el = findEvent(target, eventId);
await scrollTo(el);
await click(el);
await nextTick();
}
export async function selectTimeRange(target, startDateTime, endDateTime) {
const [startDate, startTime] = startDateTime.split(" ");
const [endDate, endTime] = endDateTime.split(" ");
const startCol = findDateCol(target, startDate);
const endCol = findDateCol(target, endDate);
const startRow = findTimeRow(target, startTime);
const endRow = findTimeRow(target, endTime);
await scrollTo(startRow);
const startColRect = startCol.getBoundingClientRect();
const startRowRect = startRow.getBoundingClientRect();
await triggerEventForCalendar(startRow, "mousedown", {
x: startColRect.x + startColRect.width / 2,
y: startRowRect.y + 1,
});
await scrollTo(endRow, false);
const endColRect = endCol.getBoundingClientRect();
const endRowRect = endRow.getBoundingClientRect();
await triggerEventForCalendar(endRow, "mousemove", {
x: endColRect.x + endColRect.width / 2,
y: endRowRect.y - 1,
});
await triggerEventForCalendar(endRow, "mouseup", {
x: endColRect.x + endColRect.width / 2,
y: endRowRect.y - 1,
});
await nextTick();
}
export async function selectDateRange(target, startDate, endDate) {
const start = findDateCell(target, startDate);
const end = findDateCell(target, endDate);
await scrollTo(start);
await triggerEventForCalendar(start, "mousedown");
await scrollTo(end);
await triggerEventForCalendar(end, "mousemove");
await triggerEventForCalendar(end, "mouseup");
await nextTick();
}
export async function selectAllDayRange(target, startDate, endDate) {
const start = findAllDaySlot(target, startDate);
const end = findAllDaySlot(target, endDate);
await scrollTo(start);
await triggerEventForCalendar(start, "mousedown");
await scrollTo(end);
await triggerEventForCalendar(end, "mousemove");
await triggerEventForCalendar(end, "mouseup");
await nextTick();
}
export async function moveEventToDate(target, eventId, date, options = {}) {
const event = findEvent(target, eventId);
const cell = findDateCell(target, date);
await scrollTo(event);
await triggerEventForCalendar(event, "mousedown");
await scrollTo(cell);
await triggerEventForCalendar(cell, "mousemove");
if (!options.disableDrop) {
await triggerEventForCalendar(cell, "mouseup");
}
await nextTick();
}
export async function moveEventToTime(target, eventId, dateTime) {
const event = findEvent(target, eventId);
const [date, time] = dateTime.split(" ");
const col = findDateCol(target, date);
const row = findTimeRow(target, time);
// Find event position
await scrollTo(event);
const eventRect = event.getBoundingClientRect();
const eventPos = {
x: eventRect.x + eventRect.width / 2,
y: eventRect.y,
};
await triggerEventForCalendar(event, "mousedown", eventPos);
// Find target position
await scrollTo(row, false);
const colRect = col.getBoundingClientRect();
const rowRect = row.getBoundingClientRect();
const toPos = {
x: colRect.x + colRect.width / 2,
y: rowRect.y - 1,
};
await triggerEventForCalendar(row, "mousemove", toPos);
await triggerEventForCalendar(row, "mouseup", toPos);
await nextTick();
}
export async function moveEventToAllDaySlot(target, eventId, date) {
const event = findEvent(target, eventId);
const slot = findAllDaySlot(target, date);
// Find event position
await scrollTo(event);
const eventRect = event.getBoundingClientRect();
const eventPos = {
x: eventRect.x + eventRect.width / 2,
y: eventRect.y,
};
await triggerEventForCalendar(event, "mousedown", eventPos);
// Find target position
await scrollTo(slot);
const slotRect = slot.getBoundingClientRect();
const toPos = {
x: slotRect.x + slotRect.width / 2,
y: slotRect.y - 1,
};
await triggerEventForCalendar(slot, "mousemove", toPos);
await triggerEventForCalendar(slot, "mouseup", toPos);
await nextTick();
}
export async function resizeEventToTime(target, eventId, dateTime) {
const event = findEvent(target, eventId);
const [date, time] = dateTime.split(" ");
const col = findDateCol(target, date);
const row = findTimeRow(target, time);
// Find event position
await scrollTo(event);
await triggerEventForCalendar(event, "mouseenter");
// Find event resizer
const resizer = event.querySelector(".fc-end-resizer");
resizer.style.display = "block";
resizer.style.width = "100%";
resizer.style.height = "1em";
resizer.style.bottom = "0";
const resizerRect = resizer.getBoundingClientRect();
const resizerPos = {
x: resizerRect.x + resizerRect.width / 2,
y: resizerRect.y + resizerRect.height / 2,
};
await triggerEventForCalendar(resizer, "mousedown", resizerPos);
// Find target position
await scrollTo(row, false);
const colRect = col.getBoundingClientRect();
const rowRect = row.getBoundingClientRect();
const toPos = {
x: colRect.x + colRect.width / 2,
y: rowRect.y - 1,
};
await triggerEventForCalendar(row, "mousemove", toPos);
await triggerEventForCalendar(row, "mouseup", toPos);
await nextTick();
}
export async function changeScale(target, scale) {
await click(target, `.o_calendar_scale_buttons .scale_button_selection`);
await click(target, `.o_calendar_scale_buttons .o_calendar_button_${scale}`);
await nextTick();
}
export async function navigate(target, direction) {
await click(target, `.o_calendar_navigation_buttons .o_calendar_button_${direction}`);
}
export function findFilterPanelSection(target, sectionName) {
return target.querySelector(`.o_calendar_filter[data-name="${sectionName}"]`);
}
export function findFilterPanelFilter(target, sectionName, filterValue) {
return findFilterPanelSection(target, sectionName).querySelector(
`.o_calendar_filter_item[data-value="${filterValue}"]`
);
}
export function findFilterPanelSectionFilter(target, sectionName) {
return findFilterPanelSection(target, sectionName).querySelector(
`.o_calendar_filter_items_checkall`
);
}
export async function toggleFilter(target, sectionName, filterValue) {
const el = findFilterPanelFilter(target, sectionName, filterValue).querySelector(`input`);
await scrollTo(el);
await click(el);
}
export async function toggleSectionFilter(target, sectionName) {
const el = findFilterPanelSectionFilter(target, sectionName).querySelector(`input`);
await scrollTo(el);
await click(el);
}