mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-22 02:52:02 +02:00
vanilla 18.0
This commit is contained in:
parent
5454004ff9
commit
d7f6d2725e
979 changed files with 428093 additions and 0 deletions
|
|
@ -0,0 +1,214 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { FAKE_FIELDS } from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarArchParser } from "@web/views/calendar/calendar_arch_parser";
|
||||
|
||||
describe.current.tags("headless");
|
||||
|
||||
const parser = new CalendarArchParser();
|
||||
const DEFAULT_ARCH_RESULTS = {
|
||||
canCreate: true,
|
||||
canDelete: true,
|
||||
canEdit: true,
|
||||
eventLimit: 5,
|
||||
fieldMapping: {
|
||||
date_start: "start_date",
|
||||
},
|
||||
fieldNames: ["start_date"],
|
||||
filtersInfo: {},
|
||||
formViewId: false,
|
||||
hasEditDialog: false,
|
||||
quickCreate: true,
|
||||
quickCreateViewId: null,
|
||||
isDateHidden: false,
|
||||
isTimeHidden: false,
|
||||
popoverFieldNodes: {},
|
||||
scale: "week",
|
||||
scales: ["day", "week", "month", "year"],
|
||||
showUnusualDays: false,
|
||||
};
|
||||
|
||||
function parseArch(arch) {
|
||||
return parser.parse(arch, { fake: { fields: FAKE_FIELDS } }, "fake");
|
||||
}
|
||||
|
||||
function parseWith(attrs) {
|
||||
const str = Object.entries(attrs)
|
||||
.map(([k, v]) => `${k}="${v}"`)
|
||||
.join(" ");
|
||||
return parseArch(`<calendar date_start="start_date" ${str}/>`);
|
||||
}
|
||||
|
||||
test(`throw if date_start is not set`, () => {
|
||||
expect(() => parseArch(`<calendar/>`)).toThrow(
|
||||
`Calendar view has not defined "date_start" attribute.`
|
||||
);
|
||||
});
|
||||
|
||||
test(`defaults`, () => {
|
||||
expect(parseArch(`<calendar date_start="start_date"/>`)).toEqual(DEFAULT_ARCH_RESULTS);
|
||||
});
|
||||
|
||||
test("canCreate", () => {
|
||||
expect(parseWith({ create: "" }).canCreate).toBe(true);
|
||||
|
||||
expect(parseWith({ create: "true" }).canCreate).toBe(true);
|
||||
expect(parseWith({ create: "True" }).canCreate).toBe(true);
|
||||
expect(parseWith({ create: "1" }).canCreate).toBe(true);
|
||||
|
||||
expect(parseWith({ create: "false" }).canCreate).toBe(false);
|
||||
expect(parseWith({ create: "False" }).canCreate).toBe(false);
|
||||
expect(parseWith({ create: "0" }).canCreate).toBe(false);
|
||||
});
|
||||
|
||||
test("canDelete", () => {
|
||||
expect(parseWith({ delete: "" }).canDelete).toBe(true);
|
||||
|
||||
expect(parseWith({ delete: "true" }).canDelete).toBe(true);
|
||||
expect(parseWith({ delete: "True" }).canDelete).toBe(true);
|
||||
expect(parseWith({ delete: "1" }).canDelete).toBe(true);
|
||||
|
||||
expect(parseWith({ delete: "false" }).canDelete).toBe(false);
|
||||
expect(parseWith({ delete: "False" }).canDelete).toBe(false);
|
||||
expect(parseWith({ delete: "0" }).canDelete).toBe(false);
|
||||
});
|
||||
|
||||
test("canEdit", () => {
|
||||
expect(parseWith({ edit: "" }).canEdit).toBe(true);
|
||||
|
||||
expect(parseWith({ edit: "true" }).canEdit).toBe(true);
|
||||
expect(parseWith({ edit: "True" }).canEdit).toBe(true);
|
||||
expect(parseWith({ edit: "1" }).canEdit).toBe(true);
|
||||
|
||||
expect(parseWith({ edit: "false" }).canEdit).toBe(false);
|
||||
expect(parseWith({ edit: "False" }).canEdit).toBe(false);
|
||||
expect(parseWith({ edit: "0" }).canEdit).toBe(false);
|
||||
});
|
||||
|
||||
test("eventLimit", () => {
|
||||
expect(parseWith({ event_limit: "2" }).eventLimit).toBe(2);
|
||||
expect(parseWith({ event_limit: "5" }).eventLimit).toBe(5);
|
||||
|
||||
expect(() => parseWith({ event_limit: "five" })).toThrow();
|
||||
expect(() => parseWith({ event_limit: "" })).toThrow();
|
||||
});
|
||||
|
||||
test("hasEditDialog", () => {
|
||||
expect(parseWith({ event_open_popup: "" }).hasEditDialog).toBe(false);
|
||||
|
||||
expect(parseWith({ event_open_popup: "true" }).hasEditDialog).toBe(true);
|
||||
expect(parseWith({ event_open_popup: "True" }).hasEditDialog).toBe(true);
|
||||
expect(parseWith({ event_open_popup: "1" }).hasEditDialog).toBe(true);
|
||||
|
||||
expect(parseWith({ event_open_popup: "false" }).hasEditDialog).toBe(false);
|
||||
expect(parseWith({ event_open_popup: "False" }).hasEditDialog).toBe(false);
|
||||
expect(parseWith({ event_open_popup: "0" }).hasEditDialog).toBe(false);
|
||||
});
|
||||
|
||||
test("quickCreate", () => {
|
||||
expect(parseWith({ quick_create: "" }).quickCreate).toBe(true);
|
||||
|
||||
expect(parseWith({ quick_create: "true" }).quickCreate).toBe(true);
|
||||
expect(parseWith({ quick_create: "True" }).quickCreate).toBe(true);
|
||||
expect(parseWith({ quick_create: "1" }).quickCreate).toBe(true);
|
||||
|
||||
expect(parseWith({ quick_create: "false" }).quickCreate).toBe(false);
|
||||
expect(parseWith({ quick_create: "False" }).quickCreate).toBe(false);
|
||||
expect(parseWith({ quick_create: "0" }).quickCreate).toBe(false);
|
||||
|
||||
expect(parseWith({ quick_create: "12" }).quickCreate).toBe(true);
|
||||
});
|
||||
|
||||
test("quickCreateViewId", () => {
|
||||
expect(parseWith({ quick_create: "0", quick_create_view_id: "12" })).toEqual({
|
||||
...DEFAULT_ARCH_RESULTS,
|
||||
quickCreate: false,
|
||||
quickCreateViewId: null,
|
||||
});
|
||||
expect(parseWith({ quick_create: "1", quick_create_view_id: "12" })).toEqual({
|
||||
...DEFAULT_ARCH_RESULTS,
|
||||
quickCreate: true,
|
||||
quickCreateViewId: 12,
|
||||
});
|
||||
expect(parseWith({ quick_create: "1" })).toEqual({
|
||||
...DEFAULT_ARCH_RESULTS,
|
||||
quickCreate: true,
|
||||
quickCreateViewId: null,
|
||||
});
|
||||
});
|
||||
|
||||
test("isDateHidden", () => {
|
||||
expect(parseWith({ hide_date: "" }).isDateHidden).toBe(false);
|
||||
|
||||
expect(parseWith({ hide_date: "true" }).isDateHidden).toBe(true);
|
||||
expect(parseWith({ hide_date: "True" }).isDateHidden).toBe(true);
|
||||
expect(parseWith({ hide_date: "1" }).isDateHidden).toBe(true);
|
||||
|
||||
expect(parseWith({ hide_date: "false" }).isDateHidden).toBe(false);
|
||||
expect(parseWith({ hide_date: "False" }).isDateHidden).toBe(false);
|
||||
expect(parseWith({ hide_date: "0" }).isDateHidden).toBe(false);
|
||||
});
|
||||
|
||||
test("isTimeHidden", () => {
|
||||
expect(parseWith({ hide_time: "" }).isTimeHidden).toBe(false);
|
||||
|
||||
expect(parseWith({ hide_time: "true" }).isTimeHidden).toBe(true);
|
||||
expect(parseWith({ hide_time: "True" }).isTimeHidden).toBe(true);
|
||||
expect(parseWith({ hide_time: "1" }).isTimeHidden).toBe(true);
|
||||
|
||||
expect(parseWith({ hide_time: "false" }).isTimeHidden).toBe(false);
|
||||
expect(parseWith({ hide_time: "False" }).isTimeHidden).toBe(false);
|
||||
expect(parseWith({ hide_time: "0" }).isTimeHidden).toBe(false);
|
||||
});
|
||||
|
||||
test("scale", () => {
|
||||
expect(parseWith({ mode: "day" }).scale).toBe("day");
|
||||
expect(parseWith({ mode: "week" }).scale).toBe("week");
|
||||
expect(parseWith({ mode: "month" }).scale).toBe("month");
|
||||
expect(parseWith({ mode: "year" }).scale).toBe("year");
|
||||
|
||||
expect(() => parseWith({ mode: "" })).toThrow(`Calendar view cannot display mode: `);
|
||||
expect(() => parseWith({ mode: "other" })).toThrow(`Calendar view cannot display mode: other`);
|
||||
});
|
||||
|
||||
test("scales", () => {
|
||||
expect(parseWith({ scales: "" }).scales).toEqual([]);
|
||||
|
||||
expect(parseWith({ scales: "day" }).scales).toEqual(["day"]);
|
||||
expect(parseWith({ scales: "day,week" }).scales).toEqual(["day", "week"]);
|
||||
expect(parseWith({ scales: "day,week,month" }).scales).toEqual(["day", "week", "month"]);
|
||||
expect(parseWith({ scales: "day,week,month,year" }).scales).toEqual([
|
||||
"day",
|
||||
"week",
|
||||
"month",
|
||||
"year",
|
||||
]);
|
||||
expect(parseWith({ scales: "week" }).scales).toEqual(["week"]);
|
||||
expect(parseWith({ scales: "week,month" }).scales).toEqual(["week", "month"]);
|
||||
expect(parseWith({ scales: "week,month,year" }).scales).toEqual(["week", "month", "year"]);
|
||||
expect(parseWith({ scales: "month" }).scales).toEqual(["month"]);
|
||||
expect(parseWith({ scales: "month,year" }).scales).toEqual(["month", "year"]);
|
||||
expect(parseWith({ scales: "year" }).scales).toEqual(["year"]);
|
||||
expect(parseWith({ scales: "year,day,month,week" }).scales).toEqual([
|
||||
"year",
|
||||
"day",
|
||||
"month",
|
||||
"week",
|
||||
]);
|
||||
|
||||
expect(() =>
|
||||
parseArch(`<calendar date_start="start_date" scales="month" mode="day"/>`)
|
||||
).toThrow();
|
||||
});
|
||||
|
||||
test("showUnusualDays", () => {
|
||||
expect(parseWith({ show_unusual_days: "" }).showUnusualDays).toBe(false);
|
||||
|
||||
expect(parseWith({ show_unusual_days: "true" }).showUnusualDays).toBe(true);
|
||||
expect(parseWith({ show_unusual_days: "True" }).showUnusualDays).toBe(true);
|
||||
expect(parseWith({ show_unusual_days: "1" }).showUnusualDays).toBe(true);
|
||||
|
||||
expect(parseWith({ show_unusual_days: "false" }).showUnusualDays).toBe(false);
|
||||
expect(parseWith({ show_unusual_days: "False" }).showUnusualDays).toBe(false);
|
||||
expect(parseWith({ show_unusual_days: "0" }).showUnusualDays).toBe(false);
|
||||
});
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { click } from "@odoo/hoot-dom";
|
||||
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { DEFAULT_DATE, FAKE_MODEL } from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarCommonPopover } from "@web/views/calendar/calendar_common/calendar_common_popover";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
const FAKE_RECORD = {
|
||||
id: 5,
|
||||
title: "Meeting",
|
||||
isAllDay: false,
|
||||
start: DEFAULT_DATE,
|
||||
end: DEFAULT_DATE.plus({ hours: 3, minutes: 15 }),
|
||||
colorIndex: 0,
|
||||
isTimeHidden: false,
|
||||
rawRecord: {
|
||||
name: "Meeting",
|
||||
},
|
||||
};
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
record: FAKE_RECORD,
|
||||
createRecord() {},
|
||||
deleteRecord() {},
|
||||
editRecord() {},
|
||||
close() {},
|
||||
};
|
||||
|
||||
async function start(props = {}) {
|
||||
await mountWithCleanup(CalendarCommonPopover, {
|
||||
props: { ...FAKE_PROPS, ...props },
|
||||
});
|
||||
}
|
||||
|
||||
test(`mount a CalendarCommonPopover`, async () => {
|
||||
await start();
|
||||
expect(`.popover-header`).toHaveCount(1);
|
||||
expect(`.popover-header`).toHaveText("Meeting");
|
||||
expect(`.list-group`).toHaveCount(2);
|
||||
expect(`.list-group.o_cw_popover_fields_secondary`).toHaveCount(1);
|
||||
expect(`.card-footer .o_cw_popover_edit`).toHaveCount(1);
|
||||
expect(`.card-footer .o_cw_popover_delete`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`date duration: is all day and is same day`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, isAllDay: true, isTimeHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("July 16, 2021");
|
||||
});
|
||||
|
||||
test(`date duration: is all day and two days duration`, async () => {
|
||||
await start({
|
||||
record: {
|
||||
...FAKE_RECORD,
|
||||
end: DEFAULT_DATE.plus({ days: 1 }),
|
||||
isAllDay: true,
|
||||
isTimeHidden: true,
|
||||
},
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("July 16-17, 2021 2 days");
|
||||
});
|
||||
|
||||
test(`time duration: 1 hour diff`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, end: DEFAULT_DATE.plus({ hours: 1 }) },
|
||||
model: { ...FAKE_MODEL, isDateHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("08:00 - 09:00 (1 hour)");
|
||||
});
|
||||
|
||||
test(`time duration: 2 hours diff`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, end: DEFAULT_DATE.plus({ hours: 2 }) },
|
||||
model: { ...FAKE_MODEL, isDateHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("08:00 - 10:00 (2 hours)");
|
||||
});
|
||||
|
||||
test(`time duration: 1 minute diff`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, end: DEFAULT_DATE.plus({ minutes: 1 }) },
|
||||
model: { ...FAKE_MODEL, isDateHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("08:00 - 08:01 (1 minute)");
|
||||
});
|
||||
|
||||
test(`time duration: 2 minutes diff`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, end: DEFAULT_DATE.plus({ minutes: 2 }) },
|
||||
model: { ...FAKE_MODEL, isDateHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("08:00 - 08:02 (2 minutes)");
|
||||
});
|
||||
|
||||
test(`time duration: 3 hours and 15 minutes diff`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, isDateHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("08:00 - 11:15 (3 hours, 15 minutes)");
|
||||
});
|
||||
|
||||
test(`isDateHidden is true`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, isDateHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("08:00 - 11:15 (3 hours, 15 minutes)");
|
||||
});
|
||||
|
||||
test(`isDateHidden is false`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, isDateHidden: false },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("July 16, 2021\n08:00 - 11:15 (3 hours, 15 minutes)");
|
||||
});
|
||||
|
||||
test(`isTimeHidden is true`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, isTimeHidden: true },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("July 16, 2021");
|
||||
});
|
||||
|
||||
test(`isTimeHidden is false`, async () => {
|
||||
await start({
|
||||
record: { ...FAKE_RECORD, isTimeHidden: false },
|
||||
});
|
||||
expect(`.list-group:eq(0)`).toHaveText("July 16, 2021\n08:00 - 11:15 (3 hours, 15 minutes)");
|
||||
});
|
||||
|
||||
test(`canDelete is true`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, canDelete: true },
|
||||
});
|
||||
expect(`.o_cw_popover_delete`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`canDelete is false`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, canDelete: false },
|
||||
});
|
||||
expect(`.o_cw_popover_delete`).toHaveCount(0);
|
||||
});
|
||||
|
||||
test(`click on delete button`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, canDelete: true },
|
||||
deleteRecord: () => expect.step("delete"),
|
||||
});
|
||||
await click(`.o_cw_popover_delete`);
|
||||
expect.verifySteps(["delete"]);
|
||||
});
|
||||
|
||||
test(`click on edit button`, async () => {
|
||||
await start({
|
||||
editRecord: () => expect.step("edit"),
|
||||
});
|
||||
await click(`.o_cw_popover_edit`);
|
||||
expect.verifySteps(["edit"]);
|
||||
});
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
import { beforeEach, expect, test } from "@odoo/hoot";
|
||||
import { queryAllTexts, queryFirst, queryRect } from "@odoo/hoot-dom";
|
||||
import { runAllTimers } from "@odoo/hoot-mock";
|
||||
import { mockService, mountWithCleanup, preloadBundle } from "@web/../tests/web_test_helpers";
|
||||
import {
|
||||
DEFAULT_DATE,
|
||||
FAKE_MODEL,
|
||||
clickAllDaySlot,
|
||||
clickEvent,
|
||||
selectTimeRange,
|
||||
} from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarCommonRenderer } from "@web/views/calendar/calendar_common/calendar_common_renderer";
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
createRecord() {},
|
||||
deleteRecord() {},
|
||||
editRecord() {},
|
||||
displayName: "Plop",
|
||||
};
|
||||
|
||||
async function start(props = {}, target) {
|
||||
await mountWithCleanup(CalendarCommonRenderer, {
|
||||
props: { ...FAKE_PROPS, ...props },
|
||||
target,
|
||||
});
|
||||
}
|
||||
|
||||
preloadBundle("web.fullcalendar_lib");
|
||||
beforeEach(() => {
|
||||
luxon.Settings.defaultZone = "UTC+1";
|
||||
});
|
||||
|
||||
test(`mount a CalendarCommonRenderer`, async () => {
|
||||
await start();
|
||||
expect(`.o_calendar_widget.fc`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`Day: mount a CalendarCommonRenderer`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "day" } });
|
||||
expect(`.o_calendar_widget.fc .fc-timeGridDay-view`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`Week: mount a CalendarCommonRenderer`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "week" } });
|
||||
expect(`.o_calendar_widget.fc .fc-timeGridWeek-view`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`Month: mount a CalendarCommonRenderer`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "month" } });
|
||||
expect(`.o_calendar_widget.fc .fc-dayGridMonth-view`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`Day: check week number`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "day" } });
|
||||
expect(`[aria-label^="Week "]`).toHaveCount(1);
|
||||
expect(`[aria-label^="Week "]`).toHaveText(/(Week )?28/);
|
||||
});
|
||||
|
||||
test(`Day: check date`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "day" } });
|
||||
expect(`.fc-col-header-cell.fc-day`).toHaveCount(1);
|
||||
expect(`.fc-col-header-cell.fc-day:eq(0) .o_cw_day_name`).toHaveText("Friday");
|
||||
expect(`.fc-col-header-cell.fc-day:eq(0) .o_cw_day_number`).toHaveText("16");
|
||||
});
|
||||
|
||||
test(`Day: click all day slot`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, scale: "day" },
|
||||
createRecord(record) {
|
||||
expect.step("create");
|
||||
expect(record.isAllDay).toBe(true);
|
||||
expect(record.start.valueOf()).toBe(DEFAULT_DATE.startOf("day").valueOf());
|
||||
},
|
||||
});
|
||||
await clickAllDaySlot("2021-07-16");
|
||||
expect.verifySteps(["create"]);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test(`Day: select range`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, scale: "day" },
|
||||
createRecord(record) {
|
||||
expect.step("create");
|
||||
expect(record.isAllDay).toBe(false);
|
||||
expect(record.start.valueOf()).toBe(luxon.DateTime.local(2021, 7, 16, 8, 0).valueOf());
|
||||
expect(record.end.valueOf()).toBe(luxon.DateTime.local(2021, 7, 16, 10, 0).valueOf());
|
||||
},
|
||||
});
|
||||
await selectTimeRange("2021-07-16 08:00:00", "2021-07-16 10:00:00");
|
||||
expect.verifySteps(["create"]);
|
||||
});
|
||||
|
||||
test(`Day: check event`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "day" } });
|
||||
expect(`.o_event`).toHaveCount(1);
|
||||
expect(`.o_event`).toHaveAttribute("data-event-id", "1");
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test(`Day: click on event`, async () => {
|
||||
mockService("popover", () => ({
|
||||
add(target, component, { record }) {
|
||||
expect.step("popover");
|
||||
expect(record.id).toBe(1);
|
||||
return () => {};
|
||||
},
|
||||
}));
|
||||
await start({ model: { ...FAKE_MODEL, scale: "day" } });
|
||||
await clickEvent(1);
|
||||
await runAllTimers();
|
||||
expect.verifySteps(["popover"]);
|
||||
});
|
||||
|
||||
test(`Week: check week number`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "week" } });
|
||||
expect(`.fc-scrollgrid-section-header .fc-timegrid-axis-cushion`).toHaveCount(1);
|
||||
expect(`.fc-scrollgrid-section-header .fc-timegrid-axis-cushion`).toHaveText(/(Week )?28/);
|
||||
});
|
||||
|
||||
test(`Week: check dates`, async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "week" } });
|
||||
expect(`.fc-col-header-cell.fc-day`).toHaveCount(7);
|
||||
expect(queryAllTexts(`.fc-col-header-cell .o_cw_day_name`)).toEqual([
|
||||
"Sun",
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
"Thu",
|
||||
"Fri",
|
||||
"Sat",
|
||||
]);
|
||||
expect(queryAllTexts`.fc-col-header-cell .o_cw_day_number`).toEqual([
|
||||
"11",
|
||||
"12",
|
||||
"13",
|
||||
"14",
|
||||
"15",
|
||||
"16",
|
||||
"17",
|
||||
]);
|
||||
});
|
||||
|
||||
test(`Day: automatically scroll to 6am`, async () => {
|
||||
await mountWithCleanup(`<div class="scrollable" style="height: 500px;"/>`);
|
||||
await start({ model: { ...FAKE_MODEL, scale: "day" } }, queryFirst(`.scrollable`));
|
||||
|
||||
const containerDimensions = queryRect(`.fc-scrollgrid-section-liquid .fc-scroller`);
|
||||
const dayStartDimensions = queryRect(`.fc-timegrid-slot[data-time="06:00:00"]:eq(0)`);
|
||||
expect(Math.abs(dayStartDimensions.y - containerDimensions.y)).toBeLessThan(2);
|
||||
});
|
||||
|
||||
test(`Week: automatically scroll to 6am`, async () => {
|
||||
await mountWithCleanup(`<div class="scrollable" style="height: 500px;"/>`);
|
||||
await start({ model: { ...FAKE_MODEL, scale: "week" } }, queryFirst(`.scrollable`));
|
||||
|
||||
const containerDimensions = queryRect(`.fc-scrollgrid-section-liquid .fc-scroller`);
|
||||
const dayStartDimensions = queryRect(`.fc-timegrid-slot[data-time="06:00:00"]:eq(0)`);
|
||||
expect(Math.abs(dayStartDimensions.y - containerDimensions.y)).toBeLessThan(2);
|
||||
});
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
import { beforeEach, describe, expect, test } from "@odoo/hoot";
|
||||
import { queryAllTexts } from "@odoo/hoot-dom";
|
||||
import { mockDate } from "@odoo/hoot-mock";
|
||||
import {
|
||||
contains,
|
||||
defineModels,
|
||||
defineParams,
|
||||
fields,
|
||||
findComponent,
|
||||
models,
|
||||
mountView,
|
||||
patchWithCleanup,
|
||||
preloadBundle,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
|
||||
import { CalendarController } from "@web/views/calendar/calendar_controller";
|
||||
import { changeScale } from "./calendar_test_helpers";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
class Event extends models.Model {
|
||||
name = fields.Char();
|
||||
start = fields.Date();
|
||||
|
||||
has_access() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
defineModels([Event]);
|
||||
preloadBundle("web.fullcalendar_lib");
|
||||
beforeEach(() => {
|
||||
mockDate("2021-08-14T08:00:00");
|
||||
});
|
||||
|
||||
test(`Mount a CalendarDatePicker`, async () => {
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="day"/>`,
|
||||
});
|
||||
expect(`.o_datetime_picker`).toHaveCount(1);
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveCount(1);
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveText("14");
|
||||
expect(`.o_datetime_picker_header .o_datetime_button`).toHaveText("August 2021");
|
||||
expect(queryAllTexts`.o_datetime_picker .o_day_of_week_cell`).toEqual([
|
||||
"S",
|
||||
"M",
|
||||
"T",
|
||||
"W",
|
||||
"T",
|
||||
"F",
|
||||
"S",
|
||||
]);
|
||||
});
|
||||
|
||||
test(`Scale: init with day`, async () => {
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="day"/>`,
|
||||
});
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveCount(1);
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveText("14");
|
||||
});
|
||||
|
||||
test(`Scale: init with week`, async () => {
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="week"/>`,
|
||||
});
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveCount(1);
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveText("14");
|
||||
});
|
||||
|
||||
test(`Scale: init with month`, async () => {
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="month"/>`,
|
||||
});
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveCount(1);
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveText("14");
|
||||
});
|
||||
|
||||
test(`Scale: init with year`, async () => {
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="year"/>`,
|
||||
});
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveCount(1);
|
||||
expect(`.o_datetime_picker .o_selected`).toHaveText("14");
|
||||
});
|
||||
|
||||
test(`First day: 0 = Sunday`, async () => {
|
||||
// the week start depends on the locale
|
||||
defineParams({
|
||||
lang_parameters: { week_start: 0 },
|
||||
});
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="day"/>`,
|
||||
});
|
||||
expect(queryAllTexts`.o_datetime_picker .o_day_of_week_cell`).toEqual([
|
||||
"S",
|
||||
"M",
|
||||
"T",
|
||||
"W",
|
||||
"T",
|
||||
"F",
|
||||
"S",
|
||||
]);
|
||||
});
|
||||
|
||||
test(`First day: 1 = Monday`, async () => {
|
||||
// the week start depends on the locale
|
||||
defineParams({
|
||||
lang_parameters: { week_start: 1 },
|
||||
});
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="day"/>`,
|
||||
});
|
||||
expect(queryAllTexts`.o_datetime_picker .o_day_of_week_cell`).toEqual([
|
||||
"M",
|
||||
"T",
|
||||
"W",
|
||||
"T",
|
||||
"F",
|
||||
"S",
|
||||
"S",
|
||||
]);
|
||||
});
|
||||
|
||||
test(`Click on active day should change scale : day -> month`, async () => {
|
||||
const view = await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="day"/>`,
|
||||
});
|
||||
const calendar = findComponent(view, (component) => component instanceof CalendarController);
|
||||
await contains(`.o_datetime_picker .o_selected`).click();
|
||||
expect(calendar.model.scale).toBe("month");
|
||||
expect(calendar.model.date.valueOf()).toBe(luxon.DateTime.local(2021, 8, 14).valueOf());
|
||||
});
|
||||
|
||||
test(`Click on active day should change scale : month -> week`, async () => {
|
||||
const view = await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="month"/>`,
|
||||
});
|
||||
const calendar = findComponent(view, (component) => component instanceof CalendarController);
|
||||
await contains(`.o_datetime_picker .o_selected`).click();
|
||||
expect(calendar.model.scale).toBe("week");
|
||||
expect(calendar.model.date.valueOf()).toBe(luxon.DateTime.local(2021, 8, 14).valueOf());
|
||||
});
|
||||
|
||||
test(`Click on active day should change scale : week -> day`, async () => {
|
||||
const view = await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="week"/>`,
|
||||
});
|
||||
const calendar = findComponent(view, (component) => component instanceof CalendarController);
|
||||
await contains(`.o_datetime_picker .o_selected`).click();
|
||||
expect(calendar.model.scale).toBe("day");
|
||||
expect(calendar.model.date.valueOf()).toBe(luxon.DateTime.local(2021, 8, 14).valueOf());
|
||||
});
|
||||
|
||||
test(`Scale: today is correctly highlighted`, async () => {
|
||||
mockDate("2021-07-04T08:00:00");
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start" mode="month"/>`,
|
||||
});
|
||||
expect(`.o_datetime_picker .o_today`).toHaveClass("o_selected");
|
||||
expect(`.o_datetime_picker .o_today`).toHaveText("4");
|
||||
});
|
||||
|
||||
test(`Scale: scale default is fetched from sessionStorage`, async () => {
|
||||
patchWithCleanup(sessionStorage, {
|
||||
setItem(key, value) {
|
||||
if (key === "calendar-scale") {
|
||||
expect.step(`scale_${value}`);
|
||||
}
|
||||
},
|
||||
getItem(key) {
|
||||
if (key === "calendar-scale") {
|
||||
return "month";
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await mountView({
|
||||
resModel: "event",
|
||||
type: "calendar",
|
||||
arch: `<calendar date_start="start"/>`,
|
||||
});
|
||||
expect(`.scale_button_selection`).toHaveText("Month");
|
||||
|
||||
await changeScale("year");
|
||||
expect(`.scale_button_selection`).toHaveText("Year");
|
||||
expect.verifySteps(["scale_year"]);
|
||||
});
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { click, queryAllTexts } from "@odoo/hoot-dom";
|
||||
import { contains, mountWithCleanup, preloadBundle } from "@web/../tests/web_test_helpers";
|
||||
import { FAKE_MODEL } from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarFilterPanel } from "@web/views/calendar/filter_panel/calendar_filter_panel";
|
||||
import { runAllTimers } from "@odoo/hoot-mock";
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
};
|
||||
|
||||
async function start(props = {}) {
|
||||
await mountWithCleanup(CalendarFilterPanel, {
|
||||
props: { ...FAKE_PROPS, ...props },
|
||||
});
|
||||
}
|
||||
|
||||
preloadBundle("web.fullcalendar_lib");
|
||||
|
||||
test(`render filter panel`, async () => {
|
||||
await start({});
|
||||
expect(`.o_calendar_filter`).toHaveCount(2);
|
||||
expect(`.o_calendar_filter:eq(0) .o_cw_filter_label`).toHaveText("Attendees");
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item`).toHaveCount(4);
|
||||
expect(`.o_calendar_filter:eq(1) .o_cw_filter_label`).toHaveText("Users");
|
||||
expect(`.o_calendar_filter:eq(1) .o_calendar_filter_item`).toHaveCount(2);
|
||||
});
|
||||
|
||||
test(`filters are correctly sorted`, async () => {
|
||||
await start({});
|
||||
expect(queryAllTexts`.o_calendar_filter:eq(0) .o_calendar_filter_item`).toEqual([
|
||||
"Mitchell Admin",
|
||||
"Brandon Freeman",
|
||||
"Marc Demo",
|
||||
"Everybody's calendar",
|
||||
]);
|
||||
expect(queryAllTexts`.o_calendar_filter:eq(1) .o_calendar_filter_item`).toEqual([
|
||||
"Brandon Freeman",
|
||||
"Marc Demo",
|
||||
]);
|
||||
});
|
||||
|
||||
test(`section can collapse`, async () => {
|
||||
await start({});
|
||||
expect(`.o_calendar_filter:eq(0) .o_cw_filter_collapse_icon`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item`).toHaveCount(4);
|
||||
|
||||
await contains(`.o_calendar_filter:eq(0) .o_cw_filter_label`).click();
|
||||
await runAllTimers();
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item`).toHaveCount(0);
|
||||
|
||||
await contains(`.o_calendar_filter:eq(0) .o_cw_filter_label`).click();
|
||||
await runAllTimers();
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item`).toHaveCount(4);
|
||||
});
|
||||
|
||||
test(`section cannot collapse`, async () => {
|
||||
await start({});
|
||||
expect(`.o_calendar_filter:eq(1) .o_cw_filter_label > i`).toHaveCount(0);
|
||||
expect(`.o_calendar_filter:eq(1)`).not.toHaveClass("o_calendar_filter-collapsed");
|
||||
expect(`.o_calendar_filter:eq(1) .o_calendar_filter_item`).toHaveCount(2);
|
||||
|
||||
await contains(`.o_calendar_filter:eq(1) .o_cw_filter_label`).click();
|
||||
await runAllTimers();
|
||||
expect(`.o_calendar_filter:eq(1)`).not.toHaveClass("o_calendar_filter-collapsed");
|
||||
expect(`.o_calendar_filter:eq(1) .o_calendar_filter_item`).toHaveCount(2);
|
||||
});
|
||||
|
||||
test(`filters can have avatar`, async () => {
|
||||
await start({});
|
||||
expect(`.o_calendar_filter:eq(0) .o_cw_filter_avatar`).toHaveCount(4);
|
||||
expect(`.o_calendar_filter:eq(0) img.o_cw_filter_avatar`).toHaveCount(3);
|
||||
expect(`.o_calendar_filter:eq(0) i.o_cw_filter_avatar`).toHaveCount(1);
|
||||
expect(
|
||||
`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(0) .o_cw_filter_avatar`
|
||||
).toHaveAttribute("data-src", "/web/image/res.partner/3/avatar_128");
|
||||
expect(
|
||||
`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(1) .o_cw_filter_avatar`
|
||||
).toHaveAttribute("data-src", "/web/image/res.partner/4/avatar_128");
|
||||
expect(
|
||||
`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(2) .o_cw_filter_avatar`
|
||||
).toHaveAttribute("data-src", "/web/image/res.partner/6/avatar_128");
|
||||
});
|
||||
|
||||
test(`filters cannot have avatar`, async () => {
|
||||
await start({});
|
||||
expect(`.o_calendar_filter:eq(1) .o_calendar_filter_item`).toHaveCount(2);
|
||||
expect(`.o_calendar_filter:eq(1) .o_cw_filter_avatar`).toHaveCount(0);
|
||||
});
|
||||
|
||||
test(`filter can have remove button`, async () => {
|
||||
await start({});
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item`).toHaveCount(4);
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item .o_remove`).toHaveCount(2);
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(0) .o_remove`).toHaveCount(0);
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(1) .o_remove`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(2) .o_remove`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(3) .o_remove`).toHaveCount(0);
|
||||
});
|
||||
|
||||
test(`click on remove button`, async () => {
|
||||
await start({
|
||||
model: {
|
||||
...FAKE_MODEL,
|
||||
unlinkFilter(fieldName, recordId) {
|
||||
expect.step(`${fieldName} ${recordId}`);
|
||||
},
|
||||
},
|
||||
});
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(1) .o_remove`);
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(2) .o_remove`);
|
||||
expect.verifySteps(["partner_ids 1", "partner_ids 2"]);
|
||||
});
|
||||
|
||||
test(`click on filter`, async () => {
|
||||
await start({
|
||||
model: {
|
||||
...FAKE_MODEL,
|
||||
updateFilters(fieldName, args) {
|
||||
expect.step(`${fieldName} ${Object.keys(args)[0]} ${Object.values(args)[0]}`);
|
||||
},
|
||||
},
|
||||
});
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(0) input`);
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(1) input`);
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(2) input`);
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(3) input`);
|
||||
await click(`.o_calendar_filter:eq(0) .o_calendar_filter_item:eq(3) input`);
|
||||
expect.verifySteps([
|
||||
"partner_ids 3 false",
|
||||
"partner_ids 4 false",
|
||||
"partner_ids 6 true",
|
||||
"partner_ids all true",
|
||||
"partner_ids all false",
|
||||
]);
|
||||
});
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { waitFor } from "@odoo/hoot-dom";
|
||||
import {
|
||||
contains,
|
||||
getService,
|
||||
mountWithCleanup,
|
||||
preloadBundle,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
import { FAKE_MODEL } from "./calendar_test_helpers";
|
||||
|
||||
import { MainComponentsContainer } from "@web/core/main_components_container";
|
||||
import { CalendarQuickCreate } from "@web/views/calendar/quick_create/calendar_quick_create";
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
record: {},
|
||||
editRecord() {},
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* props?: object;
|
||||
* dialogOptions?: import("@web/core/dialog/dialog_service").DialogServiceInterfaceAddOptions;
|
||||
* }} [params]
|
||||
*/
|
||||
async function start(params = {}) {
|
||||
await mountWithCleanup(MainComponentsContainer);
|
||||
getService("dialog").add(
|
||||
CalendarQuickCreate,
|
||||
{ ...FAKE_PROPS, ...params.props },
|
||||
params.dialogOptions
|
||||
);
|
||||
await waitFor(`.o_dialog`);
|
||||
}
|
||||
|
||||
preloadBundle("web.fullcalendar_lib");
|
||||
|
||||
test.tags("desktop");
|
||||
test(`mount a CalendarQuickCreate`, async () => {
|
||||
await start();
|
||||
expect(`.o-calendar-quick-create`).toHaveCount(1);
|
||||
expect(`.o_dialog .modal-sm`).toHaveCount(1);
|
||||
expect(`.modal-title`).toHaveText("New Event");
|
||||
expect(`input[name="title"]`).toBeFocused();
|
||||
expect(`.o-calendar-quick-create--create-btn`).toHaveCount(1);
|
||||
expect(`.o-calendar-quick-create--edit-btn`).toHaveCount(1);
|
||||
expect(`.o-calendar-quick-create--cancel-btn`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`click on create button`, async () => {
|
||||
await start({
|
||||
props: {
|
||||
model: { ...FAKE_MODEL, createRecord: () => expect.step("create") },
|
||||
},
|
||||
dialogOptions: { onClose: () => expect.step("close") },
|
||||
});
|
||||
await contains(`.o-calendar-quick-create--create-btn`).click();
|
||||
expect.verifySteps([]);
|
||||
expect(`input[name=title]`).toHaveClass("o_field_invalid");
|
||||
});
|
||||
|
||||
test(`click on create button (with name)`, async () => {
|
||||
await start({
|
||||
props: {
|
||||
model: {
|
||||
...FAKE_MODEL,
|
||||
createRecord(record) {
|
||||
expect.step("create");
|
||||
expect(record.title).toBe("TEST");
|
||||
},
|
||||
},
|
||||
},
|
||||
dialogOptions: { onClose: () => expect.step("close") },
|
||||
});
|
||||
await contains(`.o-calendar-quick-create--input`).edit("TEST", { confirm: "blur" });
|
||||
await contains(`.o-calendar-quick-create--create-btn`).click();
|
||||
expect.verifySteps(["create", "close"]);
|
||||
});
|
||||
|
||||
test(`click on edit button`, async () => {
|
||||
await start({
|
||||
props: { editRecord: () => expect.step("edit") },
|
||||
dialogOptions: { onClose: () => expect.step("close") },
|
||||
});
|
||||
await contains(`.o-calendar-quick-create--edit-btn`).click();
|
||||
expect.verifySteps(["edit", "close"]);
|
||||
});
|
||||
|
||||
test(`click on edit button (with name)`, async () => {
|
||||
await start({
|
||||
props: {
|
||||
editRecord(record) {
|
||||
expect.step("edit");
|
||||
expect(record.title).toBe("TEST");
|
||||
},
|
||||
},
|
||||
dialogOptions: { onClose: () => expect.step("close") },
|
||||
});
|
||||
await contains(`.o-calendar-quick-create--input`).edit("TEST", { confirm: "blur" });
|
||||
await contains(`.o-calendar-quick-create--edit-btn`).click();
|
||||
expect.verifySteps(["edit", "close"]);
|
||||
});
|
||||
|
||||
test(`click on cancel button`, async () => {
|
||||
await start({
|
||||
dialogOptions: { onClose: () => expect.step("close") },
|
||||
});
|
||||
await contains(`.o-calendar-quick-create--cancel-btn`).click();
|
||||
expect.verifySteps(["close"]);
|
||||
});
|
||||
|
||||
test(`check default title`, async () => {
|
||||
await start({
|
||||
props: { title: "Example Title" },
|
||||
});
|
||||
expect(`.o-calendar-quick-create--input`).toHaveValue("Example Title");
|
||||
});
|
||||
|
|
@ -0,0 +1,746 @@
|
|||
import { click, drag, hover, queryFirst, queryRect } from "@odoo/hoot-dom";
|
||||
import { advanceFrame, advanceTime, animationFrame } from "@odoo/hoot-mock";
|
||||
import { EventBus } from "@odoo/owl";
|
||||
import { contains, getMockEnv, swipeLeft, swipeRight } from "@web/../tests/web_test_helpers";
|
||||
|
||||
import { createElement } from "@web/core/utils/xml";
|
||||
import { Field } from "@web/views/fields/field";
|
||||
|
||||
export const DEFAULT_DATE = luxon.DateTime.local(2021, 7, 16, 8, 0, 0, 0);
|
||||
|
||||
export const FAKE_RECORDS = {
|
||||
1: {
|
||||
id: 1,
|
||||
title: "1 day, all day in July",
|
||||
start: DEFAULT_DATE,
|
||||
isAllDay: true,
|
||||
end: DEFAULT_DATE,
|
||||
},
|
||||
2: {
|
||||
id: 2,
|
||||
title: "3 days, all day in July",
|
||||
start: DEFAULT_DATE.plus({ days: 2 }),
|
||||
isAllDay: true,
|
||||
end: DEFAULT_DATE.plus({ days: 4 }),
|
||||
},
|
||||
3: {
|
||||
id: 3,
|
||||
title: "1 day, all day in June",
|
||||
start: DEFAULT_DATE.plus({ months: -1 }),
|
||||
isAllDay: true,
|
||||
end: DEFAULT_DATE.plus({ months: -1 }),
|
||||
},
|
||||
4: {
|
||||
id: 4,
|
||||
title: "3 days, all day in June",
|
||||
start: DEFAULT_DATE.plus({ months: -1, days: 2 }),
|
||||
isAllDay: true,
|
||||
end: DEFAULT_DATE.plus({ months: -1, days: 4 }),
|
||||
},
|
||||
5: {
|
||||
id: 5,
|
||||
title: "Over June and July",
|
||||
start: DEFAULT_DATE.startOf("month").plus({ days: -2 }),
|
||||
isAllDay: true,
|
||||
end: DEFAULT_DATE.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" },
|
||||
};
|
||||
|
||||
export const FAKE_MODEL = {
|
||||
bus: new EventBus(),
|
||||
canCreate: true,
|
||||
canDelete: true,
|
||||
canEdit: true,
|
||||
date: DEFAULT_DATE,
|
||||
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,
|
||||
quickCreate: false,
|
||||
popoverFieldNodes: {
|
||||
name: Field.parseFieldNode(
|
||||
createElement("field", { name: "name" }),
|
||||
{ event: { fields: FAKE_FIELDS } },
|
||||
"event",
|
||||
"calendar"
|
||||
),
|
||||
},
|
||||
activeFields: {
|
||||
name: {
|
||||
context: "{}",
|
||||
invisible: false,
|
||||
readonly: false,
|
||||
required: false,
|
||||
onChange: false,
|
||||
},
|
||||
},
|
||||
rangeEnd: DEFAULT_DATE.endOf("month"),
|
||||
rangeStart: DEFAULT_DATE.startOf("month"),
|
||||
records: FAKE_RECORDS,
|
||||
resModel: "event",
|
||||
scale: "month",
|
||||
scales: ["day", "week", "month", "year"],
|
||||
unusualDays: [],
|
||||
load() {},
|
||||
createFilter() {},
|
||||
createRecord() {},
|
||||
unlinkFilter() {},
|
||||
unlinkRecord() {},
|
||||
updateFilter() {},
|
||||
updateRecord() {},
|
||||
};
|
||||
|
||||
// DOM Utils
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
function instantScrollTo(element) {
|
||||
element.scrollIntoView({ behavior: "instant", block: "center" });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} date
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findAllDaySlot(date) {
|
||||
return queryFirst(`.fc-daygrid-body .fc-day[data-date="${date}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} date
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findDateCell(date) {
|
||||
return queryFirst(`.fc-day[data-date="${date}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findEvent(eventId) {
|
||||
return queryFirst(`.o_event[data-event-id="${eventId}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} date
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findDateColumn(date) {
|
||||
return queryFirst(`.fc-col-header-cell.fc-day[data-date="${date}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} time
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findTimeRow(time) {
|
||||
return queryFirst(`.fc-timegrid-slot[data-time="${time}"]:eq(1)`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} sectionName
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findFilterPanelSection(sectionName) {
|
||||
return queryFirst(`.o_calendar_filter[data-name="${sectionName}"]`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} sectionName
|
||||
* @param {string} filterValue
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findFilterPanelFilter(sectionName, filterValue) {
|
||||
const root = findFilterPanelSection(sectionName);
|
||||
return queryFirst(`.o_calendar_filter_item[data-value="${filterValue}"]`, { root });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} sectionName
|
||||
* @returns {HTMLElement}
|
||||
*/
|
||||
export function findFilterPanelSectionFilter(sectionName) {
|
||||
const root = findFilterPanelSection(sectionName);
|
||||
return queryFirst(`.o_calendar_filter_items_checkall`, { root });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} date
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function pickDate(date) {
|
||||
const day = date.split("-")[2];
|
||||
const iDay = parseInt(day, 10) - 1;
|
||||
await click(`.o_datetime_picker .o_date_item_cell:not(.o_out_of_range):eq(${iDay})`);
|
||||
await animationFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} date
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function clickAllDaySlot(date) {
|
||||
const slot = findAllDaySlot(date);
|
||||
|
||||
instantScrollTo(slot);
|
||||
|
||||
await click(slot);
|
||||
await animationFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} date
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function clickDate(date) {
|
||||
const cell = findDateCell(date);
|
||||
|
||||
instantScrollTo(cell);
|
||||
|
||||
await click(cell);
|
||||
await advanceTime(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function clickEvent(eventId) {
|
||||
const eventEl = findEvent(eventId);
|
||||
|
||||
instantScrollTo(eventEl);
|
||||
|
||||
await click(eventEl);
|
||||
await advanceTime(500); // wait for the popover to open (debounced)
|
||||
}
|
||||
|
||||
export function expandCalendarView() {
|
||||
// Expends Calendar view and FC too
|
||||
let tmpElement = queryFirst(".fc");
|
||||
do {
|
||||
tmpElement = tmpElement.parentElement;
|
||||
tmpElement.classList.add("h-100");
|
||||
} while (!tmpElement.classList.contains("o_view_controller"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} startDateTime
|
||||
* @param {string} endDateTime
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function selectTimeRange(startDateTime, endDateTime) {
|
||||
const [startDate, startTime] = startDateTime.split(" ");
|
||||
const [endDate, endTime] = endDateTime.split(" ");
|
||||
|
||||
// Try to display both rows on the screen before drag'n'drop.
|
||||
const startHour = Number(startTime.slice(0, 2));
|
||||
const endHour = Number(endTime.slice(0, 2));
|
||||
const midHour = Math.floor((startHour + endHour) / 2);
|
||||
const midTime = `${String(midHour).padStart(2, "0")}:00:00`;
|
||||
|
||||
instantScrollTo(
|
||||
queryFirst(`.fc-timegrid-slot[data-time="${midTime}"]:eq(1)`, { visible: false })
|
||||
);
|
||||
|
||||
const startColumnRect = queryRect(`.fc-col-header-cell.fc-day[data-date="${startDate}"]`);
|
||||
const startRow = queryFirst(`.fc-timegrid-slot[data-time="${startTime}"]:eq(1)`);
|
||||
const endColumnRect = queryRect(`.fc-col-header-cell.fc-day[data-date="${endDate}"]`);
|
||||
const endRow = queryFirst(`.fc-timegrid-slot[data-time="${endTime}"]:eq(1)`);
|
||||
const optionStart = {
|
||||
relative: true,
|
||||
position: { y: 1, x: startColumnRect.left },
|
||||
};
|
||||
|
||||
await hover(startRow, optionStart);
|
||||
await animationFrame();
|
||||
const { drop } = await drag(startRow, optionStart);
|
||||
await animationFrame();
|
||||
await drop(endRow, {
|
||||
position: { y: -1, x: endColumnRect.left },
|
||||
relative: true,
|
||||
});
|
||||
|
||||
await animationFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} startDate
|
||||
* @param {string} endDate
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function selectDateRange(startDate, endDate) {
|
||||
const startCell = findDateCell(startDate);
|
||||
const endCell = findDateCell(endDate);
|
||||
|
||||
instantScrollTo(startCell);
|
||||
|
||||
await hover(startCell);
|
||||
await animationFrame();
|
||||
|
||||
const { moveTo, drop } = await drag(startCell);
|
||||
await animationFrame();
|
||||
|
||||
await moveTo(endCell);
|
||||
await animationFrame();
|
||||
|
||||
await drop();
|
||||
await animationFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} startDate
|
||||
* @param {string} endDate
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function selectAllDayRange(startDate, endDate) {
|
||||
const start = findAllDaySlot(startDate);
|
||||
const end = findAllDaySlot(endDate);
|
||||
|
||||
instantScrollTo(start);
|
||||
|
||||
await hover(start);
|
||||
await animationFrame();
|
||||
|
||||
const { drop } = await drag(start);
|
||||
await animationFrame();
|
||||
|
||||
await drop(end);
|
||||
await animationFrame();
|
||||
}
|
||||
export async function closeCwPopOver() {
|
||||
if (getMockEnv().isSmall) {
|
||||
await contains(`.oi-arrow-left`).click();
|
||||
} else {
|
||||
await contains(`.o_cw_popover_close`).click();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @param {string} date
|
||||
* @param {{ disableDrop: boolean }} [options]
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function moveEventToDate(eventId, date, options) {
|
||||
const eventEl = findEvent(eventId);
|
||||
const cell = findDateCell(date);
|
||||
|
||||
instantScrollTo(eventEl);
|
||||
|
||||
await hover(eventEl);
|
||||
await animationFrame();
|
||||
|
||||
const { drop, moveTo } = await drag(eventEl);
|
||||
await animationFrame();
|
||||
|
||||
await moveTo(cell);
|
||||
await animationFrame();
|
||||
|
||||
if (!options?.disableDrop) {
|
||||
await drop();
|
||||
}
|
||||
|
||||
await animationFrame();
|
||||
await animationFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @param {string} dateTime
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function moveEventToTime(eventId, dateTime) {
|
||||
const eventEl = findEvent(eventId);
|
||||
const [date, time] = dateTime.split(" ");
|
||||
|
||||
instantScrollTo(eventEl);
|
||||
|
||||
const row = findTimeRow(time);
|
||||
const rowRect = queryRect(row);
|
||||
|
||||
const column = findDateColumn(date);
|
||||
const columnRect = queryRect(column);
|
||||
|
||||
const { drop, moveTo } = await drag(eventEl, {
|
||||
position: { y: 1 },
|
||||
relative: true,
|
||||
});
|
||||
|
||||
if (getMockEnv().isSmall) {
|
||||
await advanceTime(500);
|
||||
}
|
||||
|
||||
await animationFrame();
|
||||
|
||||
await moveTo(row, {
|
||||
position: {
|
||||
y: rowRect.y + 1,
|
||||
x: columnRect.x + columnRect.width / 2,
|
||||
},
|
||||
});
|
||||
await animationFrame();
|
||||
|
||||
await drop();
|
||||
await advanceFrame(5);
|
||||
}
|
||||
|
||||
export async function selectHourOnPicker(selectedValue) {
|
||||
await contains(`.o_time_picker_select:eq(0)`).select(selectedValue);
|
||||
await contains(".o_datetime_picker .o_apply").click();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @param {string} date
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function moveEventToAllDaySlot(eventId, date) {
|
||||
const eventEl = findEvent(eventId);
|
||||
const slot = findAllDaySlot(date);
|
||||
|
||||
instantScrollTo(eventEl);
|
||||
|
||||
const columnRect = queryRect(eventEl);
|
||||
const slotRect = queryRect(slot);
|
||||
|
||||
const { drop, moveTo } = await drag(eventEl, {
|
||||
position: { y: 1 },
|
||||
relative: true,
|
||||
});
|
||||
|
||||
if (getMockEnv().isSmall) {
|
||||
await advanceTime(500);
|
||||
}
|
||||
|
||||
await animationFrame();
|
||||
|
||||
await moveTo(slot, {
|
||||
position: {
|
||||
x: columnRect.x + columnRect.width / 2,
|
||||
y: slotRect.y,
|
||||
},
|
||||
});
|
||||
await animationFrame();
|
||||
|
||||
await drop();
|
||||
await advanceFrame(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @param {string} dateTime
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function resizeEventToTime(eventId, dateTime) {
|
||||
const eventEl = findEvent(eventId);
|
||||
|
||||
instantScrollTo(eventEl);
|
||||
|
||||
await hover(`.fc-event-main:first`, { root: eventEl });
|
||||
await animationFrame();
|
||||
|
||||
const resizer = queryFirst(`.fc-event-resizer-end`, { root: eventEl });
|
||||
Object.assign(resizer.style, {
|
||||
display: "block",
|
||||
height: "1px",
|
||||
bottom: "0",
|
||||
});
|
||||
|
||||
const [date, time] = dateTime.split(" ");
|
||||
|
||||
const row = findTimeRow(time);
|
||||
|
||||
const column = findDateColumn(date);
|
||||
const columnRect = queryRect(column);
|
||||
|
||||
await (
|
||||
await drag(resizer)
|
||||
).drop(row, {
|
||||
position: { x: columnRect.x, y: -1 },
|
||||
relative: true,
|
||||
});
|
||||
await advanceTime(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} eventId
|
||||
* @param {string} date
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function resizeEventToDate(eventId, date) {
|
||||
const eventEl = findEvent(eventId);
|
||||
const slot = findAllDaySlot(date);
|
||||
|
||||
instantScrollTo(eventEl);
|
||||
|
||||
await hover(".fc-event-main", { root: eventEl });
|
||||
await animationFrame();
|
||||
|
||||
// Show the resizer
|
||||
const resizer = queryFirst(".fc-event-resizer-end", { root: eventEl });
|
||||
Object.assign(resizer.style, { display: "block", height: "1px", bottom: "0" });
|
||||
|
||||
instantScrollTo(slot);
|
||||
|
||||
const rowRect = queryRect(resizer);
|
||||
|
||||
// Find the date cell and calculate the positions for dragging
|
||||
const dateCell = findDateCell(date);
|
||||
const columnRect = queryRect(dateCell);
|
||||
|
||||
// Perform the drag-and-drop operation
|
||||
await hover(resizer, {
|
||||
position: { x: 0 },
|
||||
relative: true,
|
||||
});
|
||||
await animationFrame();
|
||||
|
||||
const { drop } = await drag(resizer);
|
||||
await animationFrame();
|
||||
|
||||
await drop(dateCell, {
|
||||
position: { y: rowRect.y - columnRect.y },
|
||||
relative: true,
|
||||
});
|
||||
await advanceTime(500);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {"day" | "week" | "month" | "year"} scale
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function changeScale(scale) {
|
||||
await contains(`.o_view_scale_selector .scale_button_selection`).click();
|
||||
await contains(`.o-dropdown--menu .o_scale_button_${scale}`).click();
|
||||
}
|
||||
|
||||
export async function displayCalendarPanel() {
|
||||
if (getMockEnv().isSmall) {
|
||||
await contains(".o_calendar_container .o_other_calendar_panel").click();
|
||||
}
|
||||
}
|
||||
|
||||
export async function hideCalendarPanel() {
|
||||
if (getMockEnv().isSmall) {
|
||||
await contains(".o_calendar_container .o_other_calendar_panel").click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {"prev" | "next"} direction
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function navigate(direction) {
|
||||
if (getMockEnv().isSmall) {
|
||||
if (direction === "next") {
|
||||
await swipeLeft(".o_calendar_widget");
|
||||
} else {
|
||||
await swipeRight(".o_calendar_widget");
|
||||
}
|
||||
await advanceFrame(16);
|
||||
} else {
|
||||
await contains(`.o_calendar_navigation_buttons .o_calendar_button_${direction}`).click();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} sectionName
|
||||
* @param {string} filterValue
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function toggleFilter(sectionName, filterValue) {
|
||||
const otherCalendarPanel = queryFirst(".o_other_calendar_panel");
|
||||
if (otherCalendarPanel) {
|
||||
click(otherCalendarPanel);
|
||||
await animationFrame();
|
||||
}
|
||||
const root = findFilterPanelFilter(sectionName, filterValue);
|
||||
const input = queryFirst(`input`, { root });
|
||||
|
||||
instantScrollTo(input);
|
||||
|
||||
await click(input);
|
||||
await animationFrame();
|
||||
|
||||
if (otherCalendarPanel) {
|
||||
await click(otherCalendarPanel);
|
||||
await animationFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} sectionName
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function toggleSectionFilter(sectionName) {
|
||||
const otherCalendarPanel = queryFirst(".o_other_calendar_panel");
|
||||
if (otherCalendarPanel) {
|
||||
await click(otherCalendarPanel);
|
||||
await animationFrame();
|
||||
}
|
||||
const root = findFilterPanelSectionFilter(sectionName);
|
||||
const input = queryFirst(`input`, { root });
|
||||
|
||||
instantScrollTo(input);
|
||||
|
||||
await click(input);
|
||||
await animationFrame();
|
||||
|
||||
if (otherCalendarPanel) {
|
||||
await click(otherCalendarPanel);
|
||||
await animationFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} sectionName
|
||||
* @param {string} filterValue
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function removeFilter(sectionName, filterValue) {
|
||||
const root = findFilterPanelFilter(sectionName, filterValue);
|
||||
const button = queryFirst(`.o_remove`, { root });
|
||||
|
||||
instantScrollTo(button);
|
||||
|
||||
await click(button);
|
||||
await animationFrame();
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,115 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { queryAllTexts } from "@odoo/hoot-dom";
|
||||
import { contains, mountWithCleanup, preloadBundle } from "@web/../tests/web_test_helpers";
|
||||
import { DEFAULT_DATE, FAKE_MODEL } from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarYearPopover } from "@web/views/calendar/calendar_year/calendar_year_popover";
|
||||
|
||||
describe.current.tags("desktop");
|
||||
|
||||
const FAKE_RECORDS = [
|
||||
{
|
||||
id: 1,
|
||||
start: DEFAULT_DATE,
|
||||
end: DEFAULT_DATE,
|
||||
isAllDay: true,
|
||||
title: "R1",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
start: DEFAULT_DATE.set({ hours: 14 }),
|
||||
end: DEFAULT_DATE.set({ hours: 16 }),
|
||||
isAllDay: false,
|
||||
title: "R2",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
start: DEFAULT_DATE.minus({ days: 1 }),
|
||||
end: DEFAULT_DATE.plus({ days: 1 }),
|
||||
isAllDay: true,
|
||||
title: "R3",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
start: DEFAULT_DATE.minus({ days: 3 }),
|
||||
end: DEFAULT_DATE.plus({ days: 1 }),
|
||||
isAllDay: true,
|
||||
title: "R4",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
start: DEFAULT_DATE.minus({ days: 1 }),
|
||||
end: DEFAULT_DATE.plus({ days: 3 }),
|
||||
isAllDay: true,
|
||||
title: "R5",
|
||||
},
|
||||
];
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
date: DEFAULT_DATE,
|
||||
records: FAKE_RECORDS,
|
||||
createRecord() {},
|
||||
deleteRecord() {},
|
||||
editRecord() {},
|
||||
close() {},
|
||||
};
|
||||
|
||||
async function start(props = {}) {
|
||||
await mountWithCleanup(CalendarYearPopover, {
|
||||
props: { ...FAKE_PROPS, ...props },
|
||||
});
|
||||
}
|
||||
|
||||
preloadBundle("web.fullcalendar_lib");
|
||||
|
||||
test(`canCreate is true`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, canCreate: true },
|
||||
});
|
||||
expect(`.o_cw_popover_create`).toHaveCount(1);
|
||||
});
|
||||
|
||||
test(`canCreate is false`, async () => {
|
||||
await start({
|
||||
model: { ...FAKE_MODEL, canCreate: false },
|
||||
});
|
||||
expect(`.o_cw_popover_create`).toHaveCount(0);
|
||||
});
|
||||
|
||||
test(`click on create button`, async () => {
|
||||
await start({
|
||||
createRecord: () => expect.step("create"),
|
||||
model: { ...FAKE_MODEL, canCreate: true },
|
||||
});
|
||||
expect(`.o_cw_popover_create`).toHaveCount(1);
|
||||
|
||||
await contains(`.o_cw_popover_create`).click();
|
||||
expect.verifySteps(["create"]);
|
||||
});
|
||||
|
||||
test(`group records`, async () => {
|
||||
await start();
|
||||
expect(`.o_cw_body > div`).toHaveCount(4);
|
||||
expect(`.o_cw_body > a`).toHaveCount(1);
|
||||
expect(queryAllTexts`.o_cw_body > div`).toEqual([
|
||||
"July 16, 2021\nR1\n14:00\nR2",
|
||||
"July 13-17, 2021\nR4",
|
||||
"July 15-17, 2021\nR3",
|
||||
"July 15-19, 2021\nR5",
|
||||
]);
|
||||
expect(`.o_cw_body`).toHaveText(
|
||||
"July 16, 2021\nR1\n14:00\nR2\nJuly 13-17, 2021\nR4\nJuly 15-17, 2021\nR3\nJuly 15-19, 2021\nR5\n Create"
|
||||
);
|
||||
});
|
||||
|
||||
test(`click on record`, async () => {
|
||||
await start({
|
||||
records: [FAKE_RECORDS[3]],
|
||||
editRecord: () => expect.step("edit"),
|
||||
});
|
||||
expect(`.o_cw_body a.o_cw_popover_link`).toHaveCount(1);
|
||||
|
||||
await contains(`.o_cw_body a.o_cw_popover_link`).click();
|
||||
expect.verifySteps(["edit"]);
|
||||
});
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { queryAllTexts, resize } from "@odoo/hoot-dom";
|
||||
import { mockTimeZone, runAllTimers } from "@odoo/hoot-mock";
|
||||
import {
|
||||
mockService,
|
||||
mountWithCleanup,
|
||||
preloadBundle,
|
||||
patchWithCleanup,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
import { FAKE_MODEL, clickDate, selectDateRange } from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarYearRenderer } from "@web/views/calendar/calendar_year/calendar_year_renderer";
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
createRecord() {},
|
||||
deleteRecord() {},
|
||||
editRecord() {},
|
||||
};
|
||||
|
||||
async function start(props = {}) {
|
||||
await mountWithCleanup(CalendarYearRenderer, {
|
||||
props: { ...FAKE_PROPS, ...props },
|
||||
});
|
||||
}
|
||||
|
||||
preloadBundle("web.fullcalendar_lib");
|
||||
|
||||
test(`mount a CalendarYearRenderer`, async () => {
|
||||
await start();
|
||||
expect(`.fc-month-container`).toHaveCount(12);
|
||||
|
||||
// check "title format"
|
||||
expect(`.fc-toolbar-chunk:nth-child(2) .fc-toolbar-title`).toHaveCount(12);
|
||||
expect(queryAllTexts`.fc-toolbar-chunk:nth-child(2) .fc-toolbar-title`).toEqual([
|
||||
"January 2021",
|
||||
"February 2021",
|
||||
"March 2021",
|
||||
"April 2021",
|
||||
"May 2021",
|
||||
"June 2021",
|
||||
"July 2021",
|
||||
"August 2021",
|
||||
"September 2021",
|
||||
"October 2021",
|
||||
"November 2021",
|
||||
"December 2021",
|
||||
]);
|
||||
|
||||
// check day header format
|
||||
expect(`.fc-month:eq(0) .fc-col-header-cell`).toHaveCount(7);
|
||||
expect(queryAllTexts`.fc-month:eq(0) .fc-col-header-cell`).toEqual([
|
||||
"S",
|
||||
"M",
|
||||
"T",
|
||||
"W",
|
||||
"T",
|
||||
"F",
|
||||
"S",
|
||||
]);
|
||||
|
||||
// check showNonCurrentDates
|
||||
expect(`:not(.fc-day-disabled) > * > * > .fc-daygrid-day-number`).toHaveCount(365);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test(`display events`, async () => {
|
||||
mockService("popover", () => ({
|
||||
add(target, component, props) {
|
||||
expect.step(`${props.date.toISODate()} ${props.records[0].title}`);
|
||||
return () => {};
|
||||
},
|
||||
}));
|
||||
|
||||
await start({
|
||||
createRecord(record) {
|
||||
expect.step(`${record.start.toISODate()} allDay:${record.isAllDay} no event`);
|
||||
},
|
||||
});
|
||||
|
||||
await clickDate("2021-07-15");
|
||||
expect.verifySteps(["2021-07-15 allDay:true no event"]);
|
||||
await clickDate("2021-07-16");
|
||||
expect.verifySteps(["2021-07-16 1 day, all day in July"]);
|
||||
await clickDate("2021-07-17");
|
||||
expect.verifySteps(["2021-07-17 allDay:true no event"]);
|
||||
await clickDate("2021-07-18");
|
||||
expect.verifySteps(["2021-07-18 3 days, all day in July"]);
|
||||
await clickDate("2021-07-19");
|
||||
expect.verifySteps(["2021-07-19 3 days, all day in July"]);
|
||||
await clickDate("2021-07-20");
|
||||
expect.verifySteps(["2021-07-20 3 days, all day in July"]);
|
||||
await clickDate("2021-07-21");
|
||||
expect.verifySteps(["2021-07-21 allDay:true no event"]);
|
||||
await clickDate("2021-06-28");
|
||||
expect.verifySteps(["2021-06-28 allDay:true no event"]);
|
||||
await clickDate("2021-06-29");
|
||||
expect.verifySteps(["2021-06-29 Over June and July"]);
|
||||
await clickDate("2021-06-30");
|
||||
expect.verifySteps(["2021-06-30 Over June and July"]);
|
||||
await clickDate("2021-07-01");
|
||||
expect.verifySteps(["2021-07-01 Over June and July"]);
|
||||
await clickDate("2021-07-02");
|
||||
expect.verifySteps(["2021-07-02 Over June and July"]);
|
||||
await clickDate("2021-07-03");
|
||||
expect.verifySteps(["2021-07-03 Over June and July"]);
|
||||
await clickDate("2021-07-04");
|
||||
expect.verifySteps(["2021-07-04 allDay:true no event"]);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test(`select a range of date`, async () => {
|
||||
await start({
|
||||
createRecord({ isAllDay, start, end }) {
|
||||
expect.step("create");
|
||||
expect(isAllDay).toBe(true);
|
||||
expect(start.toSQL()).toBe("2021-07-02 00:00:00.000 +01:00");
|
||||
expect(end.toSQL()).toBe("2021-07-05 00:00:00.000 +01:00");
|
||||
},
|
||||
});
|
||||
await selectDateRange("2021-07-02", "2021-07-05");
|
||||
expect.verifySteps(["create"]);
|
||||
});
|
||||
|
||||
test(`display correct column header for days, independent of the timezone`, async () => {
|
||||
// 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.
|
||||
mockTimeZone(-9);
|
||||
await start();
|
||||
expect(queryAllTexts`.fc-month:eq(0) .fc-col-header-cell`).toEqual([
|
||||
"S",
|
||||
"M",
|
||||
"T",
|
||||
"W",
|
||||
"T",
|
||||
"F",
|
||||
"S",
|
||||
]);
|
||||
});
|
||||
|
||||
test("resize callback is being called", async () => {
|
||||
patchWithCleanup(CalendarYearRenderer.prototype, {
|
||||
onWindowResize() {
|
||||
expect.step("onWindowResize");
|
||||
},
|
||||
});
|
||||
await start();
|
||||
expect.verifySteps([]);
|
||||
await resize({ height: 500 });
|
||||
await runAllTimers();
|
||||
expect.verifySteps(new Array(12).fill("onWindowResize")); // one for each FullCalendar instance
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue