mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-21 06:12:04 +02:00
vanilla 19.0
This commit is contained in:
parent
991d2234ca
commit
d1963a3c3a
3066 changed files with 1651266 additions and 922560 deletions
|
|
@ -0,0 +1,218 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { FAKE_FIELDS } from "./calendar_test_helpers";
|
||||
|
||||
import { parseXML } from "@web/core/utils/xml";
|
||||
import { CalendarArchParser } from "@web/views/calendar/calendar_arch_parser";
|
||||
|
||||
describe.current.tags("headless");
|
||||
|
||||
const parser = new CalendarArchParser();
|
||||
const DEFAULT_ARCH_RESULTS = {
|
||||
aggregate: null,
|
||||
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,
|
||||
monthOverflow: true,
|
||||
multiCreateView: null,
|
||||
popoverFieldNodes: {},
|
||||
scale: "week",
|
||||
scales: ["day", "week", "month", "year"],
|
||||
showUnusualDays: false,
|
||||
showDatePicker: true,
|
||||
};
|
||||
|
||||
function parseArch(arch) {
|
||||
return parser.parse(parseXML(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 must define "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(["day", "week", "month", "year"]);
|
||||
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);
|
||||
});
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
/** @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);
|
||||
});
|
||||
|
|
@ -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"]);
|
||||
});
|
||||
|
|
@ -1,222 +0,0 @@
|
|||
/** @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"]);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
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";
|
||||
import { CallbackRecorder } from "@web/search/action_hook";
|
||||
|
||||
const FAKE_PROPS = {
|
||||
model: FAKE_MODEL,
|
||||
createRecord() {},
|
||||
deleteRecord() {},
|
||||
editRecord() {},
|
||||
callbackRecorder: new CallbackRecorder(),
|
||||
onSquareSelection() {},
|
||||
cleanSquareSelection() {},
|
||||
};
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
test("Month: remove row when no day of current month", async () => {
|
||||
await start({ model: { ...FAKE_MODEL, scale: "month" } });
|
||||
expect(".fc-day-other, .fc-day-disabled").toHaveCount(4);
|
||||
});
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
/** @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]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
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,
|
||||
preloadBundle,
|
||||
} from "@web/../tests/web_test_helpers";
|
||||
|
||||
import { CalendarController } from "@web/views/calendar/calendar_controller";
|
||||
|
||||
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");
|
||||
});
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/** @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");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,213 +0,0 @@
|
|||
/** @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([]);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { click, queryAllTexts } from "@odoo/hoot-dom";
|
||||
import { contains, mountWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { FAKE_FILTER_SECTIONS, FAKE_MODEL } from "./calendar_test_helpers";
|
||||
|
||||
import { CalendarFilterSection } from "@web/views/calendar/calendar_filter_section/calendar_filter_section";
|
||||
import { runAllTimers } from "@odoo/hoot-mock";
|
||||
|
||||
test(`render filter panel`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: FAKE_MODEL,
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
expect(`.o_calendar_filter`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter .o_cw_filter_label`).toHaveText("Attendees");
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item`).toHaveCount(3);
|
||||
});
|
||||
|
||||
test(`filters are correctly sorted`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: FAKE_MODEL,
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
expect(queryAllTexts`.o_calendar_filter .o_calendar_filter_item`).toEqual([
|
||||
"Mitchell Admin",
|
||||
"Brandon Freeman",
|
||||
"Marc Demo",
|
||||
]);
|
||||
});
|
||||
|
||||
test(`section can collapse`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: FAKE_MODEL,
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
expect(`.o_calendar_filter .o_cw_filter_collapse_icon`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item`).toHaveCount(3);
|
||||
|
||||
await contains(`.o_calendar_filter .o_cw_filter_label`).click();
|
||||
await runAllTimers();
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item`).toHaveCount(0);
|
||||
|
||||
await contains(`.o_calendar_filter .o_cw_filter_label`).click();
|
||||
await runAllTimers();
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item`).toHaveCount(3);
|
||||
});
|
||||
|
||||
test(`filters can have avatar`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: FAKE_MODEL,
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
expect(`.o_calendar_filter .o_cw_filter_avatar`).toHaveCount(3);
|
||||
expect(`.o_calendar_filter img.o_cw_filter_avatar`).toHaveCount(3);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(0) .o_cw_filter_avatar`).toHaveAttribute(
|
||||
"data-src",
|
||||
"/web/image/res.partner/3/avatar_128"
|
||||
);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(1) .o_cw_filter_avatar`).toHaveAttribute(
|
||||
"data-src",
|
||||
"/web/image/res.partner/4/avatar_128"
|
||||
);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(2) .o_cw_filter_avatar`).toHaveAttribute(
|
||||
"data-src",
|
||||
"/web/image/res.partner/6/avatar_128"
|
||||
);
|
||||
});
|
||||
|
||||
test(`filters with no avatar`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: FAKE_MODEL,
|
||||
section: FAKE_FILTER_SECTIONS[1],
|
||||
},
|
||||
});
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item`).toHaveCount(2);
|
||||
expect(`.o_calendar_filter .o_cw_filter_avatar`).toHaveCount(0);
|
||||
});
|
||||
|
||||
test(`filter can have remove button`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: FAKE_MODEL,
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item`).toHaveCount(3);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item .o_remove`).toHaveCount(2);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(0) .o_remove`).toHaveCount(0);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(1) .o_remove`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(2) .o_remove`).toHaveCount(1);
|
||||
expect(`.o_calendar_filter .o_calendar_filter_item:eq(3) .o_remove`).toHaveCount(0);
|
||||
});
|
||||
|
||||
test(`click on remove button`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: {
|
||||
...FAKE_MODEL,
|
||||
unlinkFilter(fieldName, recordId) {
|
||||
expect.step(`${fieldName} ${recordId}`);
|
||||
},
|
||||
},
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
await click(`.o_calendar_filter .o_calendar_filter_item:eq(1) .o_remove`);
|
||||
await click(`.o_calendar_filter .o_calendar_filter_item:eq(2) .o_remove`);
|
||||
expect.verifySteps(["partner_ids 1", "partner_ids 2"]);
|
||||
});
|
||||
|
||||
test(`click on filter`, async () => {
|
||||
await mountWithCleanup(CalendarFilterSection, {
|
||||
props: {
|
||||
model: {
|
||||
...FAKE_MODEL,
|
||||
updateFilters(fieldName, filters, active) {
|
||||
expect.step(`${fieldName} ${filters.map((f) => f.value)} ${active}`);
|
||||
},
|
||||
},
|
||||
section: FAKE_FILTER_SECTIONS[0],
|
||||
},
|
||||
});
|
||||
await click(`.o_calendar_filter .o_calendar_filter_item:eq(0) input`);
|
||||
await click(`.o_calendar_filter .o_calendar_filter_item:eq(1) input`);
|
||||
await click(`.o_calendar_filter .o_calendar_filter_item:eq(2) input`);
|
||||
await click(`.o_calendar_filter .o_calendar_filter_items_checkall input`);
|
||||
await click(`.o_calendar_filter .o_calendar_filter_items_checkall input`);
|
||||
expect.verifySteps([
|
||||
"partner_ids 3 false",
|
||||
"partner_ids 4 false",
|
||||
"partner_ids 6 true",
|
||||
"partner_ids 3,4,6 true",
|
||||
"partner_ids 3,4,6 false",
|
||||
]);
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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");
|
||||
});
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/** @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");
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,742 @@
|
|||
import { click, drag, edit, 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 { CalendarModel } from "@web/views/calendar/calendar_model";
|
||||
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",
|
||||
},
|
||||
canAddFilter: true,
|
||||
filters: [
|
||||
{
|
||||
type: "user",
|
||||
label: "Mitchell Admin",
|
||||
active: true,
|
||||
value: 3,
|
||||
colorIndex: 3,
|
||||
recordId: null,
|
||||
canRemove: false,
|
||||
hasAvatar: true,
|
||||
},
|
||||
{
|
||||
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,
|
||||
},
|
||||
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 click(".o_time_picker_input:eq(0)");
|
||||
await animationFrame();
|
||||
await edit(selectedValue, { confirm: "enter" });
|
||||
await animationFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
await advanceTime(CalendarModel.DEBOUNCED_LOAD_DELAY);
|
||||
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();
|
||||
}
|
||||
await advanceTime(CalendarModel.DEBOUNCED_LOAD_DELAY);
|
||||
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 advanceTime(CalendarModel.DEBOUNCED_LOAD_DELAY);
|
||||
await animationFrame();
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
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"]);
|
||||
});
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
/** @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"]);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
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("remove row when no day of current month", async () => {
|
||||
await start();
|
||||
expect(".fc-day-other, .fc-day-disabled").toHaveCount(76);
|
||||
});
|
||||
|
||||
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
|
||||
});
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
/** @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"]);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,536 +0,0 @@
|
|||
/** @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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue