mirror of
https://github.com/bringout/oca-ocb-core.git
synced 2026-04-20 00:52:07 +02:00
vanilla 17.0
This commit is contained in:
parent
d72e748793
commit
a9bcec8e91
1986 changed files with 1613876 additions and 568976 deletions
|
|
@ -931,7 +931,7 @@ QUnit.module("ActionSwiper", ({ beforeEach }) => {
|
|||
const { execRegisteredTimeouts } = mockTimeout();
|
||||
patchWithCleanup(ActionSwiper.prototype, {
|
||||
setup() {
|
||||
this._super(...arguments);
|
||||
super.setup();
|
||||
onPatched(() => {
|
||||
if (executingAction) {
|
||||
assert.step("ActionSwiper patched");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { Component, xml } from "@odoo/owl";
|
||||
import { clearRegistryWithCleanup, makeTestEnv } from "@web/../tests/helpers/mock_env";
|
||||
import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services";
|
||||
import { click, getFixture, mount } from "@web/../tests/helpers/utils";
|
||||
import { DateTimeInput } from "@web/core/datetime/datetime_input";
|
||||
import { datetimePickerService } from "@web/core/datetime/datetimepicker_service";
|
||||
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
|
||||
import { popoverService } from "@web/core/popover/popover_service";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { uiService } from "@web/core/ui/ui_service";
|
||||
|
||||
const { DateTime } = luxon;
|
||||
|
||||
/**
|
||||
* @typedef {import("@web/core/datetime/datetime_input").DateTimeInputProps} DateTimeInputProps
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {DateTimeInputProps} props
|
||||
*/
|
||||
const mountInput = async (props) => {
|
||||
const env = await makeTestEnv();
|
||||
await mount(Root, getFixture(), { env, props });
|
||||
return getFixture().querySelector(".o_datetime_input");
|
||||
};
|
||||
|
||||
class Root extends Component {
|
||||
static components = { DateTimeInput };
|
||||
|
||||
static template = xml`
|
||||
<div class="d-flex">
|
||||
<DateTimeInput t-props="props" />
|
||||
</div>
|
||||
<t t-foreach="mainComponentEntries" t-as="comp" t-key="comp[0]">
|
||||
<t t-component="comp[1].Component" t-props="comp[1].props" />
|
||||
</t>
|
||||
`;
|
||||
|
||||
setup() {
|
||||
this.mainComponentEntries = mainComponentRegistry.getEntries();
|
||||
}
|
||||
}
|
||||
|
||||
const mainComponentRegistry = registry.category("main_components");
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
QUnit.module("Components", ({ beforeEach }) => {
|
||||
beforeEach(() => {
|
||||
clearRegistryWithCleanup(mainComponentRegistry);
|
||||
|
||||
serviceRegistry
|
||||
.add("datetime_picker", datetimePickerService)
|
||||
.add("hotkey", hotkeyService)
|
||||
.add(
|
||||
"localization",
|
||||
makeFakeLocalizationService({
|
||||
dateFormat: "dd/MM/yyyy",
|
||||
dateTimeFormat: "dd/MM/yyyy HH:mm:ss",
|
||||
})
|
||||
)
|
||||
.add("popover", popoverService)
|
||||
.add("ui", uiService);
|
||||
});
|
||||
|
||||
QUnit.module("DateTimeInput (date)");
|
||||
|
||||
QUnit.test("popover should have enough space to be displayed", async (assert) => {
|
||||
const { parentElement: parent } = await mountInput({
|
||||
value: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy"),
|
||||
type: "date",
|
||||
});
|
||||
|
||||
const initialParentRect = parent.getBoundingClientRect();
|
||||
|
||||
await click(parent, ".o_datetime_input");
|
||||
|
||||
const pickerRect = getFixture().querySelector(".o_datetime_picker").getBoundingClientRect();
|
||||
const finalParentRect = parent.getBoundingClientRect();
|
||||
|
||||
assert.ok(
|
||||
initialParentRect.height < pickerRect.height,
|
||||
"initial height shouldn't be big enough to display the picker"
|
||||
);
|
||||
assert.ok(
|
||||
finalParentRect.height > pickerRect.height,
|
||||
"initial height should be big enough to display the picker"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { hotkeyService } from "@web/core/hotkeys/hotkey_service";
|
||||
import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { makeTestEnv } from "../../helpers/mock_env";
|
||||
import { getFixture, mount, dragAndDrop } from "../../helpers/utils";
|
||||
import { makeFakeDialogService } from "../../helpers/mock_services";
|
||||
|
||||
import { Component, xml } from "@odoo/owl";
|
||||
const serviceRegistry = registry.category("services");
|
||||
let parent;
|
||||
let target;
|
||||
|
||||
async function makeDialogTestEnv() {
|
||||
const env = await makeTestEnv();
|
||||
env.dialogData = {
|
||||
isActive: true,
|
||||
close: () => {},
|
||||
scrollToOrigin: () => {},
|
||||
};
|
||||
return env;
|
||||
}
|
||||
|
||||
QUnit.module("Components", (hooks) => {
|
||||
hooks.beforeEach(async () => {
|
||||
target = getFixture();
|
||||
serviceRegistry.add("hotkey", hotkeyService);
|
||||
serviceRegistry.add("dialog", makeFakeDialogService());
|
||||
});
|
||||
hooks.afterEach(() => {
|
||||
if (parent) {
|
||||
parent = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.module("Dialog");
|
||||
|
||||
QUnit.test("dialog can't be moved on small screen", async (assert) => {
|
||||
class Parent extends Component {
|
||||
static template = xml`<Dialog>content</Dialog>`;
|
||||
static components = { Dialog };
|
||||
}
|
||||
|
||||
await mount(Parent, target, { env: await makeDialogTestEnv() });
|
||||
const content = target.querySelector(".modal-content");
|
||||
assert.strictEqual(content.style.top, "0px");
|
||||
assert.strictEqual(content.style.left, "0px");
|
||||
|
||||
const header = content.querySelector(".modal-header");
|
||||
const headerRect = header.getBoundingClientRect();
|
||||
// Even if the `dragAndDrop` is called, confirms that there are no effects
|
||||
await dragAndDrop(header, document.body, {
|
||||
// the util function sets the source coordinates at (x; y) + (w/2; h/2)
|
||||
// so we need to move the dialog based on these coordinates.
|
||||
x: headerRect.x + headerRect.width / 2 + 20,
|
||||
y: headerRect.y + headerRect.height / 2 + 50,
|
||||
});
|
||||
assert.strictEqual(content.style.top, "0px");
|
||||
assert.strictEqual(content.style.left, "0px");
|
||||
});
|
||||
});
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { click, getFixture, triggerEvent, nextTick } from "@web/../tests/helpers/utils";
|
||||
import { getFixture, nextTick } from "@web/../tests/helpers/utils";
|
||||
import { ControlPanel } from "@web/search/control_panel/control_panel";
|
||||
import {
|
||||
editSearch,
|
||||
makeWithSearch,
|
||||
setupControlPanelServiceRegistry,
|
||||
} from "@web/../tests/search/helpers";
|
||||
import { makeWithSearch, setupControlPanelServiceRegistry } from "@web/../tests/search/helpers";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { uiService } from "@web/core/ui/ui_service";
|
||||
|
||||
|
|
@ -42,86 +38,6 @@ QUnit.module("Search", (hooks) => {
|
|||
|
||||
QUnit.module("Control Panel (mobile)");
|
||||
|
||||
QUnit.test("Display control panel mobile", async (assert) => {
|
||||
await makeWithSearch({
|
||||
serverData,
|
||||
resModel: "foo",
|
||||
Component: ControlPanel,
|
||||
searchMenuTypes: ["filter"],
|
||||
searchViewId: false,
|
||||
});
|
||||
|
||||
assert.containsOnce(target, ".breadcrumb");
|
||||
assert.containsOnce(target, ".o_enable_searchview");
|
||||
assert.containsNone(target, ".o_searchview");
|
||||
assert.containsNone(target, ".o_toggle_searchview_full");
|
||||
|
||||
await click(target, ".o_enable_searchview");
|
||||
|
||||
assert.containsNone(target, ".breadcrumb");
|
||||
assert.containsOnce(target, ".o_enable_searchview");
|
||||
assert.containsOnce(target, ".o_searchview");
|
||||
assert.containsOnce(target, ".o_toggle_searchview_full");
|
||||
|
||||
await click(target, ".o_toggle_searchview_full");
|
||||
|
||||
assert.containsOnce(document.body, ".o_searchview.o_mobile_search");
|
||||
assert.containsN(document.body, ".o_mobile_search .o_mobile_search_button", 2);
|
||||
assert.strictEqual(
|
||||
document.body.querySelector(".o_mobile_search_header").textContent.trim(),
|
||||
"FILTER CLEAR"
|
||||
);
|
||||
assert.containsOnce(document.body, ".o_searchview.o_mobile_search .o_cp_searchview");
|
||||
assert.containsOnce(document.body, ".o_searchview.o_mobile_search .o_mobile_search_footer");
|
||||
|
||||
await click(document.body.querySelector(".o_mobile_search_button"));
|
||||
|
||||
assert.containsNone(target, ".breadcrumb");
|
||||
assert.containsOnce(target, ".o_enable_searchview");
|
||||
assert.containsOnce(target, ".o_searchview");
|
||||
assert.containsOnce(target, ".o_toggle_searchview_full");
|
||||
|
||||
await click(target, ".o_enable_searchview");
|
||||
|
||||
assert.containsOnce(target, ".breadcrumb");
|
||||
assert.containsOnce(target, ".o_enable_searchview");
|
||||
assert.containsNone(target, ".o_searchview");
|
||||
assert.containsNone(target, ".o_toggle_searchview_full");
|
||||
});
|
||||
|
||||
QUnit.test("Make a simple search in mobile mode", async (assert) => {
|
||||
await makeWithSearch({
|
||||
serverData,
|
||||
resModel: "foo",
|
||||
Component: ControlPanel,
|
||||
searchMenuTypes: ["filter"],
|
||||
searchViewFields: {
|
||||
birthday: { string: "Birthday", type: "date", store: true, sortable: true },
|
||||
},
|
||||
searchViewArch: `
|
||||
<search>
|
||||
<field name="birthday"/>
|
||||
</search>
|
||||
`,
|
||||
});
|
||||
assert.containsNone(target, ".o_searchview");
|
||||
|
||||
await click(target, ".o_enable_searchview");
|
||||
assert.containsOnce(target, ".o_searchview");
|
||||
const input = target.querySelector(".o_searchview input");
|
||||
assert.containsNone(target, ".o_searchview_autocomplete");
|
||||
|
||||
await editSearch(target, "2022-02-14");
|
||||
assert.strictEqual(input.value, "2022-02-14", "input value should be updated");
|
||||
assert.containsOnce(target, ".o_searchview_autocomplete");
|
||||
|
||||
await triggerEvent(input, null, "keydown", { key: "Escape" });
|
||||
assert.containsNone(target, ".o_searchview_autocomplete");
|
||||
|
||||
await click(target, ".o_enable_searchview");
|
||||
assert.containsNone(target, ".o_searchview");
|
||||
});
|
||||
|
||||
QUnit.test("Control panel is shown/hide on top when scrolling", async (assert) => {
|
||||
await makeWithSearch({
|
||||
serverData,
|
||||
|
|
|
|||
|
|
@ -92,63 +92,55 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
|
||||
assert.containsNone(target, ".o_calendar_button_prev", "prev button should be hidden");
|
||||
assert.containsNone(target, ".o_calendar_button_next", "next button should be hidden");
|
||||
await click(target, ".o_calendar_container .o_other_calendar_panel");
|
||||
assert.isVisible(
|
||||
target.querySelector(
|
||||
".o_cp_bottom_left .o_calendar_buttons .o_calendar_scale_buttons + button.o_cp_today_button"
|
||||
".o_calendar_container .o_calendar_header button.o_calendar_button_today"
|
||||
),
|
||||
"today button should be visible near the calendar buttons (bottom left corner)"
|
||||
"today button should be visible"
|
||||
);
|
||||
|
||||
// Test all views
|
||||
// displays month mode by default
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".fc-view-container > .fc-timeGridWeek-view",
|
||||
"should display the current week"
|
||||
);
|
||||
assert.equal(
|
||||
target.querySelector(".breadcrumb-item").textContent,
|
||||
"undefined (Dec 11 – 17, 2016)"
|
||||
target.querySelector(".o_calendar_container .o_calendar_header .dropdown-toggle")
|
||||
.textContent,
|
||||
"Week",
|
||||
"should display the current week"
|
||||
);
|
||||
|
||||
// switch to day mode
|
||||
await click(target, ".o_control_panel .scale_button_selection");
|
||||
await click(target, ".o_control_panel .o_calendar_button_day");
|
||||
await click(target, ".o_calendar_container .o_calendar_header .dropdown-toggle");
|
||||
await click(target, ".o_calendar_container .o_calendar_header .o_scale_button_day");
|
||||
await nextTick();
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".fc-view-container > .fc-timeGridDay-view",
|
||||
"should display the current day"
|
||||
);
|
||||
assert.equal(
|
||||
target.querySelector(".breadcrumb-item").textContent,
|
||||
"undefined (December 12, 2016)"
|
||||
target.querySelector(".o_calendar_container .o_calendar_header .dropdown-toggle")
|
||||
.textContent,
|
||||
"Day",
|
||||
"should display the current day"
|
||||
);
|
||||
|
||||
// switch to month mode
|
||||
await click(target, ".o_control_panel .scale_button_selection");
|
||||
await click(target, ".o_control_panel .o_calendar_button_month");
|
||||
await click(target, ".o_calendar_container .o_calendar_header .dropdown-toggle");
|
||||
await click(target, ".o_calendar_container .o_calendar_header .o_scale_button_month");
|
||||
await nextTick();
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".fc-view-container > .fc-dayGridMonth-view",
|
||||
"should display the current month"
|
||||
);
|
||||
assert.equal(
|
||||
target.querySelector(".breadcrumb-item").textContent,
|
||||
"undefined (December 2016)"
|
||||
target.querySelector(".o_calendar_container .o_calendar_header .dropdown-toggle")
|
||||
.textContent,
|
||||
"Month",
|
||||
"should display the current month"
|
||||
);
|
||||
|
||||
// switch to year mode
|
||||
await click(target, ".o_control_panel .scale_button_selection");
|
||||
await click(target, ".o_control_panel .o_calendar_button_year");
|
||||
await click(target, ".o_calendar_container .o_calendar_header .dropdown-toggle");
|
||||
await click(target, ".o_calendar_container .o_calendar_header .o_scale_button_year");
|
||||
await nextTick();
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".fc-view-container > .fc-dayGridYear-view",
|
||||
assert.equal(
|
||||
target.querySelector(".o_calendar_container .o_calendar_header .dropdown-toggle")
|
||||
.textContent,
|
||||
"Year",
|
||||
"should display the current year"
|
||||
);
|
||||
assert.equal(target.querySelector(".breadcrumb-item").textContent, "undefined (2016)");
|
||||
});
|
||||
|
||||
QUnit.test("calendar: popover is rendered as dialog in mobile", async function (assert) {
|
||||
|
|
@ -186,7 +178,9 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
await swipeRight(target, ".o_calendar_widget");
|
||||
assert.equal(target.querySelector(".fc-day-header[data-date]").dataset.date, "2016-12-11");
|
||||
|
||||
await click(target, ".o_other_calendar_panel");
|
||||
await click(target, ".o_calendar_button_today");
|
||||
await click(target, ".o_other_calendar_panel");
|
||||
assert.equal(target.querySelector(".fc-day-header[data-date]").dataset.date, "2016-12-12");
|
||||
});
|
||||
|
||||
|
|
@ -202,18 +196,21 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
</calendar>`,
|
||||
});
|
||||
|
||||
assert.containsOnce(target, ".o_calendar_renderer");
|
||||
assert.containsOnce(target, ".o_other_calendar_panel");
|
||||
await click(target, ".o_other_calendar_panel");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".o_calendar_filter_items_checkall",
|
||||
"should contain one filter to check all"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
".o_other_calendar_panel .o_filter > *",
|
||||
3,
|
||||
"should contains 3 child nodes -> 1 label (USER) + 2 resources (user 1/2)"
|
||||
".o_calendar_filter_item",
|
||||
2,
|
||||
"should contain 2 child nodes -> 2 resources"
|
||||
);
|
||||
assert.containsNone(target, ".o_calendar_sidebar");
|
||||
assert.containsOnce(target, ".o_calendar_renderer");
|
||||
|
||||
// Toggle the other calendar panel should hide the calendar view and show the sidebar
|
||||
await click(target, ".o_other_calendar_panel");
|
||||
assert.containsOnce(target, ".o_calendar_sidebar");
|
||||
assert.containsNone(target, ".o_calendar_renderer");
|
||||
assert.containsOnce(target, ".o_calendar_filter");
|
||||
|
|
@ -224,8 +221,8 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
assert.containsN(
|
||||
target,
|
||||
".o_other_calendar_panel .o_filter > *",
|
||||
1,
|
||||
"should contains 1 child node -> 1 label (USER)"
|
||||
0,
|
||||
"should contain 0 child nodes -> no filters selected"
|
||||
);
|
||||
|
||||
// Toggle again the other calendar panel should hide the sidebar and show the calendar view
|
||||
|
|
@ -238,11 +235,11 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
patchWithCleanup(CalendarCommonRenderer.prototype, {
|
||||
onDateClick(...args) {
|
||||
assert.step("dateClick");
|
||||
return this._super(...args);
|
||||
return super.onDateClick(...args);
|
||||
},
|
||||
onSelect(...args) {
|
||||
assert.step("select");
|
||||
return this._super(...args);
|
||||
return super.onSelect(...args);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -268,20 +265,20 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
QUnit.test('calendar: select range on "Free Zone" opens quick create', async function (assert) {
|
||||
patchWithCleanup(CalendarCommonRenderer.prototype, {
|
||||
get options() {
|
||||
return Object.assign({}, this._super(), {
|
||||
return Object.assign({}, super.options, {
|
||||
selectLongPressDelay: 0,
|
||||
});
|
||||
},
|
||||
onDateClick(info) {
|
||||
assert.step("dateClick");
|
||||
return this._super(info);
|
||||
return super.onDateClick(info);
|
||||
},
|
||||
onSelect(info) {
|
||||
assert.step("select");
|
||||
const { startStr, endStr } = info;
|
||||
assert.equal(startStr, "2016-12-12T01:00:00+01:00");
|
||||
assert.equal(endStr, "2016-12-12T02:00:00+01:00");
|
||||
return this._super(info);
|
||||
return super.onSelect(info);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -309,21 +306,21 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
QUnit.test("calendar (year): select date range opens quick create", async function (assert) {
|
||||
patchWithCleanup(CalendarYearRenderer.prototype, {
|
||||
get options() {
|
||||
return Object.assign({}, this._super(), {
|
||||
return Object.assign({}, super.options, {
|
||||
longPressDelay: 0,
|
||||
selectLongPressDelay: 0,
|
||||
});
|
||||
},
|
||||
onDateClick(info) {
|
||||
assert.step("dateClick");
|
||||
return this._super(info);
|
||||
return super.onDateClick(info);
|
||||
},
|
||||
onSelect(info) {
|
||||
assert.step("select");
|
||||
const { startStr, endStr } = info;
|
||||
assert.equal(startStr, "2016-02-02");
|
||||
assert.equal(endStr, "2016-02-06"); // end date is exclusive
|
||||
return this._super(info);
|
||||
return super.onSelect(info);
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -358,34 +355,39 @@ QUnit.module("Views", ({ beforeEach }) => {
|
|||
// Should display year view
|
||||
assert.containsOnce(target, ".fc-dayGridYear-view");
|
||||
assert.containsN(target, ".fc-month-container", 12);
|
||||
assert.equal(target.querySelector(".breadcrumb-item").textContent, "undefined (2016)");
|
||||
|
||||
// Tap on a date
|
||||
await tap(target, ".fc-day-top[data-date='2016-02-05']");
|
||||
await nextTick(); // switch renderer
|
||||
await nextTick(); // await breadcrumb update
|
||||
assert.strictEqual(
|
||||
document.querySelector(".o_calendar_container .o_calendar_header h5").textContent,
|
||||
"5 February 2016"
|
||||
);
|
||||
|
||||
// Should display day view
|
||||
assert.containsNone(target, ".fc-dayGridYear-view");
|
||||
assert.containsOnce(target, ".fc-timeGridDay-view");
|
||||
assert.equal(
|
||||
target.querySelector(".breadcrumb-item").textContent,
|
||||
"undefined (February 5, 2016)"
|
||||
);
|
||||
assert.equal(target.querySelector(".fc-day-header[data-date]").dataset.date, "2016-02-05");
|
||||
|
||||
// Change scale to month
|
||||
await changeScale(target, "month");
|
||||
assert.containsOnce(target, ".o_calendar_container .o_calendar_header h5");
|
||||
assert.strictEqual(
|
||||
document.querySelector(".o_calendar_container .o_calendar_header h5").textContent,
|
||||
"February 2016"
|
||||
);
|
||||
assert.containsNone(target, ".fc-timeGridDay-view");
|
||||
assert.containsOnce(target, ".fc-dayGridMonth-view");
|
||||
assert.equal(
|
||||
target.querySelector(".breadcrumb-item").textContent,
|
||||
"undefined (February 2016)"
|
||||
);
|
||||
|
||||
// Tap on a date
|
||||
await tap(target, ".fc-day-top[data-date='2016-02-10']");
|
||||
await nextTick(); // await reload & render
|
||||
await nextTick(); // await breadcrumb update
|
||||
assert.strictEqual(
|
||||
document.querySelector(".o_calendar_container .o_calendar_header h5").textContent,
|
||||
"February 2016"
|
||||
);
|
||||
|
||||
// should open a Quick create modal view in mobile on short tap on date in monthly view
|
||||
assert.containsOnce(target, ".modal");
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ QUnit.module("Fields", (hooks) => {
|
|||
<field name="timmy" widget="many2many_tags" placeholder="foo"/>
|
||||
</form>`,
|
||||
});
|
||||
assert.strictEqual(target.querySelector("#timmy").placeholder, "foo");
|
||||
assert.strictEqual(target.querySelector("#timmy_0").placeholder, "foo");
|
||||
});
|
||||
|
||||
QUnit.test("Many2ManyTagsField placeholder should be empty", async function (assert) {
|
||||
|
|
@ -57,6 +57,6 @@ QUnit.module("Fields", (hooks) => {
|
|||
<field name="timmy" widget="many2many_tags"/>
|
||||
</form>`,
|
||||
});
|
||||
assert.strictEqual(target.querySelector("#timmy").placeholder, "");
|
||||
assert.strictEqual(target.querySelector("#timmy_0").placeholder, "");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import * as BarcodeScanner from "@web/webclient/barcode/barcode_scanner";
|
|||
let serverData;
|
||||
let target;
|
||||
|
||||
const CREATE = "create";
|
||||
const NAME_SEARCH = "name_search";
|
||||
const PRODUCT_PRODUCT = "product.product";
|
||||
const SALE_ORDER_LINE = "sale_order_line";
|
||||
|
|
@ -123,8 +122,8 @@ QUnit.module("Fields", (hooks) => {
|
|||
<field name="${PRODUCT_FIELD_NAME}" options="{'can_scan_barcode': True}"/>
|
||||
</form>`,
|
||||
async mockRPC(route, args, performRPC) {
|
||||
if (args.method === CREATE && args.model === SALE_ORDER_LINE) {
|
||||
const selectedId = args.args[0][PRODUCT_FIELD_NAME];
|
||||
if (args.method === "web_save" && args.model === SALE_ORDER_LINE) {
|
||||
const selectedId = args.args[1][PRODUCT_FIELD_NAME];
|
||||
assert.equal(
|
||||
selectedId,
|
||||
selectedRecordTest.id,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import { click, getFixture } from "@web/../tests/helpers/utils";
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { registerCleanup } from "@web/../tests/helpers/cleanup";
|
||||
|
||||
let fixture;
|
||||
let serverData;
|
||||
|
|
@ -10,6 +11,8 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
beforeEach(() => {
|
||||
setupViewRegistries();
|
||||
fixture = getFixture();
|
||||
fixture.setAttribute("style", "width:100vw; height:100vh;");
|
||||
registerCleanup(() => fixture.removeAttribute("style"));
|
||||
serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
|
|
@ -20,6 +23,7 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
records: [
|
||||
{ id: 1, display_name: "first record", trululu: 4 },
|
||||
{ id: 2, display_name: "second record", trululu: 1 },
|
||||
{ id: 3, display_name: "third record" },
|
||||
{ id: 4, display_name: "aaa" },
|
||||
],
|
||||
},
|
||||
|
|
@ -29,7 +33,7 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
|
||||
QUnit.module("StatusBarField");
|
||||
|
||||
QUnit.test("statusbar is rendered correclty on small devices", async (assert) => {
|
||||
QUnit.test("statusbar is rendered correctly on small devices", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
|
|
@ -45,16 +49,9 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
`,
|
||||
});
|
||||
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_statusbar_status > button",
|
||||
"should have only one visible status in mobile, the active one"
|
||||
);
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_statusbar_status .dropdown",
|
||||
"should have a dropdown containing all status"
|
||||
);
|
||||
assert.containsN(fixture, ".o_statusbar_status .o_arrow_button:visible", 4);
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .o_arrow_button.dropdown-toggle:visible");
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .o_arrow_button.o_arrow_button_current");
|
||||
assert.containsNone(
|
||||
fixture,
|
||||
".o_statusbar_status .dropdown-menu",
|
||||
|
|
@ -62,34 +59,18 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
);
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".o_statusbar_status button.dropdown-toggle").textContent.trim(),
|
||||
"aaa",
|
||||
"statusbar button should display current field value"
|
||||
"..."
|
||||
);
|
||||
|
||||
// open the dropdown
|
||||
await click(fixture, ".o_statusbar_status > button");
|
||||
await click(fixture, ".o_statusbar_status .dropdown-toggle.o_last");
|
||||
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_statusbar_status .dropdown-menu",
|
||||
"dropdown should be visible"
|
||||
);
|
||||
assert.containsN(
|
||||
fixture,
|
||||
".o_statusbar_status .dropdown-menu .btn",
|
||||
3,
|
||||
"should have 3 status"
|
||||
);
|
||||
assert.containsN(
|
||||
fixture,
|
||||
".o_statusbar_status .btn.disabled",
|
||||
3,
|
||||
"all status should be disabled"
|
||||
);
|
||||
assert.hasClass(
|
||||
fixture.querySelector(".o_statusbar_status .btn:nth-child(3)"),
|
||||
"btn-primary",
|
||||
"active status should be btn-primary"
|
||||
);
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .dropdown-menu .dropdown-item.disabled");
|
||||
});
|
||||
|
||||
QUnit.test("statusbar with no status on extra small screens", async (assert) => {
|
||||
|
|
@ -112,49 +93,19 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
"o_field_empty",
|
||||
"statusbar widget should have class o_field_empty in edit"
|
||||
);
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_statusbar_status button.dropdown-toggle",
|
||||
"statusbar widget should have a button"
|
||||
);
|
||||
assert.strictEqual(
|
||||
fixture.querySelector(".o_statusbar_status button.dropdown-toggle").textContent.trim(),
|
||||
"",
|
||||
"statusbar button shouldn't have text for null field value"
|
||||
);
|
||||
assert.containsOnce(fixture, ".o_statusbar_status button.dropdown-toggle:visible");
|
||||
assert.strictEqual($(".o_statusbar_status button.dropdown-toggle:visible").text(), "...");
|
||||
|
||||
await click(fixture, ".o_statusbar_status button.dropdown-toggle");
|
||||
assert.containsOnce(
|
||||
fixture,
|
||||
".o_statusbar_status .dropdown-menu",
|
||||
"statusbar widget should have a dropdown menu"
|
||||
);
|
||||
assert.containsN(
|
||||
fixture,
|
||||
".o_statusbar_status .dropdown-menu .btn",
|
||||
3,
|
||||
"statusbar widget dropdown menu should have 3 buttons"
|
||||
);
|
||||
await click($(".o_statusbar_status button.dropdown-toggle:visible")[0]);
|
||||
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .dropdown-menu");
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .dropdown-menu .dropdown-item");
|
||||
assert.strictEqual(
|
||||
fixture
|
||||
.querySelectorAll(".o_statusbar_status .dropdown-menu .btn")[0]
|
||||
.querySelector(".o_statusbar_status .dropdown-menu .dropdown-item")
|
||||
.textContent.trim(),
|
||||
"first record",
|
||||
"statusbar widget dropdown first button should display the first record display_name"
|
||||
);
|
||||
assert.strictEqual(
|
||||
fixture
|
||||
.querySelectorAll(".o_statusbar_status .dropdown-menu .btn")[1]
|
||||
.textContent.trim(),
|
||||
"second record",
|
||||
"statusbar widget dropdown second button should display the second record display_name"
|
||||
);
|
||||
assert.strictEqual(
|
||||
fixture
|
||||
.querySelectorAll(".o_statusbar_status .dropdown-menu .btn")[2]
|
||||
.textContent.trim(),
|
||||
"aaa",
|
||||
"statusbar widget dropdown third button should display the third record display_name"
|
||||
"statusbar widget dropdown first item should display the first record display_name"
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -173,37 +124,20 @@ QUnit.module("Mobile Fields", ({ beforeEach }) => {
|
|||
`,
|
||||
});
|
||||
|
||||
await click(fixture, ".o_statusbar_status .dropdown-toggle");
|
||||
assert.hasClass(
|
||||
fixture.querySelector(".o_statusbar_status .dropdown-menu .btn:nth-child(3)"),
|
||||
"btn-primary"
|
||||
);
|
||||
assert.hasClass(
|
||||
fixture.querySelector(".o_statusbar_status .dropdown-menu .btn:nth-child(3)"),
|
||||
"disabled"
|
||||
);
|
||||
// Open dropdown
|
||||
await click($(".o_statusbar_status .dropdown-toggle:visible")[0]);
|
||||
|
||||
assert.containsN(
|
||||
fixture,
|
||||
".o_statusbar_status .btn-secondary:not(.dropdown-toggle):not(.disabled)",
|
||||
2,
|
||||
"other status should be btn-secondary and not disabled"
|
||||
);
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .dropdown-item");
|
||||
|
||||
await click(
|
||||
fixture.querySelector(
|
||||
".o_statusbar_status .btn-secondary:not(.dropdown-toggle):not(.disabled)"
|
||||
)
|
||||
);
|
||||
await click(fixture, ".o_statusbar_status .dropdown-item");
|
||||
|
||||
await click(fixture, ".o_statusbar_status .dropdown-toggle");
|
||||
assert.hasClass(
|
||||
fixture.querySelector(".o_statusbar_status .dropdown-menu .btn:nth-child(1)"),
|
||||
"btn-primary"
|
||||
);
|
||||
assert.hasClass(
|
||||
fixture.querySelector(".o_statusbar_status .dropdown-menu .btn:nth-child(1)"),
|
||||
"disabled"
|
||||
);
|
||||
assert.strictEqual($(".o_arrow_button_current").text(), "first record");
|
||||
assert.containsN(fixture, ".o_statusbar_status .o_arrow_button:visible", 3);
|
||||
assert.containsOnce(fixture, ".o_statusbar_status .dropdown-toggle:visible");
|
||||
|
||||
// Open second dropdown
|
||||
await click($(".o_statusbar_status .dropdown-toggle:visible")[0]);
|
||||
|
||||
assert.containsN(fixture, ".o_statusbar_status .dropdown-item", 2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
fields: {
|
||||
display_name: { type: "char", string: "Display Name" },
|
||||
trululu: { type: "many2one", string: "Trululu", relation: "partner" },
|
||||
boolean: { type: "boolean", string: "Bool" },
|
||||
},
|
||||
records: [
|
||||
{ id: 1, display_name: "first record", trululu: 4 },
|
||||
|
|
@ -104,8 +105,8 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
arch: `
|
||||
<form>
|
||||
<header>
|
||||
<button string="Confirm" attrs="{'invisible': [['display_name', '=', 'first record']]}" />
|
||||
<button string="Do it" attrs="{'invisible': [['display_name', '=', 'first record']]}" />
|
||||
<button string="Confirm" invisible="display_name == 'first record'" />
|
||||
<button string="Do it" invisible="display_name == 'first record'" />
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
|
|
@ -145,7 +146,7 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
arch: `
|
||||
<form>
|
||||
<header>
|
||||
<button string="Hola" attrs="{'invisible': [['display_name', '=', 'first record']]}" />
|
||||
<button string="Hola" invisible="display_name == 'first record'" />
|
||||
<button string="Ciao" />
|
||||
</header>
|
||||
<sheet>
|
||||
|
|
@ -197,7 +198,7 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
<form>
|
||||
<header>
|
||||
<widget name="attach_document" string="Attach document" />
|
||||
<button string="Ciao" attrs="{'invisible': [['display_name', '=', 'first record']]}" />
|
||||
<button string="Ciao" invisible="display_name == 'first record'" />
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
|
|
@ -251,8 +252,8 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
<form>
|
||||
<header>
|
||||
<button string="Just more than one" />
|
||||
<button string="Confirm" attrs="{'invisible': [['display_name', '=', '']]}" />
|
||||
<button string="Do it" attrs="{'invisible': [['display_name', '!=', '']]}" />
|
||||
<button string="Confirm" invisible="display_name == ''" />
|
||||
<button string="Do it" invisible="display_name != ''" />
|
||||
</header>
|
||||
<sheet>
|
||||
<field name="display_name" />
|
||||
|
|
@ -319,8 +320,8 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
</sheet>
|
||||
</form>
|
||||
`,
|
||||
mockRPC(route, { method, args: [, , changedField] }) {
|
||||
if (method === "onchange" && changedField === "display_name") {
|
||||
mockRPC(route, { method, args }) {
|
||||
if (method === "onchange" && args[2][0] === "display_name") {
|
||||
return onchangeDef;
|
||||
}
|
||||
},
|
||||
|
|
@ -422,7 +423,7 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
);
|
||||
|
||||
// click on back button
|
||||
await click(fixture, ".modal .modal-header .fa-arrow-left");
|
||||
await click(fixture, ".modal .modal-header .oi-arrow-left");
|
||||
assert.strictEqual(
|
||||
window.scrollY,
|
||||
265,
|
||||
|
|
@ -436,7 +437,7 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
let fileInput;
|
||||
patchWithCleanup(AttachDocumentWidget.prototype, {
|
||||
setup() {
|
||||
this._super();
|
||||
super.setup();
|
||||
fileInput = this.fileInput;
|
||||
},
|
||||
});
|
||||
|
|
@ -479,4 +480,38 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
await nextTick();
|
||||
assert.verifySteps(["post"]);
|
||||
});
|
||||
|
||||
QUnit.test("button box with 3/4 buttons (close to threshold)", async (assert) => {
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<sheet>
|
||||
<div name="button_box">
|
||||
<button>MyButton</button>
|
||||
<button>MyButton2</button>
|
||||
<button>MyButton3</button>
|
||||
<button invisible="not boolean">MyButton4</button>
|
||||
</div>
|
||||
<field name="boolean"/>
|
||||
</sheet>
|
||||
</form>`,
|
||||
resId: 2,
|
||||
});
|
||||
|
||||
// 3 buttons to display -> no "More" dropdown
|
||||
assert.containsNone(fixture, ".o_field_widget[name=boolean] input:checked");
|
||||
assert.containsN(fixture, ".o-form-buttonbox > .oe_stat_button", 3);
|
||||
assert.containsNone(fixture, ".o-form-buttonbox .o_button_more");
|
||||
|
||||
// 4 buttons to display -> 2 buttons visible + 2 inside the "More" dropdown
|
||||
await click(fixture.querySelector(".o_field_widget[name=boolean] input"));
|
||||
assert.containsN(fixture, ".o-form-buttonbox > .oe_stat_button", 3);
|
||||
assert.containsOnce(fixture, ".o-form-buttonbox .oe_stat_button .o_button_more");
|
||||
|
||||
await click(fixture.querySelector(".o_button_more"));
|
||||
assert.containsN(fixture, ".o_dropdown_more .oe_stat_button", 2);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { click, getFixture, patchWithCleanup } from "@web/../tests/helpers/utils";
|
||||
import { AnimatedNumber } from "@web/views/view_components/animated_number";
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
|
||||
QUnit.module("Views", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
patchWithCleanup(AnimatedNumber, { enableAnimations: false });
|
||||
serverData = {
|
||||
models: {
|
||||
partner: {
|
||||
fields: {
|
||||
foo: { string: "Foo", type: "char" },
|
||||
product_id: {
|
||||
string: "something_id",
|
||||
type: "many2one",
|
||||
relation: "product",
|
||||
},
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
foo: "yop",
|
||||
product_id: 3,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
foo: "blip",
|
||||
product_id: 5,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
foo: "gnap",
|
||||
product_id: 3,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
foo: "blip",
|
||||
product_id: 5,
|
||||
},
|
||||
],
|
||||
},
|
||||
product: {
|
||||
fields: {
|
||||
id: { string: "ID", type: "integer" },
|
||||
name: { string: "Display Name", type: "char" },
|
||||
},
|
||||
records: [
|
||||
{ id: 3, name: "hello" },
|
||||
{ id: 5, name: "xmo" },
|
||||
],
|
||||
},
|
||||
},
|
||||
views: {},
|
||||
};
|
||||
target = getFixture();
|
||||
|
||||
setupViewRegistries();
|
||||
});
|
||||
|
||||
QUnit.module("KanbanView");
|
||||
|
||||
QUnit.test("Should load grouped kanban with folded column", async (assert) => {
|
||||
await makeView({
|
||||
type: "kanban",
|
||||
resModel: "partner",
|
||||
serverData,
|
||||
arch: `
|
||||
<kanban>
|
||||
<progressbar field="foo" colors='{"yop": "success", "blip": "danger"}'/>
|
||||
<field name="product_id"/>
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div><field name="foo"/></div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>`,
|
||||
groupBy: ["product_id"],
|
||||
async mockRPC(route, args, performRPC) {
|
||||
if (args.method === "web_read_group") {
|
||||
const result = await performRPC(route, args);
|
||||
result.groups[1].__fold = true;
|
||||
return result;
|
||||
}
|
||||
},
|
||||
});
|
||||
assert.containsN(target, ".o_column_progress", 2, "Should have 2 progress bar");
|
||||
assert.containsN(target, ".o_kanban_group", 2, "Should have 2 grouped column");
|
||||
assert.containsN(target, ".o_kanban_record", 2, "Should have 2 loaded record");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".o_kanban_load_more",
|
||||
"Should have a folded column with a load more button"
|
||||
);
|
||||
await click(target, ".o_kanban_load_more button");
|
||||
assert.containsNone(target, ".o_kanban_load_more", "Shouldn't have a load more button");
|
||||
assert.containsN(target, ".o_kanban_record", 4, "Should have 4 loaded record");
|
||||
});
|
||||
});
|
||||
|
|
@ -61,13 +61,13 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
|
||||
assert.containsN(fixture, ".o_data_row", 4);
|
||||
assert.containsNone(fixture, ".o_list_selection_box");
|
||||
assert.containsOnce(fixture, ".o_control_panel .o_cp_bottom_right");
|
||||
assert.containsOnce(fixture, ".o_control_panel .fa-search");
|
||||
|
||||
// select a record
|
||||
await triggerEvents(fixture, ".o_data_row:nth-child(1)", ["touchstart", "touchend"]);
|
||||
assert.containsOnce(fixture, ".o_list_selection_box");
|
||||
assert.containsNone(fixture, ".o_list_selection_box .o_list_select_domain");
|
||||
assert.containsNone(fixture, ".o_control_panel .o_cp_bottom_right");
|
||||
assert.containsNone(fixture, ".o_control_panel .o_cp_searchview");
|
||||
assert.ok(
|
||||
fixture.querySelector(".o_list_selection_box").textContent.includes("1 selected")
|
||||
);
|
||||
|
|
@ -87,14 +87,14 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
await toggleActionMenu(fixture);
|
||||
assert.deepEqual(
|
||||
getMenuItemTexts(fixture.querySelector(".o_cp_action_menus")),
|
||||
["Delete"],
|
||||
"action menu should contain the Delete action"
|
||||
["Duplicate", "Delete"],
|
||||
"action menu should contain the Duplicate and Delete actions"
|
||||
);
|
||||
|
||||
// unselect all
|
||||
await click(fixture, ".o_discard_selection");
|
||||
await click(fixture, ".o_list_unselect_all");
|
||||
assert.containsNone(fixture, ".o_list_selection_box");
|
||||
assert.containsOnce(fixture, ".o_control_panel .o_cp_bottom_right");
|
||||
assert.containsOnce(fixture, ".o_control_panel .fa-search");
|
||||
});
|
||||
|
||||
QUnit.test("selection box is properly displayed (multi pages)", async function (assert) {
|
||||
|
|
@ -134,8 +134,8 @@ QUnit.module("Mobile Views", ({ beforeEach }) => {
|
|||
await toggleActionMenu(fixture);
|
||||
assert.deepEqual(
|
||||
getMenuItemTexts(fixture.querySelector(".o_cp_action_menus")),
|
||||
["Delete"],
|
||||
"action menu should contain the Delete action"
|
||||
["Duplicate", "Delete"],
|
||||
"action menu should contain the Duplicate and Delete actions"
|
||||
);
|
||||
|
||||
// select all records of first page
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/** @odoo-module */
|
||||
|
||||
import { click, getFixture } from "@web/../tests/helpers/utils";
|
||||
import { click, getFixture, editInput } from "@web/../tests/helpers/utils";
|
||||
import { makeView, setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
|
||||
QUnit.module("ViewDialogs", (hooks) => {
|
||||
|
|
@ -76,8 +76,8 @@ QUnit.module("ViewDialogs", (hooks) => {
|
|||
<field name="linked_sale_order_line" widget="many2many_tags"/>
|
||||
</form>`,
|
||||
async mockRPC(route, args) {
|
||||
if (args.method === "create" && args.model === "sale_order_line") {
|
||||
const { product_id: selectedId } = args.args[0];
|
||||
if (args.method === "web_save" && args.model === "sale_order_line") {
|
||||
const { product_id: selectedId } = args.args[1];
|
||||
assert.strictEqual(selectedId, false, `there should be no product selected`);
|
||||
}
|
||||
},
|
||||
|
|
@ -132,8 +132,8 @@ QUnit.module("ViewDialogs", (hooks) => {
|
|||
<field name="linked_sale_order_line" widget="many2many_tags"/>
|
||||
</form>`,
|
||||
async mockRPC(route, args) {
|
||||
if (args.method === "create" && args.model === "sale_order_line") {
|
||||
const { product_id: selectedId } = args.args[0];
|
||||
if (args.method === "web_save" && args.model === "sale_order_line") {
|
||||
const { product_id: selectedId } = args.args[1];
|
||||
assert.strictEqual(selectedId, 111, `the product should be selected`);
|
||||
}
|
||||
if (args.method === "some_action") {
|
||||
|
|
@ -148,4 +148,42 @@ QUnit.module("ViewDialogs", (hooks) => {
|
|||
await click(target, ".o_form_button_save");
|
||||
assert.verifySteps([]);
|
||||
});
|
||||
|
||||
QUnit.test("SelectCreateDialog: default props, create a record", async function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
serverData.views["product,false,form"] = `<form><field name="display_name"/></form>`;
|
||||
|
||||
await makeView({
|
||||
type: "form",
|
||||
resModel: "sale_order_line",
|
||||
serverData,
|
||||
arch: `
|
||||
<form>
|
||||
<field name="product_id"/>
|
||||
<field name="linked_sale_order_line" widget="many2many_tags"/>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
await click(target, '.o_field_widget[name="product_id"] input');
|
||||
assert.containsOnce(target, ".o_dialog");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".o_dialog .o_kanban_view .o_kanban_record:not(.o_kanban_ghost)"
|
||||
);
|
||||
assert.containsN(target, ".o_dialog footer button", 2);
|
||||
assert.containsOnce(target, ".o_dialog footer button.o_create_button");
|
||||
assert.containsOnce(target, ".o_dialog footer button.o_form_button_cancel");
|
||||
assert.containsNone(target, ".o_dialog .o_control_panel_main_buttons .o-kanban-button-new");
|
||||
|
||||
await click(target.querySelector(".o_dialog footer button.o_create_button"));
|
||||
|
||||
assert.containsN(target, ".o_dialog", 2);
|
||||
assert.containsOnce(target, ".o_dialog .o_form_view");
|
||||
|
||||
await editInput(target, ".o_dialog .o_form_view .o_field_widget input", "hello");
|
||||
await click(target.querySelector(".o_dialog .o_form_button_save"));
|
||||
|
||||
assert.containsNone(target, ".o_dialog");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ QUnit.module("Widgets", (hooks) => {
|
|||
assert.expect(7);
|
||||
patchWithCleanup(SignatureWidget.prototype, {
|
||||
async onClickSignature() {
|
||||
await this._super.apply(this, arguments);
|
||||
await super.onClickSignature(...arguments);
|
||||
assert.step("onClickSignature");
|
||||
},
|
||||
async uploadSignature({signatureImage}) {
|
||||
await this._super.apply(this, arguments);
|
||||
await super.uploadSignature(...arguments);
|
||||
assert.step("uploadSignature");
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/** @odoo-module **/
|
||||
import { click, legacyExtraNextTick } from "@web/../tests/helpers/utils";
|
||||
import { click, nextTick } from "@web/../tests/helpers/utils";
|
||||
import {
|
||||
createWebClient,
|
||||
doAction,
|
||||
|
|
@ -17,6 +17,7 @@ import { companyService } from "@web/webclient/company_service";
|
|||
let serverData;
|
||||
|
||||
const serviceRegistry = registry.category("services");
|
||||
const userMenuRegistry = registry.category("user_menuitems");
|
||||
|
||||
QUnit.module("Burger Menu", {
|
||||
beforeEach() {
|
||||
|
|
@ -59,9 +60,7 @@ QUnit.test("Burger Menu on an App", async (assert) => {
|
|||
|
||||
await createWebClient({ serverData });
|
||||
await click(document.body, ".o_navbar_apps_menu .dropdown-toggle");
|
||||
await legacyExtraNextTick();
|
||||
await click(document.body, ".o_app:nth-of-type(2)");
|
||||
await legacyExtraNextTick();
|
||||
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
|
||||
|
|
@ -72,7 +71,7 @@ QUnit.test("Burger Menu on an App", async (assert) => {
|
|||
document.body.querySelector(".o_burger_menu nav.o_burger_menu_content li").textContent,
|
||||
"SubMenu"
|
||||
);
|
||||
assert.hasClass(document.body.querySelector(".o_burger_menu_content"), "o_burger_menu_dark");
|
||||
assert.hasClass(document.body.querySelector(".o_burger_menu_content"), "o_burger_menu_app");
|
||||
|
||||
await click(document.body, ".o_burger_menu_topbar");
|
||||
assert.doesNotHaveClass(
|
||||
|
|
@ -81,7 +80,7 @@ QUnit.test("Burger Menu on an App", async (assert) => {
|
|||
);
|
||||
|
||||
await click(document.body, ".o_burger_menu_topbar");
|
||||
assert.hasClass(document.body.querySelector(".o_burger_menu_content"), "o_burger_menu_dark");
|
||||
assert.hasClass(document.body.querySelector(".o_burger_menu_content"), "o_burger_menu_app");
|
||||
});
|
||||
|
||||
QUnit.test("Burger Menu on an App without SubMenu", async (assert) => {
|
||||
|
|
@ -89,9 +88,7 @@ QUnit.test("Burger Menu on an App without SubMenu", async (assert) => {
|
|||
|
||||
await createWebClient({ serverData });
|
||||
await click(document.body, ".o_navbar_apps_menu .dropdown-toggle");
|
||||
await legacyExtraNextTick();
|
||||
await click(document.body, ".o_app:nth-of-type(2)");
|
||||
await legacyExtraNextTick();
|
||||
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
|
||||
|
|
@ -111,7 +108,6 @@ QUnit.test("Burger menu closes when an action is requested", async (assert) => {
|
|||
assert.containsOnce(document.body, ".o_burger_menu");
|
||||
|
||||
await doAction(wc, 1);
|
||||
await legacyExtraNextTick();
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
assert.containsOnce(document.body, ".o_kanban_view");
|
||||
});
|
||||
|
|
@ -131,9 +127,7 @@ QUnit.test("Burger menu closes when click on menu item", async (assert) => {
|
|||
};
|
||||
await createWebClient({ serverData });
|
||||
await click(document.body, ".o_navbar_apps_menu .dropdown-toggle");
|
||||
await legacyExtraNextTick();
|
||||
await click(document.body, ".o_app:nth-of-type(2)");
|
||||
await legacyExtraNextTick();
|
||||
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
|
||||
|
|
@ -144,7 +138,30 @@ QUnit.test("Burger menu closes when click on menu item", async (assert) => {
|
|||
"SubMenu"
|
||||
);
|
||||
await click(document.body, ".o_burger_menu nav.o_burger_menu_content li");
|
||||
await legacyExtraNextTick();
|
||||
await legacyExtraNextTick();
|
||||
await nextTick();
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
});
|
||||
|
||||
QUnit.test("Burger menu closes when click on user menu item", async (assert) => {
|
||||
userMenuRegistry.add("ring_item", function () {
|
||||
return {
|
||||
type: "item",
|
||||
id: "ring",
|
||||
description: "Ring",
|
||||
callback: () => {
|
||||
assert.step("callback ring_item");
|
||||
},
|
||||
sequence: 5,
|
||||
};
|
||||
});
|
||||
await createWebClient({ serverData });
|
||||
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
|
||||
await click(document.body, ".o_mobile_menu_toggle");
|
||||
assert.containsOnce(document.body, ".o_burger_menu");
|
||||
|
||||
await click(document.body, ".o_burger_menu .o_user_menu_mobile a");
|
||||
assert.containsNone(document.body, ".o_burger_menu");
|
||||
assert.verifySteps(["callback ring_item"]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { userService } from "@web/core/user_service";
|
|||
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
|
||||
import { makeFakeLocalizationService } from "@web/../tests/helpers/mock_services";
|
||||
import { click, getFixture, mount } from "@web/../tests/helpers/utils";
|
||||
import {markup} from "@odoo/owl";
|
||||
|
||||
const serviceRegistry = registry.category("services");
|
||||
const userMenuRegistry = registry.category("user_menuitems");
|
||||
|
|
@ -84,19 +85,30 @@ QUnit.test("can be rendered", async (assert) => {
|
|||
},
|
||||
};
|
||||
});
|
||||
userMenuRegistry.add("html_item", function () {
|
||||
return {
|
||||
type: "item",
|
||||
id: "html",
|
||||
description: markup(`<div>HTML<i class="fa fa-check px-2"></i></div>`),
|
||||
callback: () => {
|
||||
assert.step("callback html_item");
|
||||
},
|
||||
sequence: 20,
|
||||
};
|
||||
});
|
||||
await mount(BurgerUserMenu, target, { env });
|
||||
assert.containsN(target, ".o_user_menu_mobile .dropdown-item", 4);
|
||||
assert.containsN(target, ".o_user_menu_mobile .dropdown-item", 5);
|
||||
assert.containsOnce(target, ".o_user_menu_mobile .dropdown-item input.form-check-input");
|
||||
assert.containsOnce(target, "div.dropdown-divider");
|
||||
const children = [...(target.querySelector(".o_user_menu_mobile").children || [])];
|
||||
assert.deepEqual(
|
||||
children.map((el) => el.tagName),
|
||||
["A", "A", "DIV", "DIV", "A"]
|
||||
["A", "A", "DIV", "DIV", "A", "A"]
|
||||
);
|
||||
const items = [...target.querySelectorAll(".dropdown-item")] || [];
|
||||
assert.deepEqual(
|
||||
items.map((el) => el.textContent),
|
||||
["Ring", "Bad", "Frodo", "Eye"]
|
||||
["Ring", "Bad", "Frodo", "HTML", "Eye"]
|
||||
);
|
||||
for (const item of items) {
|
||||
click(item);
|
||||
|
|
@ -105,6 +117,7 @@ QUnit.test("can be rendered", async (assert) => {
|
|||
"callback ring_item",
|
||||
"callback bad_item",
|
||||
"callback frodo_item",
|
||||
"callback html_item",
|
||||
"callback eye_item",
|
||||
]);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -49,36 +49,20 @@ QUnit.module("Mobile SettingsFormView", (hooks) => {
|
|||
serverData,
|
||||
arch: `
|
||||
<form string="Settings" class="oe_form_configuration o_base_settings" js_class="base_settings">
|
||||
<div class="o_setting_container">
|
||||
<div class="settings">
|
||||
<div class="app_settings_block" string="CRM" data-key="crm">
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="bar"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="bar"/>
|
||||
<div class="text-muted">this is bar</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app_settings_block" string="Project" data-key="project">
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="foo"/>
|
||||
<div class="text-muted">this is foo</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting help="this is bar">
|
||||
<field name="bar"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
<app string="Project" name="project">
|
||||
<block>
|
||||
<setting help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
|
|
@ -125,36 +109,20 @@ QUnit.module("Mobile SettingsFormView", (hooks) => {
|
|||
serverData,
|
||||
arch: `
|
||||
<form string="Settings" class="oe_form_configuration o_base_settings" js_class="base_settings">
|
||||
<div class="o_setting_container">
|
||||
<div class="settings">
|
||||
<div class="app_settings_block" string="CRM" data-key="crm">
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="bar"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="bar"/>
|
||||
<div class="text-muted">this is bar</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app_settings_block" string="Project" data-key="project">
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="foo"/>
|
||||
</div>
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="foo"/>
|
||||
<div class="text-muted">this is foo</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<app string="CRM" name="crm">
|
||||
<block>
|
||||
<setting help="this is bar">
|
||||
<field name="bar"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
<app string="Project" name="project">
|
||||
<block>
|
||||
<setting help="this is foo">
|
||||
<field name="foo"/>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</form>`,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
/** @odoo-module **/
|
||||
|
||||
import { getFixture } from "@web/../tests/helpers/utils";
|
||||
import { setupViewRegistries } from "@web/../tests/views/helpers";
|
||||
import { createWebClient, doAction } from "@web/../tests/webclient/helpers";
|
||||
|
||||
let serverData, target;
|
||||
|
||||
QUnit.module("ActionManager", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
serverData = {
|
||||
models: {
|
||||
project: {
|
||||
fields: {
|
||||
foo: { string: "Foo", type: "boolean" },
|
||||
},
|
||||
records: [
|
||||
{
|
||||
id: 1,
|
||||
foo: true,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
foo: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
"project,false,list": '<list><field name="foo"/></list>',
|
||||
"project,false,kanban": `
|
||||
<kanban>
|
||||
<templates>
|
||||
<t t-name='kanban-box'>
|
||||
<div class='oe_kanban_card'>
|
||||
<field name='foo' />
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
`,
|
||||
"project,false,search": "<search></search>",
|
||||
},
|
||||
};
|
||||
target = getFixture();
|
||||
setupViewRegistries();
|
||||
});
|
||||
|
||||
QUnit.module("Window Actions");
|
||||
|
||||
QUnit.test("execute a window action with mobile_view_mode", async (assert) => {
|
||||
const webClient = await createWebClient({ serverData });
|
||||
await doAction(webClient, {
|
||||
xml_id: "project.action",
|
||||
name: "Project Action",
|
||||
res_model: "project",
|
||||
type: "ir.actions.act_window",
|
||||
view_mode: "list,kanban",
|
||||
mobile_view_mode: "list",
|
||||
views: [
|
||||
[false, "kanban"],
|
||||
[false, "list"],
|
||||
],
|
||||
});
|
||||
assert.containsOnce(target, ".o_list_view");
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue