[REF] web: use LegacyComponent

This commit replaces Component by LegacyComponent when the component
uses removed features from owl 1 like getting its `el` or `trigger` an event.
Some tests are updated to have less LegacyComponent.

Part-of: odoo/odoo#85389
This commit is contained in:
Michael (mcm)
2022-03-01 09:57:39 +00:00
parent d6946775a2
commit 4dc2b2e539
109 changed files with 2084 additions and 1930 deletions
@@ -7,6 +7,7 @@ import { registry } from "@web/core/registry";
import { capitalize } from "@web/core/utils/strings";
import { getVisibleElements } from "@web/core/utils/ui";
import { DefaultCommandItem } from "./command_palette";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component } = owl;
@@ -15,7 +16,7 @@ commandSetupRegistry.add("default", {
emptyMessage: _lt("No command found"),
});
export class HotkeyCommandItem extends Component {
export class HotkeyCommandItem extends LegacyComponent {
setup() {
useHotkey(this.props.hotkey, () => {
this.trigger("execute-command");
@@ -3,6 +3,7 @@
import { localization } from "@web/core/l10n/localization";
import { registry } from "@web/core/registry";
import { useAutofocus } from "@web/core/utils/hooks";
import { LegacyComponent } from "@web/legacy/legacy_component";
const {
Component,
@@ -49,7 +50,7 @@ const luxonFormatToMomentFormat = (format) => {
* stringified since tempusdominus only works with moment objects.
* @extends Component
*/
export class DatePicker extends Component {
export class DatePicker extends LegacyComponent {
setup() {
this.inputRef = useRef("input");
this.state = useState({ warning: false });
+2 -1
View File
@@ -2,10 +2,11 @@
import { useHotkey } from "@web/core/hotkeys/hotkey_hook";
import { useActiveElement } from "../ui/ui_service";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useRef, useChildSubEnv, xml } = owl;
export class Dialog extends Component {
export class Dialog extends LegacyComponent {
setup() {
if (this.constructor === Dialog) {
throw new Error(
+13 -13
View File
@@ -4,6 +4,7 @@ import { useBus, useService } from "@web/core/utils/hooks";
import { usePosition } from "../position/position_hook";
import { useDropdownNavigation } from "./dropdown_navigation_hook";
import { localization } from "../l10n/localization";
import { LegacyComponent } from "@web/legacy/legacy_component";
const {
Component,
@@ -40,12 +41,13 @@ export const DROPDOWN = Symbol("Dropdown");
/**
* @extends Component
*/
export class Dropdown extends Component {
export class Dropdown extends LegacyComponent {
setup() {
this.state = useState({
open: this.props.startOpen,
groupIsOpen: this.props.startOpen,
});
this.rootRef = useRef("root");
// Set up beforeOpen ---------------------------------------------------
onWillStart(() => {
@@ -105,10 +107,7 @@ export class Dropdown extends Component {
}
position = [direction, variant].join("-");
}
const positioningOptions = {
popper: "menuRef",
position,
};
const positioningOptions = { position };
this.directionCaretClass = DIRECTION_CARET_CLASS[direction];
this.togglerRef = useRef("togglerRef");
if (this.props.toggler === "parent") {
@@ -116,26 +115,26 @@ export class Dropdown extends Component {
useEffect(
() => {
const onClick = (ev) => {
if (this.el.contains(ev.target)) {
if (this.rootRef.el.contains(ev.target)) {
// ignore clicks inside the dropdown
return;
}
this.toggle();
};
this.el.parentElement.addEventListener("click", onClick);
this.rootRef.el.parentElement.addEventListener("click", onClick);
return () => {
this.el.parentElement.removeEventListener("click", onClick);
this.rootRef.el.parentElement.removeEventListener("click", onClick);
};
},
() => []
);
// Position menu relatively to parent element
usePosition(() => this.el.parentElement, positioningOptions);
usePosition(() => this.rootRef.el.parentElement, "menuRef", positioningOptions);
} else {
// Position menu relatively to inner toggler
const togglerRef = useRef("togglerRef");
usePosition(() => togglerRef.el, positioningOptions);
usePosition(() => togglerRef.el, "menuRef", positioningOptions);
}
}
@@ -211,13 +210,13 @@ export class Dropdown extends Component {
* @param {DropdownStateChangedPayload} args
*/
onDropdownStateChanged(args) {
if (this.el.contains(args.emitter.el)) {
if (this.rootRef.el.contains(args.emitter.rootRef.el)) {
// Do not listen to events emitted by self or children
return;
}
// Emitted by direct siblings ?
if (args.emitter.el.parentElement === this.el.parentElement) {
if (args.emitter.rootRef.el.parentElement === this.rootRef.el.parentElement) {
// Sync the group status
this.state.groupIsOpen = args.newState.groupIsOpen;
@@ -266,7 +265,8 @@ export class Dropdown extends Component {
}
// Close if we clicked outside the dropdown, or outside the parent
// element if it is the toggler
const rootEl = this.props.toggler === "parent" ? this.el.parentElement : this.el;
const rootEl =
this.props.toggler === "parent" ? this.rootRef.el.parentElement : this.rootRef.el;
const gotClickedInside = rootEl.contains(ev.target);
if (!gotClickedInside) {
this.close();
@@ -10,6 +10,7 @@
{{ state.open ? 'show' : ''}}
{{ !parentDropdown ? 'o-dropdown--no-caret' : '' }}
"
t-ref="root"
>
<button
t-if="props.toggler !== 'parent'"
@@ -1,5 +1,6 @@
/** @odoo-module **/
import { DROPDOWN } from "./dropdown";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component } = owl;
@@ -12,7 +13,7 @@ const ParentClosingMode = {
AllParents: "all",
};
export class DropdownItem extends Component {
export class DropdownItem extends LegacyComponent {
/**
* Tells the parent dropdown that an item was selected and closes the
* parent(s) dropdown according the the parentClosingMode prop.
@@ -1,6 +1,7 @@
/** @odoo-module **/
import { browser } from "@web/core/browser/browser";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useEffect, useExternalListener } = owl;
@@ -33,7 +34,7 @@ const { Component, useEffect, useExternalListener } = owl;
* importing this file. The usual way to do that would be to use the effect
* service (by triggering the 'show_effect' event)
*/
export class RainbowMan extends Component {
export class RainbowMan extends LegacyComponent {
setup() {
useExternalListener(document.body, "click", this.closeRainbowMan);
this.delay = RainbowMan.rainbowFadeouts[this.props.fadeout];
@@ -1,6 +1,7 @@
/** @odoo-module **/
import { useService } from "@web/core/utils/hooks";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useRef } = owl;
@@ -22,7 +23,7 @@ const { Component, useRef } = owl;
* @param {string} [props.multi_upload=false] Whether the input should allow
* to upload multiple files at once.
*/
export class FileInput extends Component {
export class FileInput extends LegacyComponent {
setup() {
this.http = useService("http");
this.fileInputRef = useRef("file-input");
@@ -25,7 +25,7 @@ export class MainComponentsContainer extends Component {
}
MainComponentsContainer.template = xml`
<div>
<div class="o-main-components-container">
<t t-foreach="Components" t-as="C" t-key="C[0]">
<ErrorHandler onError="error => this.handleComponentError(error, C)">
<t t-component="C[1].Component" t-props="C[1].props"/>
@@ -6,7 +6,7 @@ const { Component } = owl;
export class Popover extends Component {
setup() {
usePosition(this.props.target, {
usePosition(this.props.target, "popper", {
margin: 16,
position: this.props.position,
});
@@ -6,6 +6,7 @@
t-att-class="props.popoverClass"
t-on-popover-compute="compute"
t-on-popover-closed="props.close"
t-ref="popper"
>
<t t-slot="default" />
</div>
@@ -2,11 +2,10 @@
import { throttleForAnimation } from "../utils/timing";
const { onWillUnmount, useComponent, useEffect, useExternalListener, useRef } = owl;
const { onWillUnmount, useEffect, useExternalListener, useRef } = owl;
/**
* @typedef {{
* popper?: string;
* container?: HTMLElement;
* margin?: number;
* position?: Position;
@@ -233,12 +232,12 @@ function reposition(reference, popper, options) {
* the original position is used.
*
* @param {HTMLElement | (()=>HTMLElement)} reference
* @param {string} popper
* @param {Options} options
*/
export function usePosition(reference, options) {
export function usePosition(reference, popper, options) {
options = { ...DEFAULTS, ...options };
const { popper } = options;
const popperRef = popper ? useRef(popper) : useComponent();
const popperRef = useRef(popper);
const getReference = reference instanceof HTMLElement ? () => reference : reference;
const update = () => {
const ref = getReference();
+6 -3
View File
@@ -6,7 +6,7 @@ import { debounce } from "@web/core/utils/timing";
import { BlockUI } from "./block_ui";
import { browser } from "@web/core/browser/browser";
const { EventBus, useComponent, useEffect, useRef } = owl;
const { EventBus, useEffect, useRef } = owl;
export const SIZES = { XS: 0, VSM: 1, SM: 2, MD: 3, LG: 4, XL: 5, XXL: 6 };
@@ -21,9 +21,12 @@ export const SIZES = { XS: 0, VSM: 1, SM: 2, MD: 3, LG: 4, XL: 5, XXL: 6 };
*
* @param {string} refName
*/
export function useActiveElement(refName = null) {
export function useActiveElement(refName) {
if (!refName) {
throw new Error("refName not given to useActiveElement");
}
const uiService = useService("ui");
const owner = refName ? useRef(refName) : useComponent();
const owner = useRef(refName);
useEffect(
(el) => {
if (el) {
@@ -4,6 +4,7 @@ odoo.define('web.ActionMenus', function (require) {
const Context = require('web.Context');
const DropdownMenu = require('web.DropdownMenu');
const Registry = require('web.Registry');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const {
Component,
@@ -27,7 +28,7 @@ odoo.define('web.ActionMenus', function (require) {
* Action menu.
* @extends Component
*/
class ActionMenus extends Component {
class ActionMenus extends LegacyComponent {
setup() {
onWillStart(async () => {
this.actionItems = await this._setActionItems(this.props);
@@ -2,6 +2,7 @@ odoo.define('web.CustomCheckbox', function (require) {
"use strict";
const utils = require('web.utils');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component } = owl;
@@ -19,7 +20,7 @@ odoo.define('web.CustomCheckbox', function (require) {
*
* @extends Component
*/
class CustomCheckbox extends Component {
class CustomCheckbox extends LegacyComponent {
/**
* @param {Object} [props]
* @param {string | number | null} [props.id]
@@ -1,6 +1,7 @@
odoo.define('web.CustomFileInput', function (require) {
"use strict";
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useRef } = owl;
/**
@@ -11,7 +12,7 @@ odoo.define('web.CustomFileInput', function (require) {
* prompt.
* @extends Component
*/
class CustomFileInput extends Component {
class CustomFileInput extends LegacyComponent {
/**
* @param {Object} [props]
* @param {string} [props.accepted_file_extensions='*'] Comma-separated
@@ -4,6 +4,7 @@ odoo.define('web.DatePickerOwl', function (require) {
const field_utils = require('web.field_utils');
const time = require('web.time');
const { useAutofocus } = require("@web/core/utils/hooks");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const {
Component,
@@ -30,7 +31,7 @@ odoo.define('web.DatePickerOwl', function (require) {
* to this component will be passed as arguments to instantiate the picker widget).
* @extends Component
*/
class DatePicker extends Component {
class DatePicker extends LegacyComponent {
setup() {
this.state = useState({ warning: false });
@@ -3,6 +3,7 @@ odoo.define('web.DropdownMenu', function (require) {
const { _t } = require('web.core');
const DropdownMenuItem = require('web.DropdownMenuItem');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useExternalListener, useRef, useState } = owl;
@@ -27,7 +28,7 @@ odoo.define('web.DropdownMenu', function (require) {
* the behaviour of these items, @see DropdownMenuItem.
* @extends Component
*/
class DropdownMenu extends Component {
class DropdownMenu extends LegacyComponent {
setup() {
this.dropdownMenu = useRef('dropdown');
this.state = useState({ open: false });
@@ -2,6 +2,7 @@ odoo.define('web.DropdownMenuItem', function (require) {
"use strict";
const { useListener } = require("@web/core/utils/hooks");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useExternalListener, useRef, useState } = owl;
@@ -26,7 +27,7 @@ odoo.define('web.DropdownMenuItem', function (require) {
* be put inside of a dropdown menu (@see CustomFilterItem as example).
* @extends Component
*/
class DropdownMenuItem extends Component {
class DropdownMenuItem extends LegacyComponent {
setup() {
this.canBeOpened = Boolean(this.props.options && this.props.options.length);
@@ -2,6 +2,7 @@ odoo.define('web.Pager', function (require) {
"use strict";
const { useAutofocus } = require("@web/core/utils/hooks");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, onWillUpdateProps, useState } = owl;
@@ -18,7 +19,7 @@ odoo.define('web.Pager', function (require) {
* or previous).
* @extends Component
*/
class Pager extends Component {
class Pager extends LegacyComponent {
/**
* @param {Object} [props]
* @param {int} [props.size] the total number of elements
@@ -5,10 +5,11 @@ odoo.define("web.ComparisonMenu", function (require) {
const { DropdownItem } = require("@web/core/dropdown/dropdown_item");
const { FACET_ICONS } = require("web.searchUtils");
const { useModel } = require("web.Model");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component } = owl;
class ComparisonMenu extends Component {
class ComparisonMenu extends LegacyComponent {
setup() {
this.icon = FACET_ICONS.comparison;
this.model = useModel('searchModel');
@@ -10,6 +10,7 @@ odoo.define('web.ControlPanel', function (require) {
const Pager = require('web.Pager');
const SearchBar = require('web.SearchBar');
const { useModel } = require('web.Model');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const {
Component,
@@ -104,7 +105,7 @@ odoo.define('web.ControlPanel', function (require) {
* inheritance mechanism when converting the views/actions.
* @extends Component
*/
class ControlPanel extends Component {
class ControlPanel extends LegacyComponent {
setup() {
this.additionalContent = getAdditionalContent(this.props);
@@ -6,6 +6,7 @@ odoo.define('web.CustomFavoriteItem', function (require) {
const FavoriteMenu = require('web.FavoriteMenu');
const { useAutofocus } = require("@web/core/utils/hooks");
const { useModel } = require('web.Model');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useState } = owl;
@@ -30,7 +31,7 @@ odoo.define('web.CustomFavoriteItem', function (require) {
* Finally, there is a 'Save' button used to apply the current configuration
* and save the context to a new filter.
*/
class CustomFavoriteItem extends Component {
class CustomFavoriteItem extends LegacyComponent {
setup() {
const favId = favoriteId++;
this.useByDefaultId = `o_favorite_use_by_default_${favId}`;
@@ -8,6 +8,7 @@ odoo.define('web.CustomFilterItem', function (require) {
const { FIELD_OPERATORS, FIELD_TYPES } = require('web.searchUtils');
const field_utils = require('web.field_utils');
const { useModel } = require('web.Model');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useState } = owl;
@@ -43,7 +44,7 @@ odoo.define('web.CustomFilterItem', function (require) {
* [date_field, '<=', y],
* ]
*/
class CustomFilterItem extends Component {
class CustomFilterItem extends LegacyComponent {
setup() {
this.model = useModel('searchModel');
@@ -7,6 +7,7 @@ odoo.define('web.FavoriteMenu', function (require) {
const { FACET_ICONS } = require("web.searchUtils");
const Registry = require('web.Registry');
const { useModel } = require('web.Model');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useState } = owl;
@@ -19,7 +20,7 @@ odoo.define('web.FavoriteMenu', function (require) {
* Only the favorite generator (@see CustomFavoriteItem) is registered in
* the `web` module.
*/
class FavoriteMenu extends Component {
class FavoriteMenu extends LegacyComponent {
setup() {
this.icon = FACET_ICONS.favorite;
this.model = useModel('searchModel');
@@ -6,6 +6,7 @@ odoo.define('web.FilterMenu', function (require) {
const CustomFilterItem = require('web.CustomFilterItem');
const { FACET_ICONS } = require("web.searchUtils");
const { useModel } = require('web.Model');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component } = owl;
@@ -16,7 +17,7 @@ odoo.define('web.FilterMenu', function (require) {
* model. It uses most of the behaviours implemented by the dropdown menu Component,
* with the addition of a filter generator (@see CustomFilterItem).
*/
class FilterMenu extends Component {
class FilterMenu extends LegacyComponent {
setup() {
this.icon = FACET_ICONS.filter;
@@ -6,10 +6,11 @@ odoo.define('web.GroupByMenu', function (require) {
const { CustomGroupByItem } = require('@web/search/group_by_menu/custom_group_by_item');
const { FACET_ICONS, GROUPABLE_TYPES } = require('web.searchUtils');
const { useModel } = require('web.Model');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component } = owl;
class GroupByMenu extends Component {
class GroupByMenu extends LegacyComponent {
setup() {
this.icon = FACET_ICONS.groupBy;
@@ -6,6 +6,7 @@ odoo.define('web.SearchBar', function (require) {
const { useAutofocus } = require("@web/core/utils/hooks");
const { useModel } = require('web.Model');
const { fuzzyTest } = require('@web/core/utils/search');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, onMounted, onWillUnmount, toRaw, useExternalListener, useState } = owl;
const CHAR_FIELDS = ['char', 'html', 'many2many', 'many2one', 'one2many', 'text'];
@@ -36,7 +37,7 @@ odoo.define('web.SearchBar', function (require) {
* records having this exact value.
* @extends Component
*/
class SearchBar extends Component {
class SearchBar extends LegacyComponent {
setup() {
this.inputRef = useAutofocus();
this.model = useModel('searchModel');
@@ -8,6 +8,7 @@ odoo.define('web.OwlDialog', function (require) {
'small': 'modal-sm',
};
const { renderToString } = require('@web/core/utils/render');
const { LegacyComponent } = require("@web/legacy/legacy_component");
/**
* Dialog (owl version)
@@ -16,7 +17,7 @@ odoo.define('web.OwlDialog', function (require) {
* is roughly the same as the legacy dialog, the only exception being the buttons.
* @extends Component
**/
class Dialog extends Component {
class Dialog extends LegacyComponent {
/**
* @param {Object} [props]
* @param {(boolean|string)} [props.backdrop='static'] The kind of modal backdrop
@@ -1,6 +1,7 @@
odoo.define('web.Popover', function (require) {
'use strict';
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, status, onWillUnmount, useEffect, useRef, useState } = owl;
/**
@@ -11,7 +12,7 @@ odoo.define('web.Popover', function (require) {
* CSS pseudo-element.
* @extends Component
**/
class Popover extends Component {
class Popover extends LegacyComponent {
/**
* @param {Object} props
* @param {String} [props.position='bottom']
@@ -3,6 +3,7 @@ odoo.define('web.AbstractFieldOwl', function (require) {
const field_utils = require('web.field_utils');
const { useListener } = require("@web/core/utils/hooks");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, onWillUpdateProps, useEffect } = owl;
@@ -45,7 +46,7 @@ odoo.define('web.AbstractFieldOwl', function (require) {
*
* @module web.AbstractFieldOwl
*/
class AbstractField extends Component {
class AbstractField extends LegacyComponent {
/**
* Abstract field class
*
@@ -1,6 +1,8 @@
odoo.define('web.OwlCompatibility', function (require) {
"use strict";
const { LegacyComponent } = require("@web/legacy/legacy_component");
/**
* This file defines the necessary tools for the transition phase where Odoo
* legacy widgets and Owl components will coexist. There are two possible
@@ -84,7 +86,7 @@ odoo.define('web.OwlCompatibility', function (require) {
* }
* }
*/
class ComponentAdapter extends Component {
class ComponentAdapter extends LegacyComponent {
/**
* Creates the template on-the-fly, depending on the type of Component
* (legacy widget or Owl component).
@@ -479,7 +481,7 @@ odoo.define('web.OwlCompatibility', function (require) {
/**
* The component class that will be instanciated between a legacy and an OWL 2 layer.
*/
class ProxyComponent extends Component {
class ProxyComponent extends LegacyComponent {
setup() {
onMounted(() => {
this.props.mounted();
@@ -1,5 +1,6 @@
/** @odoo-module alias=web.AbstractRendererOwl **/
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onMounted, onPatched } = owl;
// Renderers may display sample data when there is no real data to display. In
@@ -13,7 +14,7 @@ const FOCUSABLE_ELEMENTS = [
'[tabindex="0"]'
].map((sel) => `:scope ${sel}`).join(', ');
class AbstractRenderer extends Component {
class AbstractRenderer extends LegacyComponent {
setup() {
// Defines the elements suppressed when in demo data. This must be a list
@@ -6,10 +6,11 @@
import field_utils from 'web.field_utils';
import { INTERVAL_OPTIONS, getIntervalOptions } from 'web.searchUtils';
import { CustomGroupByItem } from "@web/search/group_by_menu/custom_group_by_item";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useEffect, useExternalListener, useState } = owl;
export class PivotGroupByMenu extends Component {
export class PivotGroupByMenu extends LegacyComponent {
constructor() {
super(...arguments);
@@ -1,6 +1,7 @@
/** @odoo-module alias=web.searchPanel **/
import { Model, useModel } from "web.Model";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onMounted, onWillStart, onWillUpdateProps, useRef, useState, useSubEnv } = owl;
@@ -14,7 +15,7 @@
* Its state is directly affected by its model (@see SearchPanelModelExtension).
* @extends Component
*/
class SearchPanel extends Component {
class SearchPanel extends LegacyComponent {
setup() {
useSubEnv({ searchModel: this.props.searchModel });
@@ -4,10 +4,11 @@ odoo.define('web.WeekDays', function (require) {
const CustomCheckbox = require('web.CustomCheckbox');
const Registry = require('web.widgetRegistry');
const utils = require('web.utils');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, onWillUpdateProps, useState } = owl;
class WeekDays extends Component {
class WeekDays extends LegacyComponent {
setup() {
this.weekdaysShort = [];
this._sortWeekdays();
@@ -8,6 +8,7 @@ import { useSetupAction } from "../webclient/actions/action_hook";
import { ClientActionAdapter } from "./action_adapters";
import { breadcrumbsToLegacy } from "./backend_utils";
import { useLegacyRefs } from "./utils";
import { LegacyComponent } from "./legacy_component";
const { Component, xml } = owl;
const actionRegistry = registry.category("actions");
@@ -21,7 +22,7 @@ const legacyClientActionTemplate = xml`
function registerClientAction(name, action) {
if (action.prototype instanceof Widget) {
// the action is a widget, wrap it into a Component and register that component
class Action extends Component {
class Action extends LegacyComponent {
setup() {
this.Widget = action;
const options = {};
+2 -1
View File
@@ -14,6 +14,7 @@ import {
} from "./backend_utils";
import { registry } from "@web/core/registry";
import { loadPublicAsset } from "@web/core/assets";
import { LegacyComponent } from "./legacy_component";
const { Component, xml, onWillStart } = owl;
const viewRegistry = registry.category("views");
@@ -31,7 +32,7 @@ const legacyViewTemplate = xml`
// registers a view from the legacy view registry to the wowl one, but wrapped
// into an Owl Component
function registerView(name, LegacyView) {
class Controller extends Component {
class Controller extends LegacyComponent {
setup() {
this.vm = useService("view");
this.Widget = Widget; // fool the ComponentAdapter with a simple Widget
@@ -3,6 +3,7 @@
import { ComponentAdapter } from "web.OwlCompatibility";
import * as legacySystrayMenu from "web.SystrayMenu";
import { registry } from "../core/registry";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
const systrayRegistry = registry.category("systray");
@@ -25,9 +26,8 @@ const legacySystrayItemTemplate = xml`<SystrayItemAdapter Component="Widget" />`
function addSystrayItem(Widget) {
const name = `_legacy_systray_item_${id++}`;
class SystrayItem extends Component {
constructor() {
super(...arguments);
class SystrayItem extends LegacyComponent {
setup() {
this.Widget = Widget;
}
}
@@ -1,10 +1,11 @@
/** @odoo-module **/
import { Dropdown } from "@web/core/dropdown/dropdown";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useState } = owl;
export class CustomGroupByItem extends Component {
export class CustomGroupByItem extends LegacyComponent {
setup() {
this.state = useState({});
if (this.props.fields.length) {
@@ -6,6 +6,7 @@ import { registry } from "@web/core/registry";
import { KeepLast } from "@web/core/utils/concurrency";
import { useAutofocus, useBus, useService } from "@web/core/utils/hooks";
import { fuzzyTest } from "@web/core/utils/search";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useExternalListener, useState } = owl;
const parsers = registry.category("parsers");
@@ -14,7 +15,7 @@ const CHAR_FIELDS = ["char", "html", "many2many", "many2one", "one2many", "text"
let nextItemId = 1;
export class SearchBar extends Component {
export class SearchBar extends LegacyComponent {
setup() {
this.fields = this.env.searchModel.searchViewFields;
this.searchItems = this.env.searchModel.getSearchItems((f) => f.type === "field");
@@ -1,5 +1,7 @@
/** @odoo-module **/
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onMounted, onWillStart, onWillUpdateProps, useState } = owl;
/**
@@ -11,7 +13,7 @@ const { Component, onMounted, onWillStart, onWillUpdateProps, useState } = owl;
* values (categories or ungrouped filters) or groups of values (grouped filters).
* Its state is directly affected by its model (@see SearchModel).
*/
export class SearchPanel extends Component {
export class SearchPanel extends LegacyComponent {
setup() {
this.state = useState({
active: {},
@@ -3,13 +3,14 @@
import { useBus, useService } from "@web/core/utils/hooks";
import { SearchModel } from "@web/search/search_model";
import { CallbackRecorder, useSetupAction } from "@web/webclient/actions/action_hook";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onWillStart, onWillUpdateProps, toRaw, useSubEnv } = owl;
export const SEARCH_KEYS = ["comparison", "context", "domain", "groupBy", "orderBy"];
const OTHER_SEARCH_KEYS = ["irFilters", "searchViewArch", "searchViewFields", "searchViewId"];
export class WithSearch extends Component {
export class WithSearch extends LegacyComponent {
setup() {
this.Component = this.props.Component;
@@ -7,6 +7,7 @@ import { SEP } from "./graph_model";
import { sortBy } from "@web/core/utils/arrays";
import { useAssets } from "@web/core/assets";
import { renderToString } from "@web/core/utils/render";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onWillUnmount, useEffect, useRef } = owl;
@@ -38,7 +39,7 @@ function shortenLabel(label) {
return shortLabel;
}
export class GraphRenderer extends Component {
export class GraphRenderer extends LegacyComponent {
setup() {
this.model = this.props.model;
@@ -13,11 +13,12 @@ import { useModel } from "../helpers/model";
import { GraphArchParser } from "./graph_arch_parser";
import { GraphModel } from "./graph_model";
import { GraphRenderer } from "./graph_renderer";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component } = owl;
const viewRegistry = registry.category("views");
export class GraphView extends Component {
export class GraphView extends LegacyComponent {
setup() {
this.actionService = useService("action");
+2 -1
View File
@@ -2,6 +2,7 @@
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { SearchPanel } from "@web/search/search_panel/search_panel";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component } = owl;
@@ -17,7 +18,7 @@ export const extractLayoutComponents = (params) => {
};
};
export class Layout extends Component {
export class Layout extends LegacyComponent {
setup() {
const { display = {} } = this.env.searchModel || {};
this.components = extractLayoutComponents(this.env.config);
@@ -3,10 +3,11 @@
import { loadAssets } from "@web/core/assets";
import { useService } from "@web/core/utils/hooks";
import { useActionLinks } from "@web/views/helpers/view_hook";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, markup, onWillStart, xml } = owl;
export class OnboardingBanner extends Component {
export class OnboardingBanner extends LegacyComponent {
setup() {
this.rpc = useService("rpc");
this.user = useService("user");
@@ -5,11 +5,12 @@ import { localization } from "@web/core/l10n/localization";
import { registry } from "@web/core/registry";
import { PivotGroupByMenu } from "@web/views/pivot/pivot_group_by_menu";
import fieldUtils from "web.field_utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onWillUpdateProps } = owl;
const formatterRegistry = registry.category("formatters");
export class PivotRenderer extends Component {
export class PivotRenderer extends LegacyComponent {
setup() {
this.model = this.props.model;
this.table = this.model.getTable();
@@ -13,11 +13,12 @@ import { Layout } from "@web/views/layout";
import { PivotArchParser } from "@web/views/pivot/pivot_arch_parser";
import { PivotModel } from "@web/views/pivot/pivot_model";
import { PivotRenderer } from "@web/views/pivot/pivot_renderer";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component } = owl;
const viewRegistry = registry.category("views");
export class PivotView extends Component {
export class PivotView extends LegacyComponent {
setup() {
this.actionService = useService("action");
+2 -1
View File
@@ -8,6 +8,7 @@ import { deepCopy } from "@web/core/utils/objects";
import { WithSearch } from "@web/search/with_search/with_search";
import { useActionLinks } from "@web/views/helpers/view_hook";
import { extractLayoutComponents } from "@web/views/layout";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onWillUpdateProps, onWillStart, toRaw, useSubEnv } = owl;
const viewRegistry = registry.category("views");
@@ -124,7 +125,7 @@ const STANDARD_PROPS = [
"searchModel",
];
export class View extends Component {
export class View extends LegacyComponent {
setup() {
const { arch, fields, resModel, searchViewArch, searchViewFields, type } = this.props;
@@ -6,6 +6,7 @@ import { useService, useBus } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { debounce } from "@web/core/utils/timing";
import { ErrorHandler } from "@web/core/utils/components";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onWillDestroy, useExternalListener, useEffect, useRef } = owl;
const systrayRegistry = registry.category("systray");
@@ -30,7 +31,7 @@ MenuDropdown.props.xmlid = {
optional: true,
};
export class NavBar extends Component {
export class NavBar extends LegacyComponent {
setup() {
this.currentAppSectionsExtra = [];
this.actionService = useService("action");
@@ -6,10 +6,11 @@ import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { browser } from "@web/core/browser/browser";
import { symmetricalDifference } from "@web/core/utils/arrays";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useState } = owl;
export class SwitchCompanyMenu extends Component {
export class SwitchCompanyMenu extends LegacyComponent {
setup() {
this.companyService = useService("company");
this.currentCompany = this.companyService.currentCompany;
@@ -34,9 +34,12 @@ QUnit.module("Components", (hooks) => {
Parent.template = xml`<CheckBox>ragabadabadaba</CheckBox>`;
Parent.components = { CheckBox };
const parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
assert.containsOnce(target, "div.custom-checkbox");
assert.strictEqual(parent.el.innerText, "rugubudubudubu");
assert.strictEqual(
target.querySelector("div.custom-checkbox").textContent,
"rugubudubudubu"
);
});
QUnit.test("call onChange prop when some change occurs", async (assert) => {
@@ -20,6 +20,7 @@ import {
patchWithCleanup,
triggerHotkey,
} from "../../helpers/utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
@@ -36,7 +37,7 @@ export async function editSearchBar(searchValue) {
await nextTick();
}
class TestComponent extends Component {
class TestComponent extends LegacyComponent {
get DialogContainer() {
return registry.category("main_components").get("DialogContainer");
}
@@ -136,13 +137,13 @@ QUnit.test("useCommand hook when the activeElement change", async (assert) => {
}
}
class OtherComponent extends Component {
class OtherComponent extends LegacyComponent {
setup() {
useActiveElement();
useActiveElement("active");
useCommand("I'm taking the throne", () => {});
}
}
OtherComponent.template = xml`<div></div>`;
OtherComponent.template = xml`<div t-ref="active"></div>`;
await mount(MyComponent, target, { env });
triggerHotkey("control+k");
@@ -199,12 +200,12 @@ QUnit.test("global command with hotkey", async (assert) => {
await nextTick();
assert.verifySteps([globalHotkey, hotkey]);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useActiveElement();
useActiveElement("active");
}
}
MyComponent.template = xml`<div></div>`;
MyComponent.template = xml`<div t-ref="active"></div>`;
await mount(MyComponent, target, { env });
triggerHotkey("a");
@@ -217,7 +218,7 @@ QUnit.test("global command with hotkey", async (assert) => {
QUnit.test("data-hotkey added to command palette", async (assert) => {
assert.expect(8);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
onClick() {
assert.step("Hodor");
}
@@ -277,7 +278,7 @@ QUnit.test("access to hotkeys from the command palette", async (assert) => {
hotkey,
});
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
onClickB() {
assert.step("B");
}
@@ -762,7 +763,7 @@ QUnit.test("command categories", async (assert) => {
QUnit.test("data-command-category", async (assert) => {
assert.expect(3);
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.components = { TestComponent };
MyComponent.template = xml`
<div>
@@ -803,7 +804,7 @@ QUnit.test("data-command-category", async (assert) => {
});
QUnit.test("display shortcuts correctly for non-MacOS ", async (assert) => {
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.components = { TestComponent };
MyComponent.template = xml`
<div>
@@ -844,7 +845,7 @@ QUnit.test("display shortcuts correctly for MacOS ", async (assert) => {
},
});
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.components = { TestComponent };
MyComponent.template = xml`
<div>
@@ -886,7 +887,7 @@ QUnit.test(
overlayModifier: "alt+control",
});
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.components = { TestComponent };
MyComponent.template = xml`
<div>
@@ -919,7 +920,7 @@ QUnit.test("display shortcuts correctly for MacOS with a new overlayModifier", a
overlayModifier: "alt+control",
});
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.components = { TestComponent };
MyComponent.template = xml`
<div>
@@ -17,6 +17,8 @@ const { Component, xml } = owl;
const { DateTime } = luxon;
const serviceRegistry = registry.category("services");
let target;
/**
* @param {typeof DatePicker} Picker
* @param {Object} props
@@ -43,7 +45,7 @@ const mountPicker = async (Picker, props) => {
if (!props.onDateTimeChanged) {
props.onDateTimeChanged = () => {};
}
const parent = await mount(Parent, getFixture(), { env, props: { Picker, props } });
const parent = await mount(Parent, target, { env, props: { Picker, props } });
return parent;
};
@@ -69,25 +71,29 @@ const useFRLocale = () => {
return "fr";
};
QUnit.module("Components", () => {
QUnit.module("Components", ({ beforeEach }) => {
beforeEach(() => {
target = getFixture();
});
QUnit.module("DatePicker");
QUnit.test("basic rendering", async function (assert) {
assert.expect(8);
const picker = await mountPicker(DatePicker, {
await mountPicker(DatePicker, {
date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", { zone: "utc" }),
});
assert.containsOnce(picker, "input.o_input.o_datepicker_input");
assert.containsOnce(picker, "span.o_datepicker_button");
assert.containsOnce(target, "input.o_input.o_datepicker_input");
assert.containsOnce(target, "span.o_datepicker_button");
assert.containsNone(document.body, "div.bootstrap-datetimepicker-widget");
const input = picker.el.querySelector("input.o_input.o_datepicker_input");
const input = target.querySelector("input.o_input.o_datepicker_input");
assert.strictEqual(input.value, "09/01/1997", "Value should be the one given");
assert.strictEqual(
input.dataset.target,
`#${picker.el.id}`,
`#${target.querySelector(".o_datepicker").id}`,
"DatePicker id should match its input target"
);
@@ -105,7 +111,7 @@ QUnit.module("Components", () => {
QUnit.test("pick a date", async function (assert) {
assert.expect(5);
const picker = await mountPicker(DatePicker, {
await mountPicker(DatePicker, {
date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", { zone: "utc" }),
onDateTimeChanged: (date) => {
assert.step("datetime-changed");
@@ -116,7 +122,7 @@ QUnit.module("Components", () => {
);
},
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
await click(input);
await click(document.querySelector(".datepicker th.next")); // next month
@@ -132,7 +138,7 @@ QUnit.module("Components", () => {
QUnit.test("pick a date with locale (locale given in props)", async function (assert) {
assert.expect(5);
const picker = await mountPicker(DatePicker, {
await mountPicker(DatePicker, {
date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", { zone: "utc" }),
format: "dd MMM, yyyy",
locale: useFRLocale(),
@@ -145,7 +151,7 @@ QUnit.module("Components", () => {
);
},
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
assert.strictEqual(input.value, "09 janv., 1997");
@@ -161,7 +167,7 @@ QUnit.module("Components", () => {
QUnit.test("pick a date with locale (locale from date props)", async function (assert) {
assert.expect(5);
const picker = await mountPicker(DatePicker, {
await mountPicker(DatePicker, {
date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", {
zone: "utc",
locale: useFRLocale(),
@@ -176,7 +182,7 @@ QUnit.module("Components", () => {
);
},
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
assert.strictEqual(input.value, "09 janv., 1997");
@@ -192,7 +198,7 @@ QUnit.module("Components", () => {
QUnit.test("enter a date value", async function (assert) {
assert.expect(5);
const picker = await mountPicker(DatePicker, {
await mountPicker(DatePicker, {
date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", { zone: "utc" }),
onDateTimeChanged: (date) => {
assert.step("datetime-changed");
@@ -203,12 +209,12 @@ QUnit.module("Components", () => {
);
},
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
assert.verifySteps([]);
input.value = "08/02/1997";
await triggerEvent(picker.el, ".o_datepicker_input", "change");
await triggerEvent(target, ".o_datepicker_input", "change");
assert.verifySteps(["datetime-changed"]);
@@ -224,11 +230,11 @@ QUnit.module("Components", () => {
QUnit.test("Date format is correctly set", async function (assert) {
assert.expect(2);
const picker = await mountPicker(DatePicker, {
await mountPicker(DatePicker, {
date: DateTime.fromFormat("09/01/1997", "dd/MM/yyyy", { zone: "utc" }),
format: "yyyy/MM/dd",
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
assert.strictEqual(input.value, "1997/01/09");
@@ -243,19 +249,19 @@ QUnit.module("Components", () => {
QUnit.test("basic rendering", async function (assert) {
assert.expect(11);
const picker = await mountPicker(DateTimePicker, {
await mountPicker(DateTimePicker, {
date: DateTime.fromFormat("09/01/1997 12:30:01", "dd/MM/yyyy HH:mm:ss"),
});
assert.containsOnce(picker, "input.o_input.o_datepicker_input");
assert.containsOnce(picker, "span.o_datepicker_button");
assert.containsOnce(target, "input.o_input.o_datepicker_input");
assert.containsOnce(target, "span.o_datepicker_button");
assert.containsNone(document.body, "div.bootstrap-datetimepicker-widget");
const input = picker.el.querySelector("input.o_input.o_datepicker_input");
const input = target.querySelector("input.o_input.o_datepicker_input");
assert.strictEqual(input.value, "09/01/1997 12:30:01", "Value should be the one given");
assert.strictEqual(
input.dataset.target,
`#${picker.el.id}`,
`#${target.querySelector(".o_datepicker").id}`,
"DateTimePicker id should match its input target"
);
@@ -289,7 +295,7 @@ QUnit.module("Components", () => {
QUnit.test("pick a date and time", async function (assert) {
assert.expect(5);
const picker = await mountPicker(DateTimePicker, {
await mountPicker(DateTimePicker, {
date: DateTime.fromFormat("09/01/1997 12:30:01", "dd/MM/yyyy HH:mm:ss"),
onDateTimeChanged: (date) => {
assert.step("datetime-changed");
@@ -300,7 +306,7 @@ QUnit.module("Components", () => {
);
},
});
const input = picker.el.querySelector("input.o_input.o_datepicker_input");
const input = target.querySelector("input.o_input.o_datepicker_input");
await click(input);
await click(document.querySelector(".datepicker th.next")); // February
@@ -323,7 +329,7 @@ QUnit.module("Components", () => {
QUnit.test("pick a date and time with locale", async function (assert) {
assert.expect(6);
const picker = await mountPicker(DateTimePicker, {
await mountPicker(DateTimePicker, {
date: DateTime.fromFormat("09/01/1997 12:30:01", "dd/MM/yyyy HH:mm:ss"),
format: "dd MMM, yyyy HH:mm:ss",
locale: useFRLocale(),
@@ -337,7 +343,7 @@ QUnit.module("Components", () => {
},
});
const input = picker.el.querySelector("input.o_input.o_datepicker_input");
const input = target.querySelector("input.o_input.o_datepicker_input");
assert.strictEqual(input.value, "09 janv., 1997 12:30:01");
@@ -365,7 +371,7 @@ QUnit.module("Components", () => {
QUnit.test("enter a datetime value", async function (assert) {
assert.expect(9);
const picker = await mountPicker(DateTimePicker, {
await mountPicker(DateTimePicker, {
date: DateTime.fromFormat("09/01/1997 12:30:01", "dd/MM/yyyy HH:mm:ss"),
onDateTimeChanged: (date) => {
assert.step("datetime-changed");
@@ -376,12 +382,12 @@ QUnit.module("Components", () => {
);
},
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
assert.verifySteps([]);
input.value = "08/02/1997 15:45:05";
await triggerEvent(picker.el, ".o_datepicker_input", "change");
await triggerEvent(target, ".o_datepicker_input", "change");
assert.verifySteps(["datetime-changed"]);
@@ -413,11 +419,11 @@ QUnit.module("Components", () => {
QUnit.test("Date time format is correctly set", async function (assert) {
assert.expect(2);
const picker = await mountPicker(DateTimePicker, {
await mountPicker(DateTimePicker, {
date: DateTime.fromFormat("09/01/1997 12:30:01", "dd/MM/yyyy HH:mm:ss"),
format: "HH:mm:ss yyyy/MM/dd",
});
const input = picker.el.querySelector(".o_datepicker_input");
const input = target.querySelector(".o_datepicker_input");
assert.strictEqual(input.value, "12:30:01 1997/01/09");
@@ -448,17 +454,17 @@ QUnit.module("Components", () => {
}
const searchModel = new MockedSearchModel();
const date_field = { name: "date_field", string: "A date", type: "date", searchable: true };
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: { date_field },
},
env: { searchModel },
});
await toggleMenu(cfi, "Add Custom Filter");
await editSelect(cfi.el.querySelector(".o_generator_menu_field"), "date_field");
const valueInput = cfi.el.querySelector(".o_generator_menu_value .o_input");
await toggleMenu(target, "Add Custom Filter");
await editSelect(target.querySelector(".o_generator_menu_field"), "date_field");
const valueInput = target.querySelector(".o_generator_menu_value .o_input");
await click(valueInput);
await editSelect(valueInput, "05/05/2005");
await applyFilter(cfi);
await applyFilter(target);
});
});
@@ -105,18 +105,16 @@ QUnit.module("DebugMenu", (hooks) => {
return null;
});
const env = await makeTestEnv(testConfig);
const debugManager = await mount(DebugMenuParent, target, { env });
let debugManagerEl = debugManager.el;
await click(debugManager.el.querySelector("button.dropdown-toggle"));
debugManagerEl = debugManager.el;
assert.containsN(debugManagerEl, ".dropdown-menu .dropdown-item", 3);
assert.containsOnce(debugManagerEl, ".dropdown-divider");
const children = [...(debugManagerEl.querySelector(".dropdown-menu").children || [])];
await mount(DebugMenuParent, target, { env });
await click(target.querySelector("button.dropdown-toggle"));
assert.containsN(target, ".dropdown-menu .dropdown-item", 3);
assert.containsOnce(target, ".dropdown-divider");
const children = [...(target.querySelector(".dropdown-menu").children || [])];
assert.deepEqual(
children.map((el) => el.tagName),
["SPAN", "SPAN", "DIV", "SPAN"]
);
const items = [...debugManagerEl.querySelectorAll(".dropdown-menu .dropdown-item")] || [];
const items = [...target.querySelectorAll(".dropdown-menu .dropdown-item")] || [];
assert.deepEqual(
items.map((el) => el.textContent),
["Item 2", "Item 1", "Item 3"]
@@ -161,9 +159,9 @@ QUnit.module("DebugMenu", (hooks) => {
};
});
const env = await makeTestEnv(testConfig);
const debugManager = await mount(DebugMenuParent, target, { env });
await click(debugManager.el.querySelector("button.dropdown-toggle"));
const items = [...debugManager.el.querySelectorAll(".dropdown-menu .dropdown-item")];
await mount(DebugMenuParent, target, { env });
await click(target.querySelector("button.dropdown-toggle"));
const items = [...target.querySelectorAll(".dropdown-menu .dropdown-item")];
assert.deepEqual(
items.map((el) => el.textContent),
["Item 1", "Item 2", "Item 3", "Item 4"]
@@ -270,10 +268,10 @@ QUnit.module("DebugMenu", (hooks) => {
});
debugRegistry.category("default").add("regenerateAssets", regenerateAssets);
const env = await makeTestEnv(testConfig);
const debugManager = await mount(DebugMenuParent, target, { env });
await click(debugManager.el.querySelector("button.dropdown-toggle"));
assert.containsOnce(debugManager.el, ".dropdown-menu .dropdown-item");
const item = debugManager.el.querySelector(".dropdown-menu .dropdown-item");
await mount(DebugMenuParent, target, { env });
await click(target.querySelector("button.dropdown-toggle"));
assert.containsOnce(target, ".dropdown-menu .dropdown-item");
const item = target.querySelector(".dropdown-menu .dropdown-item");
assert.strictEqual(item.textContent, "Regenerate Assets Bundles");
await click(item);
assert.verifySteps(["ir.attachment/search", "ir.attachment/unlink", "reloadPage"]);
+11 -10
View File
@@ -8,6 +8,7 @@ import { Dialog } from "@web/core/dialog/dialog";
import { makeTestEnv } from "../helpers/mock_env";
import { click, destroy, getFixture, mount } from "../helpers/utils";
import { makeFakeDialogService } from "../helpers/mock_services";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, useEffect, useState, xml } = owl;
const serviceRegistry = registry.category("services");
@@ -94,7 +95,7 @@ QUnit.module("Components", (hooks) => {
QUnit.test("simple rendering with two dialogs", async function (assert) {
assert.expect(3);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`
<div>
<SimpleDialog title="'First Title'">
@@ -123,7 +124,7 @@ QUnit.module("Components", (hooks) => {
assert.expect(3);
const env = await makeTestEnv();
class MyDialog extends SimpleDialog {}
class Parent extends Component {
class Parent extends LegacyComponent {
close() {
assert.step("close");
}
@@ -147,7 +148,7 @@ QUnit.module("Components", (hooks) => {
const env = await makeTestEnv();
assert.expect(3);
class MyDialog extends SimpleDialog {}
class Parent extends Component {
class Parent extends LegacyComponent {
close() {
assert.step("close");
}
@@ -180,7 +181,7 @@ QUnit.module("Components", (hooks) => {
<button class="btn btn-primary">The Second Button</button>
</div>
`;
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
super.setup();
this.state = useState({
@@ -202,7 +203,7 @@ QUnit.module("Components", (hooks) => {
QUnit.test("embed an arbitrary component in a dialog is possible", async function (assert) {
assert.expect(6);
class SubComponent extends Component {
class SubComponent extends LegacyComponent {
_onClick() {
assert.step("subcomponent-clicked");
this.props.onClicked();
@@ -211,7 +212,7 @@ QUnit.module("Components", (hooks) => {
SubComponent.template = xml`
<div class="o_subcomponent" t-esc="props.text" t-on-click="_onClick"/>
`;
class Parent extends Component {
class Parent extends LegacyComponent {
_onSubcomponentClicked() {
assert.step("message received by parent");
}
@@ -233,7 +234,7 @@ QUnit.module("Components", (hooks) => {
QUnit.test("dialog without header/footer", async function (assert) {
assert.expect(4);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`
<SimpleDialog renderHeader="false" renderFooter="false"/>
`;
@@ -248,7 +249,7 @@ QUnit.module("Components", (hooks) => {
QUnit.test("dialog size can be chosen", async function (assert) {
assert.expect(5);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`
<div>
<SimpleDialog contentClass="'xl'" size="'modal-xl'"/>
@@ -280,7 +281,7 @@ QUnit.module("Components", (hooks) => {
QUnit.test("dialog can be rendered on fullscreen", async function (assert) {
assert.expect(2);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`
<div><SimpleDialog fullscreen="true"/></div>
`;
@@ -293,7 +294,7 @@ QUnit.module("Components", (hooks) => {
QUnit.test("can be the UI active element", async function (assert) {
assert.expect(3);
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.ui = useService("ui");
this.modal = null;
+168 -166
View File
@@ -24,7 +24,6 @@ const { App, Component, xml } = owl;
const serviceRegistry = registry.category("services");
let env;
let parent;
let target;
QUnit.module("Components", ({ beforeEach }) => {
@@ -45,13 +44,13 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.template = xml`<Dropdown/>`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
assert.strictEqual(
parent.el.outerHTML,
target.querySelector(".dropdown").outerHTML,
'<div class="o-dropdown dropdown o-dropdown--no-caret"><button class="dropdown-toggle"></button></div>'
);
assert.containsOnce(parent.el, "button.dropdown-toggle");
assert.containsNone(parent.el, ".dropdown-menu");
assert.containsOnce(target, "button.dropdown-toggle");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("DropdownItem can be rendered as <span/>", async (assert) => {
@@ -59,8 +58,11 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.template = xml`<DropdownItem>coucou</DropdownItem>`;
Parent.components = { DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.strictEqual(parent.el.outerHTML, '<span class="dropdown-item">coucou</span>');
await mount(Parent, target, { env });
assert.strictEqual(
target.querySelector(".dropdown-item").outerHTML,
'<span class="dropdown-item">coucou</span>'
);
});
QUnit.test("DropdownItem (with href prop) can be rendered as <a/>", async (assert) => {
@@ -68,8 +70,11 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.template = xml`<DropdownItem href="'#'">coucou</DropdownItem>`;
Parent.components = { DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.strictEqual(parent.el.outerHTML, '<a class="dropdown-item" href="#">coucou</a>');
await mount(Parent, target, { env });
assert.strictEqual(
target.querySelector(".dropdown-item").outerHTML,
'<a class="dropdown-item" href="#">coucou</a>'
);
});
QUnit.test("DropdownItem: prevents click default with href", async (assert) => {
@@ -93,15 +98,15 @@ QUnit.module("Components", ({ beforeEach }) => {
</Dropdown>`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
// The item containing the link class contains an href prop,
// which will turn it into <a href=> So it must be defaultPrevented
// The other one not contain any href props, it must not be defaultPrevented,
// so as not to prevent the background change flow for example
await click(parent.el, "button.dropdown-toggle");
await click(parent.el, ".link");
await click(parent.el, "button.dropdown-toggle");
await click(parent.el, ".nolink");
await click(target, "button.dropdown-toggle");
await click(target, ".link");
await click(target, "button.dropdown-toggle");
await click(target, ".nolink");
});
QUnit.test("can be styled", async (assert) => {
@@ -112,14 +117,14 @@ QUnit.module("Components", ({ beforeEach }) => {
</Dropdown>`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle");
assert.hasClass(parent.el, "dropdown one");
const toggler = parent.el.querySelector(".dropdown-toggle");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle");
assert.hasClass(target.querySelector(".o-dropdown"), "dropdown one");
const toggler = target.querySelector(".dropdown-toggle");
assert.hasClass(toggler, "two");
const menu = parent.el.querySelector(".dropdown-menu");
const menu = target.querySelector(".dropdown-menu");
assert.hasClass(menu, "three");
const item = parent.el.querySelector(".dropdown-item");
const item = target.querySelector(".dropdown-item");
assert.hasClass(item, "four");
});
@@ -138,15 +143,15 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.template = xml`<Dropdown beforeOpen="beforeOpen"/>`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle");
assert.verifySteps(["beforeOpen"]);
assert.containsNone(parent.el, ".dropdown-menu");
assert.containsNone(target, ".dropdown-menu");
beforeOpenProm.resolve();
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
await click(parent.el, "button.dropdown-toggle");
assert.containsNone(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
await click(target, "button.dropdown-toggle");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("initial open state can be true", async (assert) => {
@@ -162,9 +167,9 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.template = xml`<Dropdown startOpen="true" beforeOpen="beforeOpen"/>`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
assert.verifySteps(["beforeOpen"]);
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
});
QUnit.test("close on outside click", async (assert) => {
@@ -177,11 +182,11 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle");
assert.containsOnce(parent.el, ".dropdown-menu");
await click(parent.el, "div.outside");
assert.containsNone(parent.el, ".dropdown-menu");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle");
assert.containsOnce(target, ".dropdown-menu");
await click(target, "div.outside");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("close on item selection", async (assert) => {
@@ -193,10 +198,10 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle");
await click(parent.el, ".dropdown-menu .dropdown-item");
assert.containsNone(parent.el, ".dropdown-menu");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle");
await click(target, ".dropdown-menu .dropdown-item");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("payload received on item selection", async (assert) => {
@@ -212,9 +217,9 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle");
await click(parent.el, ".dropdown-menu .dropdown-item");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle");
await click(target, ".dropdown-menu .dropdown-item");
});
QUnit.test("multi-level dropdown: can be rendered and toggled", async (assert) => {
@@ -228,11 +233,11 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
assert.containsN(parent.el, ".dropdown-menu", 3);
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
assert.containsN(target, ".dropdown-menu", 3);
});
QUnit.test("multi-level dropdown: initial open state can be true", async (assert) => {
@@ -246,8 +251,8 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.containsN(parent.el, ".dropdown-menu", 3);
await mount(Parent, target, { env });
assert.containsN(target, ".dropdown-menu", 3);
});
QUnit.test("multi-level dropdown: close on outside click", async (assert) => {
@@ -264,13 +269,13 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
assert.containsN(parent.el, ".dropdown-menu", 3);
await click(parent.el, "div.outside");
assert.containsNone(parent.el, ".dropdown-menu");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
assert.containsN(target, ".dropdown-menu", 3);
await click(target, "div.outside");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("multi-level dropdown: close on item selection", async (assert) => {
@@ -284,18 +289,15 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await click(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
assert.containsN(parent.el, ".dropdown-menu", 2);
assert.containsN(parent.el, ".dropdown-item", 2);
assert.containsOnce(
parent.el,
".dropdown-menu > .dropdown > .dropdown-toggle.dropdown-item"
);
assert.containsOnce(parent.el, ".dropdown-menu > .dropdown-item");
await click(parent.el, ".dropdown-menu > .dropdown-item");
assert.containsNone(parent.el, ".dropdown-menu");
await mount(Parent, target, { env });
await click(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
assert.containsN(target, ".dropdown-menu", 2);
assert.containsN(target, ".dropdown-item", 2);
assert.containsOnce(target, ".dropdown-menu > .dropdown > .dropdown-toggle.dropdown-item");
assert.containsOnce(target, ".dropdown-menu > .dropdown-item");
await click(target, ".dropdown-menu > .dropdown-item");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("multi-level dropdown: parent closing modes on item selection", async (assert) => {
@@ -312,30 +314,30 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
// Open the 2-level dropdowns
await click(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
assert.containsN(parent.el, ".dropdown-menu", 2);
await click(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
assert.containsN(target, ".dropdown-menu", 2);
// Select item (parentClosingMode=none)
await click(parent.el, ".item1");
assert.containsN(parent.el, ".dropdown-menu", 2);
await click(target, ".item1");
assert.containsN(target, ".dropdown-menu", 2);
// Select item (parentClosingMode=closest)
await click(parent.el, ".item2");
assert.containsN(parent.el, ".dropdown-menu", 1);
await click(target, ".item2");
assert.containsN(target, ".dropdown-menu", 1);
// Reopen second level dropdown
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
assert.containsN(parent.el, ".dropdown-menu", 2);
await mouseEnter(target, "button.dropdown-toggle:last-child");
assert.containsN(target, ".dropdown-menu", 2);
// Select item (parentClosingMode=all)
await click(parent.el, ".item3");
assert.containsNone(parent.el, ".dropdown-menu");
await click(target, ".item3");
assert.containsNone(target, ".dropdown-menu");
// Reopen the 2-level dropdowns
await click(parent.el, "button.dropdown-toggle:last-child");
await mouseEnter(parent.el, "button.dropdown-toggle:last-child");
assert.containsN(parent.el, ".dropdown-menu", 2);
await click(target, "button.dropdown-toggle:last-child");
await mouseEnter(target, "button.dropdown-toggle:last-child");
assert.containsN(target, ".dropdown-menu", 2);
// Select item (default should be parentClosingMode=all)
await click(parent.el, ".item4");
assert.containsNone(parent.el, ".dropdown-menu");
await click(target, ".item4");
assert.containsNone(target, ".dropdown-menu");
});
QUnit.test("multi-level dropdown: recursive template can be rendered", async (assert) => {
@@ -399,9 +401,9 @@ QUnit.module("Components", ({ beforeEach }) => {
</t>
</Dropdown>`
);
parent = await app.mount(target);
await app.mount(target);
assert.deepEqual(
[...parent.el.querySelectorAll("button,.dropdown-menu > .dropdown-item")].map(
[...target.querySelectorAll("button,.dropdown-menu > .dropdown-item")].map(
(el) => el.textContent
),
[
@@ -446,39 +448,39 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
// Click on ONE
const one = parent.el.querySelector(".one");
const one = target.querySelector(".one");
await click(one, "button");
assert.verifySteps([]);
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsOnce(one, ".dropdown-menu");
// Hover on TWO
const two = parent.el.querySelector(".two");
const two = target.querySelector(".two");
two.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
assert.verifySteps(["beforeOpen"]);
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsNone(two, ".dropdown-menu");
beforeOpenProm.resolve();
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsOnce(two, ".dropdown-menu");
// Hover on THREE
const three = parent.el.querySelector(".three");
const three = target.querySelector(".three");
three.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsOnce(three, ".dropdown-menu");
// Click on OUTSIDE
await click(parent.el, "div.outside");
assert.containsNone(parent.el, ".dropdown-menu");
await click(target, "div.outside");
assert.containsNone(target, ".dropdown-menu");
// Hover on ONE, TWO, THREE
one.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
two.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
three.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
await nextTick();
assert.containsNone(parent.el, ".dropdown-menu");
assert.containsNone(target, ".dropdown-menu");
}
);
@@ -495,15 +497,15 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
// Click on FOO
await click(parent.el, ".foo button");
assert.containsOnce(parent.el, ".dropdown-menu");
await click(target, ".foo button");
assert.containsOnce(target, ".dropdown-menu");
// Hover on BAR1
const bar1 = parent.el.querySelector(".bar1");
const bar1 = target.querySelector(".bar1");
bar1.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsNone(bar1, ".dropdown-menu");
}
);
@@ -521,18 +523,18 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
// Click on BAR1
await click(parent.el, ".bar1 button");
assert.containsOnce(parent.el, ".dropdown-menu");
await click(target, ".bar1 button");
assert.containsOnce(target, ".dropdown-menu");
// Click on FOO
await click(parent.el, ".foo button");
assert.containsOnce(parent.el, ".dropdown-menu");
await click(target, ".foo button");
assert.containsOnce(target, ".dropdown-menu");
// Hover on BAR1
const bar1 = parent.el.querySelector(".bar1");
const bar1 = target.querySelector(".bar1");
bar1.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsNone(bar1, ".dropdown-menu");
}
);
@@ -549,26 +551,26 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
// Click on one
await click(parent.el, ".one button");
assert.containsOnce(parent.el, ".dropdown-menu");
await click(target, ".one button");
assert.containsOnce(target, ".dropdown-menu");
// Click on two
await click(parent.el, ".two button");
assert.containsN(parent.el, ".dropdown-menu", 2);
await click(target, ".two button");
assert.containsN(target, ".dropdown-menu", 2);
// Click on one again
await click(parent.el, ".one button");
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsNone(parent.el.querySelector(".one"), ".dropdown-menu");
await click(target, ".one button");
assert.containsOnce(target, ".dropdown-menu");
assert.containsNone(target.querySelector(".one"), ".dropdown-menu");
// Hover on one
const one = parent.el.querySelector(".one");
const one = target.querySelector(".one");
one.querySelector("button").dispatchEvent(new MouseEvent("mouseenter"));
await nextTick();
assert.containsOnce(parent.el, ".dropdown-menu");
assert.containsNone(parent.el.querySelector(".one"), ".dropdown-menu");
assert.containsOnce(target, ".dropdown-menu");
assert.containsNone(target.querySelector(".one"), ".dropdown-menu");
// Click outside
await click(parent.el, "div.outside");
assert.containsOnce(parent.el, ".dropdown-menu");
await click(target, "div.outside");
assert.containsOnce(target, ".dropdown-menu");
});
QUnit.test("dropdowns keynav", async (assert) => {
@@ -587,20 +589,20 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.containsNone(parent.el, ".dropdown-menu", "menu is closed at start");
await mount(Parent, target, { env });
assert.containsNone(target, ".dropdown-menu", "menu is closed at start");
triggerHotkey("m", true);
await nextTick();
assert.containsOnce(
parent.el,
target,
".dropdown-menu",
"menu is opened after pressing the toggler hotkey"
);
// Navigate with arrows
assert.containsNone(
parent.el,
target,
".dropdown-menu > .focus",
"menu should not have any active items"
);
@@ -626,19 +628,19 @@ QUnit.module("Components", ({ beforeEach }) => {
for (const step of scenarioSteps) {
triggerHotkey(step.hotkey);
await nextTick();
assert.hasClass(parent.el.querySelector(".dropdown-menu > .focus"), step.expected);
assert.hasClass(target.querySelector(".dropdown-menu > .focus"), step.expected);
}
// Select last one activated in previous scenario (item1)
triggerHotkey("enter");
await nextTick();
assert.containsNone(parent.el, ".dropdown-menu", "menu is closed after item selection");
assert.containsNone(target, ".dropdown-menu", "menu is closed after item selection");
// Reopen dropdown
triggerHotkey("m", true);
await nextTick();
assert.containsOnce(
parent.el,
target,
".dropdown-menu",
"menu is opened after pressing the toggler hotkey"
);
@@ -646,13 +648,13 @@ QUnit.module("Components", ({ beforeEach }) => {
// Select second item through data-hotkey attribute
triggerHotkey("2", true);
await nextTick();
assert.containsNone(parent.el, ".dropdown-menu", "menu is closed after item selection");
assert.containsNone(target, ".dropdown-menu", "menu is closed after item selection");
// Reopen dropdown
triggerHotkey("m", true);
await nextTick();
assert.containsOnce(
parent.el,
target,
".dropdown-menu",
"menu is opened after pressing the toggler hotkey"
);
@@ -660,7 +662,7 @@ QUnit.module("Components", ({ beforeEach }) => {
// Close dropdown with keynav
triggerHotkey("escape");
await nextTick();
assert.containsNone(parent.el, ".dropdown-menu", "menu is closed after item selection");
assert.containsNone(target, ".dropdown-menu", "menu is closed after item selection");
assert.verifySteps(["1", "2"], "items should have been selected in this order");
});
@@ -711,13 +713,13 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.containsOnce(parent, ".dropdown");
assert.containsNone(parent, ".dropdown .dropdown-menu");
assert.containsNone(parent, ".dropdown button.dropdown-toggle");
await click(parent.el, ".my_custom_toggler");
assert.containsOnce(parent, ".dropdown .dropdown-menu");
assert.containsN(parent, ".dropdown .dropdown-menu .dropdown-item", 2);
await mount(Parent, target, { env });
assert.containsOnce(target, ".dropdown");
assert.containsNone(target, ".dropdown .dropdown-menu");
assert.containsNone(target, ".dropdown button.dropdown-toggle");
await click(target, ".my_custom_toggler");
assert.containsOnce(target, ".dropdown .dropdown-menu");
assert.containsN(target, ".dropdown .dropdown-menu .dropdown-item", 2);
});
QUnit.test("multi-level dropdown: keynav", async (assert) => {
@@ -743,8 +745,8 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.containsNone(parent.el, ".dropdown-menu", "menus are closed at start");
await mount(Parent, target, { env });
assert.containsNone(target, ".dropdown-menu", "menus are closed at start");
// Highlighting and selecting items
const scenarioSteps = [
@@ -802,7 +804,7 @@ QUnit.module("Components", ({ beforeEach }) => {
await nextTick();
if (step.highlighted !== undefined) {
let index = 0;
const activeElements = [...parent.el.querySelectorAll(".focus")].map((el) =>
const activeElements = [...target.querySelectorAll(".focus")].map((el) =>
el.classList.contains("dropdown-toggle") ? el.parentElement : el
);
assert.ok(
@@ -834,8 +836,8 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.components = { Dropdown, DropdownItem };
serviceRegistry.add("localization", makeFakeLocalizationService({ direction: "rtl" }));
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.containsNone(parent.el, ".dropdown-menu", "menus are closed at start");
await mount(Parent, target, { env });
assert.containsNone(target, ".dropdown-menu", "menus are closed at start");
// Highlighting and selecting items
const scenarioSteps = [
@@ -851,7 +853,7 @@ QUnit.module("Components", ({ beforeEach }) => {
await nextTick();
if (step.highlighted !== undefined) {
let index = 0;
const activeElements = [...parent.el.querySelectorAll(".focus")].map((el) =>
const activeElements = [...target.querySelectorAll(".focus")].map((el) =>
el.classList.contains("dropdown-toggle") ? el.parentElement : el
);
assert.ok(
@@ -878,20 +880,20 @@ QUnit.module("Components", ({ beforeEach }) => {
`;
Parent.components = { Dropdown, DropdownItem };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
assert.containsNone(parent.el, ".dropdown-menu", "menus are closed at start");
await mount(Parent, target, { env });
assert.containsNone(target, ".dropdown-menu", "menus are closed at start");
// Open main dropdown
await click(parent.el, ".main");
assert.containsOnce(parent.el, ".dropdown-menu", "1st menu is opened");
await click(target, ".main");
assert.containsOnce(target, ".dropdown-menu", "1st menu is opened");
// Mouse enter sub dropdown
await mouseEnter(parent.el, ".sub");
assert.containsN(parent.el, ".dropdown-menu", 2, "all menus are opened");
await mouseEnter(target, ".sub");
assert.containsN(target, ".dropdown-menu", 2, "all menus are opened");
// Mouse enter the adjacent dropdown item
await mouseEnter(parent.el, ".item");
assert.containsOnce(parent.el, ".dropdown-menu", "only 1st menu is opened");
await mouseEnter(target, ".item");
assert.containsOnce(target, ".dropdown-menu", "only 1st menu is opened");
}
);
@@ -918,32 +920,32 @@ QUnit.module("Components", ({ beforeEach }) => {
};
},
});
parent = await mount(Parent, target, { env });
assert.containsNone(parent.el, ".dropdown-menu", "menus are closed at start");
await mount(Parent, target, { env });
assert.containsNone(target, ".dropdown-menu", "menus are closed at start");
assert.strictEqual(hotkeyRegistrationsCount, 0, "no hotkey registered");
// Open dropdowns one by one
await click(parent.el, ".first");
assert.containsOnce(parent.el, ".dropdown-menu", "1st menu is opened");
await click(target, ".first");
assert.containsOnce(target, ".dropdown-menu", "1st menu is opened");
assert.strictEqual(hotkeyRegistrationsCount, 10, "1st menu hotkeys registered");
await mouseEnter(parent.el, ".second");
assert.containsN(parent.el, ".dropdown-menu", 2, "2nd menu is also opened");
await mouseEnter(target, ".second");
assert.containsN(target, ".dropdown-menu", 2, "2nd menu is also opened");
assert.strictEqual(hotkeyRegistrationsCount, 20, "2nd menu hotkeys also registered");
await mouseEnter(parent.el, ".third");
assert.containsN(parent.el, ".dropdown-menu", 3, "3rd menu is also opened");
await mouseEnter(target, ".third");
assert.containsN(target, ".dropdown-menu", 3, "3rd menu is also opened");
assert.strictEqual(hotkeyRegistrationsCount, 30, "3rd menu hotkeys also registered");
// Close third
triggerHotkey("escape");
await nextTick();
assert.containsN(parent.el, ".dropdown-menu", 2, "two menus still opened");
assert.containsN(target, ".dropdown-menu", 2, "two menus still opened");
assert.strictEqual(hotkeyRegistrationsCount, 20, "two menus hotkeys registered");
// Reopen second
await mouseEnter(parent.el, ".third");
assert.containsN(parent.el, ".dropdown-menu", 3, "3rd menu is also opened");
await mouseEnter(target, ".third");
assert.containsN(target, ".dropdown-menu", 3, "3rd menu is also opened");
assert.strictEqual(hotkeyRegistrationsCount, 30, "3rd menu hotkeys also registered");
// Close third, second and first
@@ -953,7 +955,7 @@ QUnit.module("Components", ({ beforeEach }) => {
await nextTick();
triggerHotkey("escape");
await nextTick();
assert.containsNone(parent.el, ".dropdown-menu", "all menus are now closed");
assert.containsNone(target, ".dropdown-menu", "all menus are now closed");
assert.strictEqual(hotkeyRegistrationsCount, 0, "no hotkey registration left");
});
@@ -965,9 +967,9 @@ QUnit.module("Components", ({ beforeEach }) => {
Parent.components = { Dropdown };
env = await makeTestEnv();
parent = await mount(Parent, target, { env });
await mount(Parent, target, { env });
assert.strictEqual(
parent.el.querySelector("button.dropdown-toggle").dataset.tooltip,
target.querySelector("button.dropdown-toggle").dataset.tooltip,
"My tooltip"
);
});
@@ -15,12 +15,13 @@ import {
nextTick,
patchWithCleanup,
} from "../../helpers/utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, markup, xml } = owl;
const serviceRegistry = registry.category("services");
const mainComponentRegistry = registry.category("main_components");
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.EffectContainer = mainComponentRegistry.get("EffectContainer");
this.NotificationContainer = mainComponentRegistry.get("NotificationContainer");
@@ -130,7 +131,7 @@ QUnit.module("Effect Service", (hooks) => {
QUnit.test("rendering a rainbowman with a custom component", async function (assert) {
assert.expect(2);
const props = { foo: "bar" };
class Custom extends Component {
class Custom extends LegacyComponent {
setup() {
assert.deepEqual(this.props, props, "should have received these props");
}
@@ -20,6 +20,7 @@ import {
makeFakeRPCService,
} from "../../helpers/mock_services";
import { makeDeferred, nextTick, patchWithCleanup } from "../../helpers/utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
const errorDialogRegistry = registry.category("error_dialogs");
@@ -83,7 +84,7 @@ QUnit.test(
"handle custom RPC_ERROR of type='server' and associated custom dialog class",
async (assert) => {
assert.expect(2);
class CustomDialog extends Component {}
class CustomDialog extends LegacyComponent {}
CustomDialog.template = xml`<RPCErrorDialog title="'Strange Error'"/>`;
CustomDialog.components = { RPCErrorDialog };
const error = new RPCError();
@@ -119,10 +120,10 @@ QUnit.test(
"handle normal RPC_ERROR of type='server' and associated custom dialog class",
async (assert) => {
assert.expect(2);
class CustomDialog extends Component {}
class CustomDialog extends LegacyComponent {}
CustomDialog.template = xml`<RPCErrorDialog title="'Strange Error'"/>`;
CustomDialog.components = { RPCErrorDialog };
class NormalDialog extends Component {}
class NormalDialog extends LegacyComponent {}
NormalDialog.template = xml`<RPCErrorDialog title="'Normal Error'"/>`;
NormalDialog.components = { RPCErrorDialog };
const error = new RPCError();
@@ -101,13 +101,13 @@ QUnit.test("invisible data-hotkeys are not enabled. ", async (assert) => {
triggerHotkey(key, true);
await nextTick();
const comp = await mount(MyComponent, target, { env });
await mount(MyComponent, target, { env });
triggerHotkey(key, true);
await nextTick();
assert.verifySteps(["click"]);
comp.el.querySelector(".myButton").disabled = true;
target.querySelector(".myButton").disabled = true;
triggerHotkey(key, true);
await nextTick();
assert.verifySteps([], "shouldn't trigger the hotkey of an invisible button");
@@ -194,9 +194,9 @@ QUnit.test("the overlay of hotkeys is correctly displayed", async (assert) => {
<button t-on-click="onClick" data-hotkey="c"/>
</div>
`;
const comp = await mount(MyComponent, target, { env });
await mount(MyComponent, target, { env });
const getOverlays = () =>
[...comp.el.querySelectorAll(".o_web_hotkey_overlay")].map((el) => el.innerText);
[...target.querySelectorAll(".o_web_hotkey_overlay")].map((el) => el.innerText);
displayHotkeysOverlay();
assert.deepEqual(getOverlays(), ["B", "C"], "should display the overlay");
@@ -240,9 +240,9 @@ QUnit.test("the overlay of hotkeys is correctly displayed on MacOs", async (asse
<button t-on-click="onClick" data-hotkey="c"/>
</div>
`;
const comp = await mount(MyComponent, target, { env });
await mount(MyComponent, target, { env });
const getOverlays = () =>
[...comp.el.querySelectorAll(".o_web_hotkey_overlay")].map((el) => el.innerText);
[...target.querySelectorAll(".o_web_hotkey_overlay")].map((el) => el.innerText);
displayHotkeysOverlay();
assert.deepEqual(getOverlays(), ["B", "C"], "should display the overlay");
@@ -317,7 +317,7 @@ QUnit.test("[data-hotkey] alt is required", async (assert) => {
}
TestComponent.template = xml`<div><button t-on-click="onClick" data-hotkey="${key}"/></div>`;
const comp = await mount(TestComponent, target, { env });
await mount(TestComponent, target, { env });
triggerHotkey(key, true);
await nextTick();
@@ -371,7 +371,7 @@ QUnit.test("[data-hotkey] never allow repeat", async (assert) => {
}
TestComponent.template = xml`<div><button t-on-click="onClick" data-hotkey="${key}"/></div>`;
const comp = await mount(TestComponent, target, { env });
await mount(TestComponent, target, { env });
triggerHotkey(key, true);
await nextTick();
@@ -513,13 +513,13 @@ QUnit.test("registrations and elements belong to the correct UI owner", async (a
class MyComponent2 extends Component {
setup() {
useHotkey("a", () => assert.step("MyComponent2 subscription"));
useActiveElement();
useActiveElement("active");
}
onClick() {
assert.step("MyComponent2 [data-hotkey]");
}
}
MyComponent2.template = xml`<div><button data-hotkey="b" t-on-click="onClick"/></div>`;
MyComponent2.template = xml`<div t-ref="active"><button data-hotkey="b" t-on-click="onClick"/></div>`;
await mount(MyComponent1, target, { env });
triggerHotkey("a");
@@ -10,14 +10,14 @@ import { translatedTerms, _lt } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { patch, unpatch } from "@web/core/utils/patch";
import { session } from "@web/session";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
const { DateTime, Settings } = luxon;
const terms = { Hello: "Bonjour" };
const serviceRegistry = registry.category("services");
class TestComponent extends Component {}
class TestComponent extends LegacyComponent {}
/**
* Patches the 'lang' of the user session and context.
@@ -29,10 +29,11 @@ QUnit.module("Components", (hooks) => {
mainComponentsRegistry.add("MainComponentA", { Component: MainComponentA, props: {} });
mainComponentsRegistry.add("MainComponentB", { Component: MainComponentB, props: {} });
const container = await mount(MainComponentsContainer, target, { env, props: {} });
await mount(MainComponentsContainer, target, { env, props: {} });
assert.containsOnce(target, "div.o-main-components-container");
assert.equal(
container.el.outerHTML,
"<div><span>MainComponentA</span><span>MainComponentB</span></div>"
target.querySelector(".o-main-components-container").innerHTML,
"<span>MainComponentA</span><span>MainComponentB</span>"
);
});
@@ -56,10 +57,11 @@ QUnit.module("Components", (hooks) => {
mainComponentsRegistry.add("MainComponentA", { Component: MainComponentA, props: {} });
mainComponentsRegistry.add("MainComponentB", { Component: MainComponentB, props: {} });
const container = await mount(MainComponentsContainer, target, { env, props: {} });
await mount(MainComponentsContainer, target, { env, props: {} });
assert.containsOnce(target, "div.o-main-components-container");
assert.equal(
container.el.outerHTML,
"<div><span>MainComponentA</span><span>MainComponentB</span></div>"
target.querySelector(".o-main-components-container").innerHTML,
"<span>MainComponentA</span><span>MainComponentB</span>"
);
const handler = (ev) => {
@@ -78,7 +80,10 @@ QUnit.module("Components", (hooks) => {
unpatch(QUnit, "MainComponentsContainer QUnit patch");
assert.verifySteps(["BOOM"]);
assert.equal(container.el.outerHTML, "<div><span>MainComponentB</span></div>");
assert.equal(
target.querySelector(".o-main-components-container").innerHTML,
"<span>MainComponentB</span>"
);
});
QUnit.test("unmounts erroring main component: variation", async function (assert) {
@@ -101,10 +106,11 @@ QUnit.module("Components", (hooks) => {
mainComponentsRegistry.add("MainComponentA", { Component: MainComponentA, props: {} });
mainComponentsRegistry.add("MainComponentB", { Component: MainComponentB, props: {} });
const container = await mount(MainComponentsContainer, target, { env, props: {} });
await mount(MainComponentsContainer, target, { env, props: {} });
assert.containsOnce(target, "div.o-main-components-container");
assert.equal(
container.el.outerHTML,
"<div><span>MainComponentA</span><span>MainComponentB</span></div>"
target.querySelector(".o-main-components-container").innerHTML,
"<span>MainComponentA</span><span>MainComponentB</span>"
);
const handler = (ev) => {
@@ -123,6 +129,9 @@ QUnit.module("Components", (hooks) => {
unpatch(QUnit, "MainComponentsContainer QUnit patch");
assert.verifySteps(["BOOM"]);
assert.equal(container.el.outerHTML, "<div><span>MainComponentA</span></div>");
assert.equal(
target.querySelector(".o-main-components-container").innerHTML,
"<span>MainComponentA</span>"
);
});
});
@@ -17,6 +17,7 @@ import {
patchWithCleanup,
} from "../../helpers/utils";
import { registerCleanup } from "../../helpers/cleanup";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
@@ -125,7 +126,7 @@ QUnit.test("rpc with simple routes", async (assert) => {
});
QUnit.test("rpc coming from destroyed components are left pending", async (assert) => {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.rpc = useService("rpc");
}
@@ -162,7 +163,7 @@ QUnit.test("rpc coming from destroyed components are left pending", async (asser
QUnit.test("rpc initiated from destroyed components throw exception", async (assert) => {
assert.expect(1);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.rpc = useService("rpc");
}
+41 -35
View File
@@ -18,6 +18,8 @@ const { Component, useState, xml } = owl;
const serviceRegistry = registry.category("services");
let target;
class PagerController extends Component {
setup() {
this.state = useState({ ...this.props });
@@ -33,13 +35,17 @@ PagerController.components = { Pager };
async function makePager(props) {
serviceRegistry.add("ui", uiService);
const env = await makeTestEnv();
const pager = await mount(PagerController, getFixture(), { env, props });
const pager = await mount(PagerController, target, { env, props });
return pager;
}
QUnit.module("Components", () => {
QUnit.module("Components", ({ beforeEach }) => {
QUnit.module("Pager");
beforeEach(() => {
target = getFixture();
});
QUnit.test("basic interactions", async function (assert) {
assert.expect(2);
@@ -52,14 +58,14 @@ QUnit.module("Components", () => {
},
});
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"1-4",
"currentMinimum should be set to 1"
);
await click(pager.el.querySelector(`.o_pager button.o_pager_next`));
await click(target.querySelector(`.o_pager button.o_pager_next`));
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"5-8",
"currentMinimum should now be 5"
);
@@ -77,23 +83,23 @@ QUnit.module("Components", () => {
},
});
await click(pager.el, ".o_pager_value");
await click(target, ".o_pager_value");
assert.containsOnce(pager, "input", "the pager should contain an input");
assert.containsOnce(target, "input", "the pager should contain an input");
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).value,
target.querySelector(`.o_pager_counter .o_pager_value`).value,
"1-4",
"the input should have correct value"
);
// change the limit
const input = pager.el.querySelector(`.o_pager_counter input.o_pager_value`);
const input = target.querySelector(`.o_pager_counter input.o_pager_value`);
input.value = "1-6";
await triggerEvents(input, null, ["change", "blur"]);
assert.containsNone(pager, "input", "the pager should not contain an input anymore");
assert.containsNone(target, "input", "the pager should not contain an input anymore");
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"1-6",
"the limit should have been updated"
);
@@ -102,7 +108,7 @@ QUnit.module("Components", () => {
QUnit.test("keydown on pager with same value", async function (assert) {
assert.expect(7);
const pager = await makePager({
await makePager({
offset: 0,
limit: 4,
total: 10,
@@ -112,18 +118,18 @@ QUnit.module("Components", () => {
});
// Enter edit mode
await click(pager.el, ".o_pager_value");
await click(target, ".o_pager_value");
assert.containsOnce(pager.el, "input");
assert.strictEqual(pager.el.querySelector(`.o_pager_counter .o_pager_value`).value, "1-4");
assert.containsOnce(target, "input");
assert.strictEqual(target.querySelector(`.o_pager_counter .o_pager_value`).value, "1-4");
assert.verifySteps([]);
// Exit edit mode
await triggerEvent(pager.el, "input", "keydown", { key: "Enter" });
await triggerEvent(target, "input", "keydown", { key: "Enter" });
assert.containsNone(pager.el, "input");
assert.containsNone(target, "input");
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"1-4"
);
assert.verifySteps(["pager-changed"]);
@@ -142,18 +148,18 @@ QUnit.module("Components", () => {
});
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"1-4",
"Initial value should be correct"
);
async function inputAndAssert(inputValue, expected, reason) {
await click(pager.el.querySelector(`.o_pager_counter .o_pager_value`));
const inputEl = pager.el.querySelector(`.o_pager_counter input.o_pager_value`);
await click(target.querySelector(`.o_pager_counter .o_pager_value`));
const inputEl = target.querySelector(`.o_pager_counter input.o_pager_value`);
inputEl.value = inputValue;
await triggerEvents(inputEl, null, ["change", "blur"]);
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
expected,
`Pager value should be "${expected}" when given "${inputValue}": ${reason}`
);
@@ -195,19 +201,19 @@ QUnit.module("Components", () => {
pager.updateProps(data);
},
});
const pagerButtons = pager.el.querySelectorAll("button");
const pagerButtons = target.querySelectorAll("button");
// Click twice
await click(pager.el.querySelector(`.o_pager button.o_pager_next`));
await click(pager.el.querySelector(`.o_pager button.o_pager_next`));
await click(target.querySelector(`.o_pager button.o_pager_next`));
await click(target.querySelector(`.o_pager button.o_pager_next`));
// Try to edit the pager value
await click(pager.el, ".o_pager_value");
await click(target, ".o_pager_value");
assert.strictEqual(pagerButtons.length, 2, "the two buttons should be displayed");
assert.ok(pagerButtons[0].disabled, "'previous' is disabled");
assert.ok(pagerButtons[1].disabled, "'next' is disabled");
assert.strictEqual(
pager.el.querySelector(".o_pager_value").tagName,
target.querySelector(".o_pager_value").tagName,
"SPAN",
"pager edition is prevented"
);
@@ -220,15 +226,15 @@ QUnit.module("Components", () => {
assert.notOk(pagerButtons[0].disabled, "'previous' is enabled");
assert.notOk(pagerButtons[1].disabled, "'next' is enabled");
assert.strictEqual(
pager.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"5-8",
"value has been updated"
);
await click(pager.el, ".o_pager_value");
await click(target, ".o_pager_value");
assert.strictEqual(
pager.el.querySelector(".o_pager_value").tagName,
target.querySelector(".o_pager_value").tagName,
"INPUT",
"pager edition is re-enabled"
);
@@ -244,15 +250,15 @@ QUnit.module("Components", () => {
},
});
await click(pager.el, ".o_pager_value");
assert.containsOnce(pager, "input", "the pager should contain an input");
await click(target, ".o_pager_value");
assert.containsOnce(target, "input", "the pager should contain an input");
assert.strictEqual(
pager.el.querySelector("input"),
target.querySelector("input"),
document.activeElement,
"pager input is focused"
);
await triggerEvent(pager.el, null, "mousedown");
assert.containsNone(pager, "input", "the pager should not contain an input");
await triggerEvent(target, null, "mousedown");
assert.containsNone(target, "input", "the pager should not contain an input");
});
});
@@ -2,9 +2,9 @@
import { popoverService } from "@web/core/popover/popover_service";
import { registry } from "@web/core/registry";
import { registerCleanup } from "../../helpers/cleanup";
import { clearRegistryWithCleanup, makeTestEnv } from "../../helpers/mock_env";
import { click, getFixture, mount, nextTick } from "../../helpers/utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
@@ -132,7 +132,7 @@ QUnit.test("close callback", async (assert) => {
QUnit.test("sub component triggers close", async (assert) => {
assert.containsOnce(fixture, ".o_popover_container");
class Comp extends Component {}
class Comp extends LegacyComponent {}
Comp.template = xml`<div id="comp" t-on-click="() => this.trigger('popover-closed')">in popover</div>`;
popovers.add(popoverTarget, Comp, {});
@@ -34,17 +34,17 @@ function isWellPositioned(popper, position = "bottom") {
const v = /** @type {import("@web/core/position/position_hook").VariantsDataKey} */ (variant[0]);
const posSolution = computePositioning(reference, popper, options).get(d, v);
const hasCorrectClass = popper.classList.contains(posSolution.className);
const correctLeft = parseFloat(popper.style.left) === posSolution.left;
const correctTop = parseFloat(popper.style.top) === posSolution.top;
const correctLeft = parseFloat(popper.style.left) === Math.round(posSolution.left * 10) / 10;
const correctTop = parseFloat(popper.style.top) === Math.round(posSolution.top * 10) / 10;
return hasCorrectClass && correctLeft && correctTop;
}
class TestComp extends Component {
setup() {
usePosition(reference, this.constructor.popperOptions);
usePosition(reference, "popper", this.constructor.popperOptions);
}
}
TestComp.template = xml`<div id="popper"/>`;
TestComp.template = xml`<div id="popper" t-ref="popper"/>`;
/** @type {import("@web/core/position/position_hook").Options} */
TestComp.popperOptions = {};
@@ -89,8 +89,8 @@ QUnit.module("usePosition Hook", {
});
QUnit.test("default position is bottom", async (assert) => {
const popper = await mount(TestComp, container);
assert.ok(isWellPositioned(popper.el, "bottom"));
await mount(TestComp, container);
assert.ok(isWellPositioned(document.getElementById("popper"), "bottom"));
});
QUnit.test("can add margin", async (assert) => {
@@ -98,30 +98,29 @@ QUnit.test("can add margin", async (assert) => {
Object.assign(TestComp.popperOptions, { margin });
let popper = await mount(TestComp, container);
const popBox1 = popper.el.getBoundingClientRect();
const popBox1 = document.getElementById("popper").getBoundingClientRect();
destroy(popper);
margin = 20;
Object.assign(TestComp.popperOptions, { margin });
popper = await mount(TestComp, container);
const popBox2 = popper.el.getBoundingClientRect();
const popBox2 = document.getElementById("popper").getBoundingClientRect();
destroy(popper);
assert.strictEqual(popBox1.top + margin, popBox2.top);
});
QUnit.test("can use a t-ref as popper", async (assert) => {
QUnit.test("popper is an inner element", async (assert) => {
patchWithCleanup(TestComp, {
popperOptions: { ...TestComp.popperOptions, popper: "popperRef" },
template: xml`
<div id="not-popper">
<div id="popper" t-ref="popperRef"/>
<div id="popper" t-ref="popper"/>
</div>
`,
});
const comp = await mount(TestComp, container);
assert.notOk(isWellPositioned(comp.el));
assert.ok(isWellPositioned(comp.el.querySelector("#popper")));
await mount(TestComp, container);
assert.notOk(isWellPositioned(document.getElementById("not-popper")));
assert.ok(isWellPositioned(document.getElementById("popper")));
});
QUnit.test("has no effect when component is destroyed", async (assert) => {
@@ -154,9 +153,9 @@ QUnit.test("has no effect when component is destroyed", async (assert) => {
const getPositionTest = (position, positionToCheck) => {
return async (assert) => {
Object.assign(TestComp.popperOptions, { position });
const popper = await mount(TestComp, container);
await mount(TestComp, container);
positionToCheck = positionToCheck || position;
assert.ok(isWellPositioned(popper.el, positionToCheck));
assert.ok(isWellPositioned(document.getElementById("popper"), positionToCheck));
};
};
QUnit.test("position top", getPositionTest("top"));
@@ -192,8 +191,11 @@ const CONTAINER_STYLE_MAP = {
const getRepositionTest = (from, to, containerStyleChanges) => {
return async (assert) => {
Object.assign(TestComp.popperOptions, { position: from });
const popper = await mount(TestComp, container);
assert.ok(isWellPositioned(popper.el, from), `points to ${from} direction`);
await mount(TestComp, container);
assert.ok(
isWellPositioned(document.getElementById("popper"), from),
`points to ${from} direction`
);
// Change container style and force update
for (const styleToApply of containerStyleChanges.split(" ")) {
@@ -201,7 +203,10 @@ const getRepositionTest = (from, to, containerStyleChanges) => {
}
triggerEvent(document, null, "scroll");
await nextTick();
assert.ok(isWellPositioned(popper.el, to), `points to ${to} direction`);
assert.ok(
isWellPositioned(document.getElementById("popper"), to),
`points to ${to} direction`
);
};
};
// -----------------------------------------------------------------------------
@@ -35,7 +35,7 @@ QUnit.test("Ignore empty hrefs", async (assert) => {
</button>
</div>`;
const comp = await mount(MyComponent, target, { env });
await mount(MyComponent, target, { env });
/**
* To determine whether the hash changed we need to use a custom hash for
@@ -47,10 +47,10 @@ QUnit.test("Ignore empty hrefs", async (assert) => {
location.hash = testHash;
registerCleanup(() => (location.hash = initialHash));
comp.el.querySelector(".inactive_link").click();
target.querySelector(".inactive_link").click();
await nextTick();
comp.el.querySelector(".fa.fa-trash").click();
target.querySelector(".fa.fa-trash").click();
await nextTick();
assert.strictEqual(location.hash, testHash);
@@ -92,16 +92,16 @@ QUnit.module("Tooltip service", (hooks) => {
const mockSetInterval = (fn) => {
simulateInterval = fn;
};
const parent = await makeParent(MyComponent, { mockSetTimeout, mockSetInterval });
await makeParent(MyComponent, { mockSetTimeout, mockSetInterval });
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
target.querySelector("button").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
simulateTimeout();
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(
target.querySelector(".o_popover_container .o_popover").innerText,
"hello"
@@ -118,10 +118,10 @@ QUnit.module("Tooltip service", (hooks) => {
layerY: y,
screenY: y,
});
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
simulateInterval();
await nextTick();
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
});
QUnit.test("basic rendering 2", async (assert) => {
@@ -135,18 +135,18 @@ QUnit.module("Tooltip service", (hooks) => {
const mockSetInterval = (fn) => {
simulateInterval = fn;
};
const parent = await makeParent(MyComponent, { mockSetTimeout, mockSetInterval });
await makeParent(MyComponent, { mockSetTimeout, mockSetInterval });
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
let [outerSpan, innerSpan] = target.querySelectorAll("span.our_span");
outerSpan.dispatchEvent(new Event("mouseenter"));
innerSpan.dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
simulateTimeout();
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(
target.querySelector(".o_popover_container .o_popover").innerText,
"hello"
@@ -163,10 +163,10 @@ QUnit.module("Tooltip service", (hooks) => {
layerY: y,
screenY: y,
});
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
simulateInterval();
await nextTick();
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
});
QUnit.test("remove element with opened tooltip", async (assert) => {
@@ -185,20 +185,20 @@ QUnit.module("Tooltip service", (hooks) => {
const mockSetInterval = (fn) => {
simulateInterval = fn;
};
const parent = await makeParent(MyComponent, { mockSetInterval });
await makeParent(MyComponent, { mockSetInterval });
assert.containsOnce(parent, "button");
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, "button");
assert.containsNone(target, ".o_popover_container .o_popover");
target.querySelector("button").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
compState.visible = false;
await nextTick();
assert.containsNone(parent, "button");
assert.containsNone(target, "button");
simulateInterval();
await nextTick();
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
});
QUnit.test("rendering with several tooltips", async (assert) => {
@@ -208,17 +208,17 @@ QUnit.module("Tooltip service", (hooks) => {
<button class="button_1" data-tooltip="tooltip 1">Action 1</button>
<button class="button_2" data-tooltip="tooltip 2">Action 2</button>
</div>`;
const parent = await makeParent(MyComponent);
await makeParent(MyComponent);
assert.containsNone(parent, ".o_popover_container .o_popover");
assert.containsNone(target, ".o_popover_container .o_popover");
target.querySelector("button.button_1").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "tooltip 1");
target.querySelector("button.button_1").dispatchEvent(new Event("mouseleave"));
target.querySelector("button.button_2").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "tooltip 2");
});
@@ -232,40 +232,40 @@ QUnit.module("Tooltip service", (hooks) => {
<button class="bottom" data-tooltip="bottom" data-tooltip-position="bottom">Bottom</button>
<button class="left" data-tooltip="left" data-tooltip-position="left">Left</button>
</div>`;
const parent = await makeParent(MyComponent);
await makeParent(MyComponent);
// default
target.querySelector("button.default").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "default");
assert.hasClass(target.querySelector(".o_popover"), "o-popper-position--bm");
// top
target.querySelector("button.top").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "top");
assert.hasClass(target.querySelector(".o_popover"), "o-popper-position--tm");
// right
target.querySelector("button.right").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "right");
assert.hasClass(target.querySelector(".o_popover"), "o-popper-position--rm");
// bottom
target.querySelector("button.bottom").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "bottom");
assert.hasClass(target.querySelector(".o_popover"), "o-popper-position--bm");
// left
target.querySelector("button.left").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o_popover");
assert.containsOnce(target, ".o_popover_container .o_popover");
assert.strictEqual(target.querySelector(".o_popover").innerText, "left");
assert.hasClass(target.querySelector(".o_popover"), "o-popper-position--lm");
});
@@ -279,12 +279,12 @@ QUnit.module("Tooltip service", (hooks) => {
const templates = {
my_tooltip_template: "<i>tooltip</i>",
};
const parent = await makeParent(MyComponent, { templates });
await makeParent(MyComponent, { templates });
assert.containsNone(parent, ".o_popover_container .o-tooltip");
assert.containsNone(target, ".o_popover_container .o-tooltip");
target.querySelector("button").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o-tooltip");
assert.containsOnce(target, ".o_popover_container .o-tooltip");
assert.strictEqual(target.querySelector(".o-tooltip").innerHTML, "<i>tooltip</i>");
});
@@ -310,12 +310,12 @@ QUnit.module("Tooltip service", (hooks) => {
</ul>
`,
};
const parent = await makeParent(MyComponent, { templates });
await makeParent(MyComponent, { templates });
assert.containsNone(parent, ".o_popover_container .o-tooltip");
assert.containsNone(target, ".o_popover_container .o-tooltip");
target.querySelector("button").dispatchEvent(new Event("mouseenter"));
await nextTick();
assert.containsOnce(parent, ".o_popover_container .o-tooltip");
assert.containsOnce(target, ".o_popover_container .o-tooltip");
assert.strictEqual(
target.querySelector(".o-tooltip").innerHTML,
"<ul><li>X: 3</li><li>Y: abc</li></ul>"
@@ -5,6 +5,7 @@ import { uiService, useActiveElement } from "@web/core/ui/ui_service";
import { makeTestEnv } from "../helpers/mock_env";
import { makeFakeLocalizationService } from "../helpers/mock_services";
import { destroy, getFixture, mount, nextTick } from "../helpers/utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
const serviceRegistry = registry.category("services");
@@ -65,25 +66,6 @@ QUnit.test("use block and unblock several times to block ui with ui service", as
assert.strictEqual(blockUI, null, "ui should not be blocked");
});
QUnit.test("a component can be the active element", async (assert) => {
class MyComponent extends Component {
setup() {
useActiveElement();
}
}
MyComponent.template = xml`<div/>`;
const env = await makeTestEnv({ ...baseConfig });
const ui = env.services.ui;
assert.deepEqual(ui.activeElement, document);
const comp = await mount(MyComponent, target, { env });
assert.deepEqual(ui.activeElement, comp.el);
destroy(comp);
assert.deepEqual(ui.activeElement, document);
});
QUnit.test("a component can be the UI active element: with t-ref delegation", async (assert) => {
class MyComponent extends Component {
setup() {
@@ -103,7 +85,7 @@ QUnit.test("a component can be the UI active element: with t-ref delegation", a
assert.deepEqual(ui.activeElement, document);
const comp = await mount(MyComponent, target, { env });
assert.deepEqual(ui.activeElement, comp.el.querySelector("div#owner"));
assert.deepEqual(ui.activeElement, document.getElementById("owner"));
comp.hasRef = false;
comp.render();
await nextTick();
@@ -5,6 +5,7 @@ import { useAutofocus, useBus, useListener, useService } from "@web/core/utils/h
import { registry } from "@web/core/registry";
import { makeTestEnv } from "@web/../tests/helpers/mock_env";
import { click, destroy, getFixture, mount, nextTick } from "@web/../tests/helpers/utils";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onMounted, xml } = owl;
const serviceRegistry = registry.category("services");
@@ -14,7 +15,7 @@ QUnit.module("utils", () => {
QUnit.module("useAutofocus");
QUnit.test("useAutofocus: simple usecase", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.inputRef = useAutofocus();
}
@@ -40,7 +41,7 @@ QUnit.module("utils", () => {
});
QUnit.test("useAutofocus: conditional autofocus", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.inputRef = useAutofocus();
this.showInput = true;
@@ -112,7 +113,7 @@ QUnit.module("utils", () => {
QUnit.module("useBus");
QUnit.test("useBus hook: simple usecase", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useBus(this.env.bus, "test-event", this.myCallback);
}
@@ -138,7 +139,7 @@ QUnit.module("utils", () => {
QUnit.module("useListener");
QUnit.test("useListener: simple usecase", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useListener("click", () => assert.step("click"));
}
@@ -154,7 +155,7 @@ QUnit.module("utils", () => {
});
QUnit.test("useListener: event delegation", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.flag = true;
useListener("click", "button", () => assert.step("click"));
@@ -185,7 +186,7 @@ QUnit.module("utils", () => {
});
QUnit.test("useListener: event delegation with capture option", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.flag = false;
useListener("click", "button", () => assert.step("click"), { capture: true });
@@ -217,7 +218,7 @@ QUnit.module("utils", () => {
QUnit.module("useService");
QUnit.test("useService: unavailable service", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useService("toy_service");
}
@@ -234,7 +235,7 @@ QUnit.module("utils", () => {
});
QUnit.test("useService: service that returns null", async function (assert) {
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
this.toyService = useService("toy_service");
}
@@ -4,6 +4,7 @@ odoo.define('web.component_extension_tests', function (require) {
const makeTestEnvironment = require("web.test_env");
const testUtils = require("web.test_utils");
const { destroy, getFixture, mount } = require("@web/../tests/helpers/utils");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, xml } = owl;
const { useListener } = require("@web/core/utils/hooks");
@@ -15,7 +16,7 @@ odoo.define('web.component_extension_tests', function (require) {
QUnit.test("Component destroyed while performing successful RPC", async function (assert) {
assert.expect(1);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`<div/>`;
const env = makeTestEnvironment({}, () => Promise.resolve());
@@ -33,7 +34,7 @@ odoo.define('web.component_extension_tests', function (require) {
QUnit.test("Component destroyed while performing failed RPC", async function (assert) {
assert.expect(1);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`<div/>`;
const env = makeTestEnvironment({}, () => Promise.reject());
@@ -52,7 +53,7 @@ odoo.define('web.component_extension_tests', function (require) {
QUnit.test("useListener handler type", async function (assert) {
assert.expect(1);
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
useListener('custom1', '_onCustom1');
}
@@ -71,7 +72,7 @@ odoo.define('web.component_extension_tests', function (require) {
assert.expect(12);
const env = makeTestEnvironment({}, () => Promise.reject());
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
useListener('custom1', this._onCustom1);
useListener('custom2', this._onCustom2);
@@ -122,7 +123,7 @@ odoo.define('web.component_extension_tests', function (require) {
QUnit.test("useListener with native JS selector", async function (assert) {
assert.expect(3);
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
useListener('custom1', 'div .custom-class', this._onCustom1);
}
@@ -149,7 +150,7 @@ odoo.define('web.component_extension_tests', function (require) {
QUnit.test("useListener with native JS selector delegation", async function (assert) {
assert.expect(3);
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
useListener('custom1', '.custom-class', this._onCustom1);
}
@@ -178,7 +179,7 @@ odoo.define('web.component_extension_tests', function (require) {
QUnit.test("useListener with capture option", async function (assert) {
assert.expect(7);
class Leaf extends Component {
class Leaf extends LegacyComponent {
setup() {
useListener('custom1', this._onCustom1);
}
@@ -188,7 +189,7 @@ odoo.define('web.component_extension_tests', function (require) {
}
Leaf.template = xml`<div class="leaf"/>`;
class Root extends Component {
class Root extends LegacyComponent {
setup() {
useListener('custom1', this._onCustom1, { capture: true });
}
@@ -5,6 +5,7 @@ odoo.define('web.dropdown_menu_tests', function (require) {
const testUtils = require('web.test_utils');
const makeTestEnvironment = require("web.test_env");
const { mount } = require("@web/../tests/helpers/utils");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useState, xml } = owl;
const { createComponent } = testUtils;
@@ -346,7 +347,7 @@ odoo.define('web.dropdown_menu_tests', function (require) {
assert.expect(7);
const items = this.items;
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.state = useState({ items });
}
@@ -393,7 +394,7 @@ odoo.define('web.dropdown_menu_tests', function (require) {
assert.expect(5);
const items = this.items;
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.items = items;
}
@@ -3,12 +3,13 @@ odoo.define('web.pager_tests', function (require) {
const Pager = require('web.Pager');
const testUtils = require('web.test_utils');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { createComponent } = testUtils;
const { Component, xml, useState } = owl;
class PagerController extends Component {
class PagerController extends LegacyComponent {
setup() {
this.state = useState({ ...this.props });
}
@@ -7,6 +7,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
const pyUtils = require('web.py_utils');
const testUtils = require('web.test_utils');
const { getFixture } = require('@web/../tests/helpers/utils');
const cpHelpers = require('@web/../tests/search/helpers');
const { createComponent } = testUtils;
@@ -14,6 +15,8 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
await cpHelpers.toggleMenu(el, "Add Custom Filter");
};
let target;
QUnit.module('Components', {
beforeEach: function () {
this.fields = {
@@ -25,6 +28,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
float_field: { name: 'float_field', string: "Floaty McFloatface", type: 'float', searchable: true },
color: { name: 'color', string: "Color", type: 'selection', selection: [['black', "Black"], ['white', "White"]], searchable: true },
};
target = getFixture();
},
}, function () {
@@ -33,7 +37,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
QUnit.test('basic rendering', async function (assert) {
assert.expect(16);
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -42,41 +46,41 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
},
});
assert.strictEqual(cfi.el.innerText.trim(), "Add Custom Filter");
assert.hasClass(cfi.el, 'o_add_custom_filter_menu');
assert.strictEqual(cfi.el.children.length, 1);
assert.strictEqual(target.querySelector(".dropdown").innerText.trim(), "Add Custom Filter");
assert.hasClass(target.querySelector(".dropdown"), "o_add_custom_filter_menu");
assert.strictEqual(target.querySelector(".dropdown").children.length, 1);
await toggleAddCustomFilterStandalone(cfi);
await toggleAddCustomFilterStandalone(target);
// Single condition
assert.containsOnce(cfi, '.o_filter_condition');
assert.containsOnce(cfi, '.o_filter_condition select.o_generator_menu_field');
assert.containsOnce(cfi, '.o_filter_condition select.o_generator_menu_operator');
assert.containsOnce(cfi, '.o_filter_condition span.o_generator_menu_value');
assert.containsNone(cfi, '.o_filter_condition .o_or_filter');
assert.containsNone(cfi, '.o_filter_condition .o_generator_menu_delete');
assert.containsOnce(target, '.o_filter_condition');
assert.containsOnce(target, '.o_filter_condition select.o_generator_menu_field');
assert.containsOnce(target, '.o_filter_condition select.o_generator_menu_operator');
assert.containsOnce(target, '.o_filter_condition span.o_generator_menu_value');
assert.containsNone(target, '.o_filter_condition .o_or_filter');
assert.containsNone(target, '.o_filter_condition .o_generator_menu_delete');
// no deletion allowed on single condition
assert.containsNone(cfi, '.o_filter_condition > i.o_generator_menu_delete');
assert.containsNone(target, '.o_filter_condition > i.o_generator_menu_delete');
// Buttons
assert.containsOnce(cfi, 'button.o_apply_filter');
assert.containsOnce(cfi, 'button.o_add_condition');
assert.containsOnce(target, 'button.o_apply_filter');
assert.containsOnce(target, 'button.o_add_condition');
assert.containsOnce(cfi, '.o_filter_condition');
assert.containsOnce(target, '.o_filter_condition');
await cpHelpers.addCondition(cfi);
await cpHelpers.addCondition(target);
assert.containsN(cfi, '.o_filter_condition', 2);
assert.containsOnce(cfi, '.o_filter_condition .o_or_filter');
assert.containsN(cfi, '.o_filter_condition .o_generator_menu_delete', 2);
assert.containsN(target, '.o_filter_condition', 2);
assert.containsOnce(target, '.o_filter_condition .o_or_filter');
assert.containsN(target, '.o_filter_condition .o_generator_menu_delete', 2);
});
QUnit.test('custom OR filter presets new condition from preceding', async function (assert) {
assert.expect(4);
const searchModel = new ActionModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -84,30 +88,30 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
});
// Open custom filter form
await toggleAddCustomFilterStandalone(cfi);
await toggleAddCustomFilterStandalone(target);
// Retrieve second selectable values for field and operator dropdowns
const fieldSecondValue = cfi.el.querySelector('.o_generator_menu_field option:nth-of-type(2)').value;
const operatorSecondValue = cfi.el.querySelector('.o_generator_menu_operator option:nth-of-type(2)').value;
const fieldSecondValue = target.querySelector('.o_generator_menu_field option:nth-of-type(2)').value;
const operatorSecondValue = target.querySelector('.o_generator_menu_operator option:nth-of-type(2)').value;
// Check if they really exist…
assert.ok(!!fieldSecondValue);
assert.ok(!!operatorSecondValue);
// Add first filter condition
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), fieldSecondValue);
await cpHelpers.editConditionOperator(cfi, 0, operatorSecondValue);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), fieldSecondValue);
await cpHelpers.editConditionOperator(target, 0, operatorSecondValue);
// Add a second conditon on the filter being created
await cpHelpers.addCondition(cfi);
await cpHelpers.addCondition(target);
// Check the defaults for field and operator dropdowns
assert.strictEqual(
cfi.el.querySelector('.o_filter_condition:nth-of-type(2) .o_generator_menu_field').value,
target.querySelector('.o_filter_condition:nth-of-type(2) .o_generator_menu_field').value,
fieldSecondValue
);
assert.strictEqual(
cfi.el.querySelector('.o_filter_condition:nth-of-type(2) .o_generator_menu_operator').value,
target.querySelector('.o_filter_condition:nth-of-type(2) .o_generator_menu_operator').value,
operatorSecondValue
);
});
@@ -124,7 +128,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -137,9 +141,9 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
domain: '[["binary_field","!=",False]]',
type: 'filter',
}];
await toggleAddCustomFilterStandalone(cfi);
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'binary_field');
await cpHelpers.applyFilter(cfi);
await toggleAddCustomFilterStandalone(target);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'binary_field');
await cpHelpers.applyFilter(target);
// Updated value
expectedFilters = [{
@@ -147,9 +151,9 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
domain: '[["binary_field","=",False]]',
type: 'filter',
}];
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'binary_field');
await cpHelpers.editConditionOperator(cfi, 0, '=');
await cpHelpers.applyFilter(cfi);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'binary_field');
await cpHelpers.editConditionOperator(target, 0, '=');
await cpHelpers.applyFilter(target);
});
QUnit.test('selection field: default and updated value', async function (assert) {
@@ -164,7 +168,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -177,9 +181,9 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
domain: '[["color","=","black"]]',
type: 'filter',
}];
await toggleAddCustomFilterStandalone(cfi);
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'color');
await cpHelpers.applyFilter(cfi);
await toggleAddCustomFilterStandalone(target);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'color');
await cpHelpers.applyFilter(target);
// Updated value
expectedFilters = [{
@@ -187,9 +191,9 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
domain: '[["color","=","white"]]',
type: 'filter',
}];
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'color');
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_value select'), 'white');
await cpHelpers.applyFilter(cfi);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'color');
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_value select'), 'white');
await cpHelpers.applyFilter(target);
});
QUnit.test('adding a simple filter works', async function (assert) {
@@ -208,21 +212,21 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
env: { searchModel },
});
await toggleAddCustomFilterStandalone(cfi);
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'boolean_field');
await cpHelpers.applyFilter(cfi);
await toggleAddCustomFilterStandalone(target);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'boolean_field');
await cpHelpers.applyFilter(target);
// The only things visible should be the button 'Add Custom Filter' and the menu;
assert.strictEqual(cfi.el.children.length, 2);
assert.containsOnce(cfi, 'button.dropdown-toggle');
assert.containsOnce(cfi, '.dropdown-menu');
assert.strictEqual(target.querySelector(".dropdown").children.length, 2);
assert.containsOnce(target, 'button.dropdown-toggle');
assert.containsOnce(target, '.dropdown-menu');
});
QUnit.test('filtering by ID interval works', async function (assert) {
@@ -246,7 +250,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -255,15 +259,15 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
async function testValue(operator, value) {
// open filter menu generator, select ID field, switch operator, type value, then click apply
await cpHelpers.editConditionField(cfi, 0, 'id_field');
await cpHelpers.editConditionOperator(cfi, 0, operator);
await cpHelpers.editConditionValue(cfi, 0,
await cpHelpers.editConditionField(target, 0, 'id_field');
await cpHelpers.editConditionOperator(target, 0, operator);
await cpHelpers.editConditionValue(target, 0,
value
);
await cpHelpers.applyFilter(cfi);
await cpHelpers.applyFilter(target);
}
await toggleAddCustomFilterStandalone(cfi);
await toggleAddCustomFilterStandalone(target);
for (const domain of [...expectedDomains]) {
await testValue(domain[0][1], domain[0][2]);
}
@@ -296,7 +300,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -305,14 +309,14 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
async function testValue(value) {
// open filter menu generator, select trululu field and enter string `a`, then click apply
await cpHelpers.editConditionField(cfi, 0, 'many2one_field');
await cpHelpers.editConditionValue(cfi, 0,
await cpHelpers.editConditionField(target, 0, 'many2one_field');
await cpHelpers.editConditionValue(target, 0,
value
);
await cpHelpers.applyFilter(cfi);
await cpHelpers.applyFilter(target);
}
await toggleAddCustomFilterStandalone(cfi);
await toggleAddCustomFilterStandalone(target);
for (const value of testedValues) {
await testValue(value);
}
@@ -337,7 +341,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -349,15 +353,15 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
env: { searchModel },
});
await toggleAddCustomFilterStandalone(cfi);
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'date_time_field');
await toggleAddCustomFilterStandalone(target);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'date_time_field');
assert.strictEqual(cfi.el.querySelector('.o_generator_menu_field').value, 'date_time_field');
assert.strictEqual(cfi.el.querySelector('.o_generator_menu_operator').value, 'between');
assert.strictEqual(target.querySelector('.o_generator_menu_field').value, 'date_time_field');
assert.strictEqual(target.querySelector('.o_generator_menu_operator').value, 'between');
await cpHelpers.editConditionOperator(cfi, 0, '=');
await testUtils.fields.editSelect(cfi.el.querySelector('.o_filter_condition span.o_generator_menu_value input'), '02/22/2017 11:00:00'); // in TZ
await cpHelpers.applyFilter(cfi);
await cpHelpers.editConditionOperator(target, 0, '=');
await testUtils.fields.editSelect(target.querySelector('.o_filter_condition span.o_generator_menu_value input'), '02/22/2017 11:00:00'); // in TZ
await cpHelpers.applyFilter(target);
});
QUnit.test('custom filter datetime between operator', async function (assert) {
@@ -378,7 +382,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -390,16 +394,16 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
env: { searchModel },
});
await toggleAddCustomFilterStandalone(cfi);
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'date_time_field');
await toggleAddCustomFilterStandalone(target);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'date_time_field');
assert.strictEqual(cfi.el.querySelector('.o_generator_menu_field').value, 'date_time_field');
assert.strictEqual(cfi.el.querySelector('.o_generator_menu_operator').value, 'between');
assert.strictEqual(target.querySelector('.o_generator_menu_field').value, 'date_time_field');
assert.strictEqual(target.querySelector('.o_generator_menu_operator').value, 'between');
const valueInputs = cfi.el.querySelectorAll('.o_generator_menu_value .o_input');
const valueInputs = target.querySelectorAll('.o_generator_menu_value .o_input');
await testUtils.fields.editSelect(valueInputs[0], '02/22/2017 11:00:00'); // in TZ
await testUtils.fields.editSelect(valueInputs[1], '02-22-2017 17:00:00'); // in TZ
await cpHelpers.applyFilter(cfi);
await cpHelpers.applyFilter(target);
});
QUnit.test('default custom filter datetime', async function (assert) {
@@ -418,7 +422,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -430,19 +434,19 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
env: { searchModel },
});
await toggleAddCustomFilterStandalone(cfi);
await testUtils.fields.editSelect(cfi.el.querySelector('.o_generator_menu_field'), 'date_time_field');
await toggleAddCustomFilterStandalone(target);
await testUtils.fields.editSelect(target.querySelector('.o_generator_menu_field'), 'date_time_field');
assert.strictEqual(cfi.el.querySelector('.o_generator_menu_field').value, 'date_time_field');
assert.strictEqual(cfi.el.querySelector('.o_generator_menu_operator').value, 'between');
assert.strictEqual(target.querySelector('.o_generator_menu_field').value, 'date_time_field');
assert.strictEqual(target.querySelector('.o_generator_menu_operator').value, 'between');
await cpHelpers.applyFilter(cfi);
await cpHelpers.applyFilter(target);
});
QUnit.test('input value parsing', async function (assert) {
assert.expect(7);
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -451,31 +455,31 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
},
});
await toggleAddCustomFilterStandalone(cfi);
await cpHelpers.addCondition(cfi);
await toggleAddCustomFilterStandalone(target);
await cpHelpers.addCondition(target);
await cpHelpers.editConditionField(cfi, 0, "float_field");
await cpHelpers.editConditionField(cfi, 1, "id");
await cpHelpers.editConditionField(target, 0, "float_field");
await cpHelpers.editConditionField(target, 1, "id");
const [floatInput, idInput] = cfi.el.querySelectorAll('.o_generator_menu_value .o_input');
const [floatInput, idInput] = target.querySelectorAll('.o_generator_menu_value .o_input');
// Default values
assert.strictEqual(floatInput.value, "0.0");
assert.strictEqual(idInput.value, "0");
// Float parsing
await cpHelpers.editConditionValue(cfi, 0, "4.2");
await cpHelpers.editConditionValue(target, 0, "4.2");
assert.strictEqual(floatInput.value, "4.2");
await cpHelpers.editConditionValue(cfi, 0, "DefinitelyValidFloat");
await cpHelpers.editConditionValue(target, 0, "DefinitelyValidFloat");
// String input in a number input gives "", which is parsed as 0
assert.strictEqual(floatInput.value, "0.0");
// Number parsing
await cpHelpers.editConditionValue(cfi, 1, "4");
await cpHelpers.editConditionValue(target, 1, "4");
assert.strictEqual(idInput.value, "4");
await cpHelpers.editConditionValue(cfi, 1, "4.2");
await cpHelpers.editConditionValue(target, 1, "4.2");
assert.strictEqual(idInput.value, "4");
await cpHelpers.editConditionValue(cfi, 1, "DefinitelyValidID");
await cpHelpers.editConditionValue(target, 1, "DefinitelyValidID");
// String input in a number input gives "", which is parsed as 0
assert.strictEqual(idInput.value, "0");
});
@@ -483,7 +487,7 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
QUnit.test('input value parsing with language', async function (assert) {
assert.expect(5);
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
@@ -498,24 +502,24 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
},
});
await toggleAddCustomFilterStandalone(cfi);
await cpHelpers.addCondition(cfi);
await toggleAddCustomFilterStandalone(target);
await cpHelpers.addCondition(target);
await cpHelpers.editConditionField(cfi, 0, "float_field");
await cpHelpers.editConditionField(target, 0, "float_field");
const [floatInput] = cfi.el.querySelectorAll('.o_generator_menu_value .o_input');
const [floatInput] = target.querySelectorAll('.o_generator_menu_value .o_input');
// Default values
assert.strictEqual(floatInput.value, "0,0");
// Float parsing
await cpHelpers.editConditionValue(cfi, 0, '4,');
await cpHelpers.editConditionValue(target, 0, '4,');
assert.strictEqual(floatInput.value, "4,");
await cpHelpers.editConditionValue(cfi, 0, '4,2');
await cpHelpers.editConditionValue(target, 0, '4,2');
assert.strictEqual(floatInput.value, "4,2");
await cpHelpers.editConditionValue(cfi, 0, '4,2,');
await cpHelpers.editConditionValue(target, 0, '4,2,');
assert.strictEqual(floatInput.value, "4,2");
await cpHelpers.editConditionValue(cfi, 0, "DefinitelyValidFloat");
await cpHelpers.editConditionValue(target, 0, "DefinitelyValidFloat");
// The input here is a string, resulting in a parsing error instead of 0
assert.strictEqual(floatInput.value, "4,2");
});
@@ -554,37 +558,37 @@ odoo.define('web.filter_menu_generator_tests', function (require) {
}
}
const searchModel = new MockedSearchModel();
const cfi = await createComponent(CustomFilterItem, {
await createComponent(CustomFilterItem, {
props: {
fields: this.fields,
},
env: { searchModel },
});
await toggleAddCustomFilterStandalone(cfi);
await cpHelpers.addCondition(cfi);
await cpHelpers.addCondition(cfi);
await cpHelpers.addCondition(cfi);
await cpHelpers.addCondition(cfi);
await toggleAddCustomFilterStandalone(target);
await cpHelpers.addCondition(target);
await cpHelpers.addCondition(target);
await cpHelpers.addCondition(target);
await cpHelpers.addCondition(target);
await cpHelpers.editConditionField(cfi, 0, 'date_field');
await cpHelpers.editConditionValue(cfi, 0, '01/09/1997');
await cpHelpers.editConditionField(target, 0, 'date_field');
await cpHelpers.editConditionValue(target, 0, '01/09/1997');
await cpHelpers.editConditionField(cfi, 1, 'boolean_field');
await cpHelpers.editConditionOperator(cfi, 1, '!=');
await cpHelpers.editConditionField(target, 1, 'boolean_field');
await cpHelpers.editConditionOperator(target, 1, '!=');
await cpHelpers.editConditionField(cfi, 2, 'char_field');
await cpHelpers.editConditionValue(cfi, 2, "I will be deleted anyway");
await cpHelpers.editConditionField(target, 2, 'char_field');
await cpHelpers.editConditionValue(target, 2, "I will be deleted anyway");
await cpHelpers.editConditionField(cfi, 3, 'float_field');
await cpHelpers.editConditionValue(cfi, 3, 7.2);
await cpHelpers.editConditionField(target, 3, 'float_field');
await cpHelpers.editConditionValue(target, 3, 7.2);
await cpHelpers.editConditionField(cfi, 4, 'id');
await cpHelpers.editConditionValue(cfi, 4, 9);
await cpHelpers.editConditionField(target, 4, 'id');
await cpHelpers.editConditionValue(target, 4, 9);
await cpHelpers.removeCondition(cfi, 2);
await cpHelpers.removeCondition(target, 2);
await cpHelpers.applyFilter(cfi);
await cpHelpers.applyFilter(target);
});
});
});
@@ -15,6 +15,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
destroy,
} = require("@web/../tests/helpers/utils");
const { createWebClient, doAction } = require("@web/../tests/webclient/helpers");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useState, xml } = owl;
const EscapeKey = { key: 'Escape', keyCode: 27, which: 27 };
@@ -25,7 +26,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
QUnit.test("Rendering of all props", async function (assert) {
assert.expect(36);
class SubComponent extends Component {
class SubComponent extends LegacyComponent {
// Handlers
_onClick() {
assert.step('subcomponent_clicked');
@@ -33,7 +34,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
}
SubComponent.template = xml`<div class="o_subcomponent" t-esc="props.text" t-on-click="_onClick"/>`;
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.state = useState({ textContent: "sup" });
}
@@ -174,7 +175,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
assert.expect(23);
const { legacyEnv } = await makeLegacyDialogMappingTestEnv();
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.dialogIds = useState([]);
}
@@ -277,7 +278,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
assert.expect(9);
const { legacyEnv, env } = await makeLegacyDialogMappingTestEnv();
class OwlDialogWrapper extends Component {
class OwlDialogWrapper extends LegacyComponent {
setup() {
this.env = legacyEnv;
this.__owl__.childEnv = legacyEnv;
@@ -295,7 +296,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
this.contentClass = this.props.contentClass;
}
}
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.dialogs = useState([]);
}
@@ -357,7 +358,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
return modal;
}
class Parent1 extends Component {
class Parent1 extends LegacyComponent {
setup() {
}
}
@@ -371,7 +372,7 @@ odoo.define('web.owl_dialog_tests', function (require) {
env: makeTestEnvironment(),
});
class Parent2 extends Component {
class Parent2 extends LegacyComponent {
setup() {
this.state = useState({ showSecondDialog: true });
}
@@ -5,6 +5,7 @@ odoo.define('web.popover_tests', function (require) {
const Popover = require('web.Popover');
const testUtils = require('web.test_utils');
const { click, mount } = require("@web/../tests/helpers/utils");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, useState, xml } = owl;
@@ -14,12 +15,12 @@ odoo.define('web.popover_tests', function (require) {
QUnit.test('Basic rendering & props', async function (assert) {
assert.expect(11);
class SubComponent extends Component {}
class SubComponent extends LegacyComponent {}
SubComponent.template = xml`
<div class="o_subcomponent" style="width: 280px;" t-esc="props.text"/>
`;
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.state = useState({
@@ -143,7 +144,7 @@ odoo.define('web.popover_tests', function (require) {
QUnit.test('Multiple popovers', async function (assert) {
assert.expect(9);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.components = { Popover };
Parent.template = xml`
<div>
@@ -191,7 +192,7 @@ odoo.define('web.popover_tests', function (require) {
QUnit.test('toggle', async function (assert) {
assert.expect(4);
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.template = xml`
<div>
<Popover>
@@ -224,7 +225,7 @@ odoo.define('web.popover_tests', function (require) {
assert.expect(7);
// Needed to trigger the event from inside the Popover slot.
class Content extends Component {
class Content extends LegacyComponent {
onClick() {
this.trigger("o-popover-close");
}
@@ -235,7 +236,7 @@ odoo.define('web.popover_tests', function (require) {
</button>
`;
class Parent extends Component {}
class Parent extends LegacyComponent {}
Parent.components = { Content, Popover };
Parent.template = xml`
<div>
@@ -22,6 +22,7 @@ odoo.define('web.test_utils_create', function (require) {
const Widget = require('web.Widget');
const { destroy, getFixture, mount, useChild } = require('@web/../tests/helpers/utils');
const { registerCleanup } = require("@web/../tests/helpers/cleanup");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, onMounted, onWillStart, useState, xml } = owl;
@@ -82,7 +83,7 @@ odoo.define('web.test_utils_create', function (require) {
throw new Error(`Argument "constructor" must be an Owl Component.`);
}
const cleanUp = await testUtilsMock.addMockEnvironmentOwl(Component, params);
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.Component = constructor;
this.state = useState(params.props || {});
@@ -157,7 +158,7 @@ odoo.define('web.test_utils_create', function (require) {
ControlPanel: { archNodes: controlPanelInfo.children, },
};
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.searchModel = new ActionModel(extensions, globalConfig);
this.state = useState(props);
@@ -12,6 +12,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
} = require('web.OwlCompatibility');
const testUtils = require('web.test_utils');
const Widget = require('web.Widget');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const makeTestPromise = testUtils.makeTestPromise;
const nextTick = testUtils.nextTick;
@@ -52,7 +53,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text('Hello World!');
}
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -82,7 +83,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text(`Hello ${this.name}!`);
}
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -113,7 +114,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text(`${this.a1} ${this.a2}!`);
}
});
class Parent extends Component {
class Parent extends LegacyComponent {
setup() {
this.MyWidget = MyWidget;
this.error = false;
@@ -157,7 +158,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
return [this.props.a1, this.props.a2];
}
}
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -188,7 +189,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text(`${this.a1} ${this.a2}!`);
}
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -232,7 +233,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.widget.render();
}
}
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -287,13 +288,13 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.widget.render();
}
}
class AsyncComponent extends Component {
class AsyncComponent extends LegacyComponent {
setup() {
onWillUpdateProps(() => prom);
}
}
AsyncComponent.template = xml`<div>Hi <t t-esc="props.name"/>!</div>`;
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -342,7 +343,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this._super.apply(this, arguments);
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -372,9 +373,9 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text('widget');
},
});
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.template = xml`<div>component</div>`;
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.Children = [MyWidget, MyComponent];
@@ -402,7 +403,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
widget = this;
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -435,7 +436,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
return this._rpc({ route: 'some/route', params: { val: 2 } });
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -478,7 +479,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
assert.strictEqual(result, 3);
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -510,7 +511,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
assert.strictEqual(this.getSession().key, 'value');
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -538,7 +539,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
return this.loadViews('some_model', { x: 2 }, [[false, 'list']]);
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -579,7 +580,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text('Hello');
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget1 = MyWidget1;
@@ -622,7 +623,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text('Hi');
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -695,7 +696,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.widget.render();
}
}
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -766,7 +767,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.widget.render();
}
}
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -812,7 +813,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
let component;
let wrapper;
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
component = this;
}
@@ -838,7 +839,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("sub component hooks are correctly called", async function (assert) {
assert.expect(13);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
assert.step("setup");
onWillStart(() => {
@@ -889,7 +890,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("lifecycle with several sub components", async function (assert) {
assert.expect(21);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert), this.props.id);
}
@@ -945,13 +946,13 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("lifecycle with several levels of sub components", async function (assert) {
assert.expect(21);
class MyChildComponent extends Component {
class MyChildComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
}
MyChildComponent.template = xml`<div>child</div>`;
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
@@ -1007,13 +1008,13 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("lifecycle mount in fragment", async function (assert) {
assert.expect(17);
class MyChildComponent extends Component {
class MyChildComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
}
MyChildComponent.template = xml`<div>child</div>`;
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
@@ -1064,13 +1065,13 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("lifecycle mount/unmount", async function (assert) {
assert.expect(37);
class MyChildComponent extends Component {
class MyChildComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
}
MyChildComponent.template = xml`<div>child</div>`;
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
@@ -1139,13 +1140,13 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("lifecycle mount/unmount/update", async function (assert) {
assert.expect(24);
class MyChildComponent extends Component {
class MyChildComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
}
MyChildComponent.template = xml`<div>child <t t-esc="props.text" /></div>`;
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
@@ -1198,13 +1199,13 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("lifecycle mount/unmount/update/render", async function (assert) {
assert.expect(36);
class MyChildComponent extends Component {
class MyChildComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
}
MyChildComponent.template = xml`<div>child <t t-esc="props.text" /></div>`;
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle(assert.step.bind(assert));
}
@@ -1272,7 +1273,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("sub component can be updated (in DOM)", async function (assert) {
assert.expect(2);
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.template = xml`<div>Component <t t-esc="props.val"/></div>`;
const MyWidget = WidgetAdapter.extend({
start() {
@@ -1300,7 +1301,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("sub component can be updated (not in DOM)", async function (assert) {
assert.expect(18);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
setup() {
useLogLifeCycle((log) => assert.step(log));
}
@@ -1361,7 +1362,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("update a destroyed sub component", async function (assert) {
assert.expect(1);
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.template = xml`<div>Component <t t-esc="props.val"/></div>`;
const MyWidget = WidgetAdapter.extend({
start() {
@@ -1387,7 +1388,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
QUnit.test("sub component that triggers events", async function (assert) {
assert.expect(3);
class WidgetComponent extends Component {}
class WidgetComponent extends LegacyComponent {}
WidgetComponent.template = xml`<div>Component</div>`;
const MyWidget = WidgetAdapter.extend({
@@ -1420,7 +1421,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
let myComponent;
let widget1;
let widget2;
class WidgetComponent extends Component {}
class WidgetComponent extends LegacyComponent {}
WidgetComponent.template = xml`<div>Component</div>`;
const MyWidget = WidgetAdapter.extend({
custom_events: _.extend({}, Widget.custom_events, {
@@ -1479,7 +1480,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
assert.expect(7);
let leafComponent;
class MyComponent extends Component {}
class MyComponent extends LegacyComponent {}
MyComponent.template = xml`<span>Component</span>`;
const MyWidget = WidgetAdapter.extend({
custom_events: {
@@ -1498,7 +1499,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
return leafComponent.mount(this.el);
},
});
class Parent extends Component {
class Parent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -1546,7 +1547,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
this.$el.text('Widget');
}
});
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
constructor() {
super(...arguments);
this.MyWidget = MyWidget;
@@ -1620,7 +1621,7 @@ odoo.define('web.OwlCompatibilityTests', function (require) {
});
fieldRegistry.add('pad_like', PadLikeWidget);
class WidgetComponent extends Component {}
class WidgetComponent extends LegacyComponent {}
WidgetComponent.template = xml`<div>Widget</div>`;
widgetRegistry.add("widget_comp", WidgetComponent);
@@ -5,6 +5,7 @@ odoo.define('web.basic_view_tests', function (require) {
const BasicRenderer = require("web.BasicRenderer");
const testUtils = require('web.test_utils');
const widgetRegistryOwl = require('web.widgetRegistry');
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, xml } = owl;
@@ -43,7 +44,7 @@ odoo.define('web.basic_view_tests', function (require) {
})
});
class MyWidget extends Component {}
class MyWidget extends LegacyComponent {}
MyWidget.fieldDependencies = {
foo: { type: 'char' },
bar: { type: 'boolean' },
@@ -30,6 +30,7 @@ const makeTestEnvironment = require("web.test_env");
const { mapLegacyEnvToWowlEnv } = require("@web/legacy/utils");
const { registry } = require("@web/core/registry");
const { scrollerService } = require("@web/core/scroller_service");
const { LegacyComponent } = require("@web/legacy/legacy_component");
const { Component, onMounted, onWillUnmount, xml } = owl;
@@ -8351,7 +8352,7 @@ QUnit.module('Views', {
QUnit.test('basic support for widgets (being Owl Components)', async function (assert) {
assert.expect(1);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
get value() {
return JSON.stringify(this.props.record.data);
}
@@ -13,6 +13,7 @@ var testUtils = require('web.test_utils');
var Widget = require('web.Widget');
var widgetRegistry = require('web.widget_registry');
const widgetRegistryOwl = require('web.widgetRegistry');
const { LegacyComponent } = require("@web/legacy/legacy_component");
var makeTestPromise = testUtils.makeTestPromise;
var nextTick = testUtils.nextTick;
@@ -6174,7 +6175,7 @@ QUnit.module('Views', {
QUnit.test('basic support for widgets (being Owl Components)', async function (assert) {
assert.expect(1);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
get value() {
return JSON.stringify(this.props.record.data);
}
@@ -22,6 +22,7 @@ const Widget = require('web.Widget');
const ControlPanel = require('web.ControlPanel');
const ListController = require('web.ListController');
const cpHelpers = require('@web/../tests/search/helpers');
const { LegacyComponent } = require("@web/legacy/legacy_component");
var createView = testUtils.createView;
const { getFixture, click, legacyExtraNextTick } = require("@web/../tests/helpers/utils");
@@ -9309,7 +9310,7 @@ QUnit.module('Views', {
QUnit.test('basic support for widgets (being Owl Components)', async function (assert) {
assert.expect(1);
class MyComponent extends Component {
class MyComponent extends LegacyComponent {
get value() {
return JSON.stringify(this.props.record.data);
}
@@ -24,6 +24,7 @@ import ActionModel from "web.ActionModel";
import { mock } from "web.test_utils";
import legacyViewRegistry from "web.view_registry";
import { browser } from "@web/core/browser/browser";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
const serviceRegistry = registry.category("services");
@@ -78,7 +79,7 @@ QUnit.module("Views", (hooks) => {
setupControlPanelServiceRegistry();
serviceRegistry.add("dialog", dialogService);
class ToyView extends Component {}
class ToyView extends LegacyComponent {}
ToyView.components = { ControlPanel };
ToyView.display_name = _lt("Toy view");
ToyView.icon = "fab fa-android";
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
import { getFixture, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
import { browser } from "@web/core/browser/browser";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import {
@@ -14,6 +14,7 @@ import {
toggleMenuItemOption,
} from "./helpers";
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -40,6 +41,7 @@ QUnit.module("Search", (hooks) => {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
target = getFixture();
});
QUnit.module("Comparison");
@@ -47,30 +49,28 @@ QUnit.module("Search", (hooks) => {
QUnit.test("simple rendering", async function (assert) {
assert.expect(6);
patchDate(1997, 0, 9, 12, 0, 0);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
searchMenuTypes: ["filter", "comparison"],
searchViewId: false,
});
assert.containsOnce(controlPanel, ".dropdown.o_filter_menu");
assert.containsNone(controlPanel, ".dropdown.o_comparison_menu");
await toggleFilterMenu(controlPanel);
await toggleMenuItem(controlPanel, "Birthday");
await toggleMenuItemOption(controlPanel, "Birthday", "January");
assert.containsOnce(controlPanel, "div.o_comparison_menu > button i.oi.oi-contrast");
assert.containsOnce(target, ".dropdown.o_filter_menu");
assert.containsNone(target, ".dropdown.o_comparison_menu");
await toggleFilterMenu(target);
await toggleMenuItem(target, "Birthday");
await toggleMenuItemOption(target, "Birthday", "January");
assert.containsOnce(target, "div.o_comparison_menu > button i.oi.oi-contrast");
assert.strictEqual(
controlPanel.el
target
.querySelector("div.o_comparison_menu > button span")
.innerText.trim()
.toUpperCase() /** @todo why do I need to upperCase */,
"COMPARISON"
);
await toggleComparisonMenu(controlPanel);
const comparisonOptions = [
...controlPanel.el.querySelectorAll(".o_comparison_menu .dropdown-item"),
];
await toggleComparisonMenu(target);
const comparisonOptions = [...target.querySelectorAll(".o_comparison_menu .dropdown-item")];
assert.strictEqual(comparisonOptions.length, 2);
assert.deepEqual(
comparisonOptions.map((e) => e.innerText.trim()),
@@ -81,42 +81,42 @@ QUnit.module("Search", (hooks) => {
QUnit.test("activate a comparison works", async function (assert) {
assert.expect(5);
patchDate(1997, 0, 9, 12, 0, 0);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
searchMenuTypes: ["filter", "comparison"],
searchViewId: false,
});
await toggleFilterMenu(controlPanel);
await toggleMenuItem(controlPanel, "Birthday");
await toggleMenuItemOption(controlPanel, "Birthday", "January");
await toggleComparisonMenu(controlPanel);
await toggleMenuItem(controlPanel, "Birthday: Previous Period");
assert.deepEqual(getFacetTexts(controlPanel), [
await toggleFilterMenu(target);
await toggleMenuItem(target, "Birthday");
await toggleMenuItemOption(target, "Birthday", "January");
await toggleComparisonMenu(target);
await toggleMenuItem(target, "Birthday: Previous Period");
assert.deepEqual(getFacetTexts(target), [
"Birthday: January 1997",
"Birthday: Previous Period",
]);
await toggleFilterMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItemOption(controlPanel, "Date", "December");
await toggleComparisonMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date: Previous Year");
assert.deepEqual(getFacetTexts(controlPanel), [
await toggleFilterMenu(target);
await toggleMenuItem(target, "Date");
await toggleMenuItemOption(target, "Date", "December");
await toggleComparisonMenu(target);
await toggleMenuItem(target, "Date: Previous Year");
assert.deepEqual(getFacetTexts(target), [
["Birthday: January 1997", "Date: December 1996"].join("or"),
"Date: Previous Year",
]);
await toggleFilterMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItemOption(controlPanel, "Date", "1996");
assert.deepEqual(getFacetTexts(controlPanel), ["Birthday: January 1997"]);
await toggleComparisonMenu(controlPanel);
await toggleMenuItem(controlPanel, "Birthday: Previous Year");
assert.deepEqual(getFacetTexts(controlPanel), [
await toggleFilterMenu(target);
await toggleMenuItem(target, "Date");
await toggleMenuItemOption(target, "Date", "1996");
assert.deepEqual(getFacetTexts(target), ["Birthday: January 1997"]);
await toggleComparisonMenu(target);
await toggleMenuItem(target, "Birthday: Previous Year");
assert.deepEqual(getFacetTexts(target), [
"Birthday: January 1997",
"Birthday: Previous Year",
]);
await removeFacet(controlPanel);
assert.deepEqual(getFacetTexts(controlPanel), []);
await removeFacet(target);
assert.deepEqual(getFacetTexts(target), []);
});
});
+19 -17
View File
@@ -1,9 +1,10 @@
/** @odoo-module **/
import { click, nextTick } from "@web/../tests/helpers/utils";
import { click, getFixture, nextTick } from "@web/../tests/helpers/utils";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { makeWithSearch, setupControlPanelServiceRegistry } from "./helpers";
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -18,12 +19,13 @@ QUnit.module("Search", (hooks) => {
},
};
setupControlPanelServiceRegistry();
target = getFixture();
});
QUnit.module("ControlPanel");
QUnit.test("simple rendering", async (assert) => {
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -35,16 +37,16 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: [],
});
assert.containsOnce(controlPanel, ".o_cp_top");
assert.containsOnce(controlPanel, ".o_cp_top_left");
assert.containsNone(controlPanel, ".o_cp_top_right");
assert.containsOnce(controlPanel, ".o_cp_bottom");
assert.containsOnce(controlPanel, ".o_cp_bottom_left");
assert.containsOnce(controlPanel, ".o_cp_bottom_right");
assert.containsOnce(target, ".o_cp_top");
assert.containsOnce(target, ".o_cp_top_left");
assert.containsNone(target, ".o_cp_top_right");
assert.containsOnce(target, ".o_cp_bottom");
assert.containsOnce(target, ".o_cp_bottom_left");
assert.containsOnce(target, ".o_cp_bottom_right");
assert.containsNone(controlPanel, ".o_cp_switch_buttons");
assert.containsNone(target, ".o_cp_switch_buttons");
assert.containsOnce(controlPanel, ".breadcrumb");
assert.containsOnce(target, ".breadcrumb");
});
QUnit.test("breadcrumbs", async (assert) => {
@@ -61,8 +63,8 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: [],
});
assert.containsN(controlPanel, ".breadcrumb li.breadcrumb-item", 2);
const breadcrumbItems = controlPanel.el.querySelectorAll("li.breadcrumb-item");
assert.containsN(target, ".breadcrumb li.breadcrumb-item", 2);
const breadcrumbItems = target.querySelectorAll("li.breadcrumb-item");
assert.strictEqual(breadcrumbItems[0].innerText, "Previous");
assert.hasClass(breadcrumbItems[1], "active");
assert.strictEqual(breadcrumbItems[1].innerText, "Current");
@@ -89,9 +91,9 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: [],
});
assert.containsOnce(controlPanel, ".o_cp_switch_buttons");
assert.containsN(controlPanel, ".o_switch_view", 2);
const views = controlPanel.el.querySelectorAll(".o_switch_view");
assert.containsOnce(target, ".o_cp_switch_buttons");
assert.containsN(target, ".o_switch_view", 2);
const views = target.querySelectorAll(".o_switch_view");
assert.strictEqual(views[0].getAttribute("data-tooltip"), "List");
assert.hasClass(views[0], "active");
@@ -123,11 +125,11 @@ QUnit.module("Search", (hooks) => {
},
searchMenuTypes: [],
});
assert.containsOnce(controlPanel.el, ".o_pager");
assert.containsOnce(target, ".o_pager");
pagerProps.total = 0;
controlPanel.render();
await nextTick();
assert.containsNone(controlPanel.el, ".o_pager");
assert.containsNone(target, ".o_pager");
});
});
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { patchWithCleanup, triggerEvent } from "@web/../tests/helpers/utils";
import { getFixture, patchWithCleanup, triggerEvent } from "@web/../tests/helpers/utils";
import { browser } from "@web/core/browser/browser";
import { dialogService } from "@web/core/dialog/dialog_service";
import { registry } from "@web/core/registry";
@@ -24,23 +24,24 @@ const { Component, xml } = owl;
const serviceRegistry = registry.category("services");
/**
* @param {Component} comp
* @param {HTMLElement} target
*/
async function toggleDefaultCheckBox(comp) {
const checkbox = comp.el.querySelector("input[type='checkbox']");
async function toggleDefaultCheckBox(target) {
const checkbox = target.querySelector("input[type='checkbox']");
checkbox.checked = !checkbox.checked;
await triggerEvent(checkbox, null, "change");
}
/**
* @param {Component} comp
* @param {HTMLElement} target
*/
async function toggleShareCheckBox(comp) {
const checkbox = comp.el.querySelectorAll("input[type='checkbox']")[1];
async function toggleShareCheckBox(target) {
const checkbox = target.querySelectorAll("input[type='checkbox']")[1];
checkbox.checked = !checkbox.checked;
await triggerEvent(checkbox, null, "change");
}
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -68,6 +69,8 @@ QUnit.module("Search", (hooks) => {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
target = getFixture();
});
QUnit.module("CustomFavoriteItem");
@@ -75,7 +78,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("simple rendering", async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -86,18 +89,14 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleFavoriteMenu(controlPanel);
await toggleSaveFavorite(controlPanel);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
assert.strictEqual(
controlPanel.el.querySelector('.o_add_favorite input[type="text"]').value,
target.querySelector('.o_add_favorite input[type="text"]').value,
"Action Name"
);
assert.containsN(
controlPanel,
'.o_add_favorite .custom-checkbox input[type="checkbox"]',
2
);
const labelEls = controlPanel.el.querySelectorAll(".o_add_favorite .custom-checkbox label");
assert.containsN(target, '.o_add_favorite .custom-checkbox input[type="checkbox"]', 2);
const labelEls = target.querySelectorAll(".o_add_favorite .custom-checkbox label");
assert.deepEqual(
[...labelEls].map((e) => e.innerText.trim()),
["Use by default", "Share with all users"]
@@ -107,7 +106,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("favorites use by default and share are exclusive", async function (assert) {
assert.expect(11);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -115,21 +114,21 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
await toggleFavoriteMenu(controlPanel);
await toggleSaveFavorite(controlPanel);
const checkboxes = controlPanel.el.querySelectorAll('input[type="checkbox"]');
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
const checkboxes = target.querySelectorAll('input[type="checkbox"]');
assert.strictEqual(checkboxes.length, 2, "2 checkboxes are present");
assert.notOk(checkboxes[0].checked, "Start: None of the checkboxes are checked (1)");
assert.notOk(checkboxes[1].checked, "Start: None of the checkboxes are checked (2)");
await toggleDefaultCheckBox(controlPanel);
await toggleDefaultCheckBox(target);
assert.ok(checkboxes[0].checked, "The first checkbox is checked");
assert.notOk(checkboxes[1].checked, "The second checkbox is not checked");
await toggleShareCheckBox(controlPanel);
await toggleShareCheckBox(target);
assert.notOk(
checkboxes[0].checked,
@@ -140,7 +139,7 @@ QUnit.module("Search", (hooks) => {
"Clicking on the second checkbox checks it, and unchecks the first (2)"
);
await toggleDefaultCheckBox(controlPanel);
await toggleDefaultCheckBox(target);
assert.ok(
checkboxes[0].checked,
@@ -151,7 +150,7 @@ QUnit.module("Search", (hooks) => {
"Clicking on the first checkbox checks it, and unchecks the second (2)"
);
await toggleDefaultCheckBox(controlPanel);
await toggleDefaultCheckBox(target);
assert.notOk(checkboxes[0].checked, "End: None of the checkboxes are checked (1)");
assert.notOk(checkboxes[1].checked, "End: None of the checkboxes are checked (2)");
@@ -172,7 +171,7 @@ QUnit.module("Search", (hooks) => {
TestComponent.components = { FavoriteMenu };
TestComponent.template = xml`<div><FavoriteMenu/></div>`;
const comp = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC: (_, args) => {
if (args.model === "ir.filters" && args.method === "create_or_replace") {
@@ -187,16 +186,16 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
await toggleFavoriteMenu(comp);
await toggleSaveFavorite(comp);
await editFavoriteName(comp, "aaa");
await saveFavorite(comp);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
await editFavoriteName(target, "aaa");
await saveFavorite(target);
});
QUnit.test("dynamic filters are saved dynamic", async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC: (_, args) => {
if (args.model === "ir.filters" && args.method === "create_or_replace") {
@@ -220,20 +219,20 @@ QUnit.module("Search", (hooks) => {
context: { search_default_filter: 1 },
});
assert.deepEqual(getFacetTexts(controlPanel), ["Filter"]);
assert.deepEqual(getFacetTexts(target), ["Filter"]);
await toggleFavoriteMenu(controlPanel);
await toggleSaveFavorite(controlPanel);
await editFavoriteName(controlPanel, "My favorite");
await saveFavorite(controlPanel);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
await editFavoriteName(target, "My favorite");
await saveFavorite(target);
assert.deepEqual(getFacetTexts(controlPanel), ["My favorite"]);
assert.deepEqual(getFacetTexts(target), ["My favorite"]);
});
QUnit.test("save filters created via autocompletion works", async function (assert) {
assert.expect(4);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC: (_, args) => {
if (args.model === "ir.filters" && args.method === "create_or_replace") {
@@ -253,19 +252,19 @@ QUnit.module("Search", (hooks) => {
`,
});
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
await editSearch(controlPanel, "a");
await validateSearch(controlPanel);
await editSearch(target, "a");
await validateSearch(target);
assert.deepEqual(getFacetTexts(controlPanel), ["Foo\na"]);
assert.deepEqual(getFacetTexts(target), ["Foo\na"]);
await toggleFavoriteMenu(controlPanel);
await toggleSaveFavorite(controlPanel);
await editFavoriteName(controlPanel, "My favorite");
await saveFavorite(controlPanel);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
await editFavoriteName(target, "My favorite");
await saveFavorite(target);
assert.deepEqual(getFacetTexts(controlPanel), ["My favorite"]);
assert.deepEqual(getFacetTexts(target), ["My favorite"]);
});
QUnit.test(
@@ -291,7 +290,7 @@ QUnit.module("Search", (hooks) => {
{ force: true }
);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC: (route, args) => {
if (args.model === "ir.filters" && args.method === "create_or_replace") {
@@ -326,20 +325,20 @@ QUnit.module("Search", (hooks) => {
],
});
await toggleFavoriteMenu(controlPanel);
await toggleSaveFavorite(controlPanel);
await toggleFavoriteMenu(target);
await toggleSaveFavorite(target);
// first try: should fail
await editFavoriteName(controlPanel, "My favorite");
await saveFavorite(controlPanel);
await editFavoriteName(target, "My favorite");
await saveFavorite(target);
// second try: should succeed
await editFavoriteName(controlPanel, "My favorite 2");
await saveFavorite(controlPanel);
await editFavoriteName(target, "My favorite 2");
await saveFavorite(target);
// third try: should fail
await editFavoriteName(controlPanel, "My favorite 2");
await saveFavorite(controlPanel);
await editFavoriteName(target, "My favorite 2");
await saveFavorite(target);
}
);
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { registerCleanup } from "@web/../tests/helpers/cleanup";
import { click, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
import { click, getFixture, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
import { localization } from "@web/core/l10n/localization";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { browser } from "@web/core/browser/browser";
@@ -25,6 +25,7 @@ function getDomain(controlPanel) {
return controlPanel.env.searchModel.domain;
}
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -89,6 +90,7 @@ QUnit.module("Search", (hooks) => {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
target = getFixture();
});
QUnit.module("CustomFilterItem");
@@ -96,7 +98,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("basic rendering", async function (assert) {
assert.expect(14);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -104,13 +106,13 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleFilterMenu(target);
const customFilterItem = controlPanel.el.querySelector(".o_add_custom_filter_menu");
const customFilterItem = target.querySelector(".o_add_custom_filter_menu");
assert.strictEqual(customFilterItem.innerText.trim(), "Add Custom Filter");
await toggleAddCustomFilter(controlPanel);
await toggleAddCustomFilter(target);
// Single condition
assert.containsOnce(customFilterItem, ".o_filter_condition");
@@ -147,7 +149,7 @@ QUnit.module("Search", (hooks) => {
async function (assert) {
assert.expect(2);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -166,9 +168,9 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
const optionEls = controlPanel.el.querySelectorAll(
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
const optionEls = target.querySelectorAll(
".o_filter_condition > select.o_generator_menu_field option"
);
assert.strictEqual(optionEls[0].innerText.trim(), "Date");
@@ -181,7 +183,7 @@ QUnit.module("Search", (hooks) => {
patchDate(2020, 1, 5, 12, 20, 0);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -199,23 +201,23 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await applyFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await applyFilter(target);
assert.ok(isItemSelected(controlPanel, 'Date is equal to "02/05/2020"'));
assert.deepEqual(getFacetTexts(controlPanel), ['Date is equal to "02/05/2020"']);
assert.ok(isItemSelected(target, 'Date is equal to "02/05/2020"'));
assert.deepEqual(getFacetTexts(target), ['Date is equal to "02/05/2020"']);
await toggleMenuItem(controlPanel, 'Date is equal to "02/05/2020"');
await toggleMenuItem(target, 'Date is equal to "02/05/2020"');
assert.notOk(isItemSelected(controlPanel, 'Date is equal to "02/05/2020"'));
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.notOk(isItemSelected(target, 'Date is equal to "02/05/2020"'));
assert.deepEqual(getFacetTexts(target), []);
});
QUnit.test("custom OR filter presets new condition from preceding", async function (assert) {
assert.expect(4);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -223,14 +225,14 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
// Retrieve second selectable values for field and operator dropdowns
const secondFieldName = controlPanel.el.querySelector(
const secondFieldName = target.querySelector(
".o_generator_menu_field option:nth-of-type(2)"
).value;
const secondOperator = controlPanel.el.querySelector(
const secondOperator = target.querySelector(
".o_generator_menu_operator option:nth-of-type(2)"
).value;
@@ -239,23 +241,21 @@ QUnit.module("Search", (hooks) => {
assert.ok(!!secondOperator);
// Add first filter condition
await editConditionField(controlPanel, 0, secondFieldName);
await editConditionOperator(controlPanel, 0, secondOperator);
await editConditionField(target, 0, secondFieldName);
await editConditionOperator(target, 0, secondOperator);
// Add a second conditon on the filter being created
await addCondition(controlPanel);
await addCondition(target);
// Check the defaults for field and operator dropdowns
assert.strictEqual(
controlPanel.el.querySelector(
".o_filter_condition:nth-of-type(2) .o_generator_menu_field"
).value,
target.querySelector(".o_filter_condition:nth-of-type(2) .o_generator_menu_field")
.value,
secondFieldName
);
assert.strictEqual(
controlPanel.el.querySelector(
".o_filter_condition:nth-of-type(2) .o_generator_menu_operator"
).value,
target.querySelector(".o_filter_condition:nth-of-type(2) .o_generator_menu_operator")
.value,
secondOperator
);
});
@@ -272,15 +272,15 @@ QUnit.module("Search", (hooks) => {
searchViewFields: {},
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
// choose ID field in 'Add Custom filter' menu and value 1
await editConditionField(controlPanel, 0, "id");
await editConditionValue(controlPanel, 0, 1);
await editConditionField(target, 0, "id");
await editConditionValue(target, 0, 1);
await applyFilter(controlPanel);
await applyFilter(target);
assert.deepEqual(getFacetTexts(controlPanel), ['ID is "1"']);
assert.deepEqual(getFacetTexts(target), ['ID is "1"']);
assert.deepEqual(getDomain(controlPanel), [["id", "=", 1]]);
});
@@ -304,29 +304,29 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleFilterMenu(controlPanel);
await toggleFilterMenu(target);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
assert.deepEqual(getDomain(controlPanel), []);
assert.containsNone(controlPanel, ".o_menu_item");
assert.containsOnce(controlPanel, ".o_add_custom_filter_menu button.dropdown-toggle");
assert.containsNone(target, ".o_menu_item");
assert.containsOnce(target, ".o_add_custom_filter_menu button.dropdown-toggle");
// the 'Add Custom Filter' menu should be closed;
assert.containsNone(controlPanel, ".o_add_custom_filter_menu .dropdown-menu");
assert.containsNone(target, ".o_add_custom_filter_menu .dropdown-menu");
await toggleAddCustomFilter(controlPanel);
await toggleAddCustomFilter(target);
// the 'Add Custom Filter' menu should be open;
assert.containsOnce(controlPanel, ".o_add_custom_filter_menu .dropdown-menu");
assert.containsOnce(target, ".o_add_custom_filter_menu .dropdown-menu");
await applyFilter(controlPanel);
await applyFilter(target);
assert.deepEqual(getFacetTexts(controlPanel), ["Boolean Field is Yes"]);
assert.deepEqual(getFacetTexts(target), ["Boolean Field is Yes"]);
assert.deepEqual(getDomain(controlPanel), [["boolean_field", "=", true]]);
assert.containsOnce(controlPanel, ".o_menu_item");
assert.containsOnce(controlPanel, ".o_add_custom_filter_menu button.dropdown-toggle");
assert.containsOnce(target, ".o_menu_item");
assert.containsOnce(target, ".o_add_custom_filter_menu button.dropdown-toggle");
// the 'Add Custom Filter' menu should still be opened;
assert.containsOnce(controlPanel, ".o_add_custom_filter_menu .dropdown-menu");
assert.containsOnce(target, ".o_add_custom_filter_menu .dropdown-menu");
});
QUnit.test("selection field: default and updated value", async function (assert) {
@@ -341,36 +341,36 @@ QUnit.module("Search", (hooks) => {
});
// Default value
await toggleFilterMenu(controlPanel);
await toggleFilterMenu(target);
assert.containsN(controlPanel, ".o_menu_item", 0);
assert.containsN(controlPanel, ".dropdown-divider", 0);
assert.containsN(target, ".o_menu_item", 0);
assert.containsN(target, ".dropdown-divider", 0);
await toggleAddCustomFilter(controlPanel);
await editConditionField(controlPanel, 0, "color");
await applyFilter(controlPanel);
await toggleAddCustomFilter(target);
await editConditionField(target, 0, "color");
await applyFilter(target);
assert.deepEqual(getFacetTexts(controlPanel), ['Color is "black"']);
assert.deepEqual(getFacetTexts(target), ['Color is "black"']);
assert.deepEqual(getDomain(controlPanel), [["color", "=", "black"]]);
assert.containsN(controlPanel, ".o_menu_item", 1);
assert.containsN(controlPanel, ".dropdown-divider", 1);
assert.containsN(target, ".o_menu_item", 1);
assert.containsN(target, ".dropdown-divider", 1);
// deactivate custom filter
await removeFacet(controlPanel);
await removeFacet(target);
// Updated value
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await editConditionField(controlPanel, 0, "color");
await editConditionValue(controlPanel, 0, "white");
await applyFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await editConditionField(target, 0, "color");
await editConditionValue(target, 0, "white");
await applyFilter(target);
assert.deepEqual(getFacetTexts(controlPanel), ['Color is "white"']);
assert.deepEqual(getFacetTexts(target), ['Color is "white"']);
assert.deepEqual(getDomain(controlPanel), [["color", "=", "white"]]);
assert.containsN(controlPanel, ".o_menu_item", 2);
assert.containsN(controlPanel, ".dropdown-divider", 2);
assert.containsN(target, ".o_menu_item", 2);
assert.containsN(target, ".dropdown-divider", 2);
});
QUnit.test(
@@ -428,15 +428,15 @@ QUnit.module("Search", (hooks) => {
];
for (const step of steps) {
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await editConditionValue(controlPanel, 0, step.value);
await applyFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await editConditionValue(target, 0, step.value);
await applyFilter(target);
assert.deepEqual(getFacetTexts(controlPanel), [step.facetContent]);
assert.deepEqual(getFacetTexts(target), [step.facetContent]);
assert.deepEqual(getDomain(controlPanel), step.domain);
await removeFacet(controlPanel);
await removeFacet(target);
}
}
);
@@ -458,26 +458,23 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await editConditionField(controlPanel, 0, "date_time_field");
await editConditionField(target, 0, "date_time_field");
assert.strictEqual(
controlPanel.el.querySelector(".o_generator_menu_field").value,
target.querySelector(".o_generator_menu_field").value,
"date_time_field"
);
assert.strictEqual(
controlPanel.el.querySelector(".o_generator_menu_operator").value,
"between"
);
assert.strictEqual(target.querySelector(".o_generator_menu_operator").value, "between");
await editConditionOperator(controlPanel, 0, "=");
await editConditionValue(controlPanel, 0, "02/22/2017 11:00:00"); // in TZ
await applyFilter(controlPanel);
await editConditionOperator(target, 0, "=");
await editConditionValue(target, 0, "02/22/2017 11:00:00"); // in TZ
await applyFilter(target);
assert.deepEqual(
getFacetTexts(controlPanel),
getFacetTexts(target),
['DateTime is equal to "02/22/2017 11:00:00"'],
"description should be in localized format"
);
@@ -505,25 +502,22 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await editConditionField(controlPanel, 0, "date_time_field");
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await editConditionField(target, 0, "date_time_field");
assert.strictEqual(
controlPanel.el.querySelector(".o_generator_menu_field").value,
target.querySelector(".o_generator_menu_field").value,
"date_time_field"
);
assert.strictEqual(
controlPanel.el.querySelector(".o_generator_menu_operator").value,
"between"
);
assert.strictEqual(target.querySelector(".o_generator_menu_operator").value, "between");
await editConditionValue(controlPanel, 0, "02/22/2017 11:00:00", 0); // in TZ
await editConditionValue(controlPanel, 0, "02-22-2017 17:00:00", 1); // in TZ
await applyFilter(controlPanel);
await editConditionValue(target, 0, "02/22/2017 11:00:00", 0); // in TZ
await editConditionValue(target, 0, "02-22-2017 17:00:00", 1); // in TZ
await applyFilter(target);
assert.deepEqual(
getFacetTexts(controlPanel),
getFacetTexts(target),
['DateTime is between "02/22/2017 11:00:00 and 02/22/2017 17:00:00"'],
"description should be in localized format"
);
@@ -541,7 +535,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("input value parsing", async function (assert) {
assert.expect(7);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -549,40 +543,38 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await addCondition(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await addCondition(target);
await editConditionField(controlPanel, 0, "float_field");
await editConditionField(controlPanel, 1, "id");
await editConditionField(target, 0, "float_field");
await editConditionField(target, 1, "id");
const [floatInput, idInput] = controlPanel.el.querySelectorAll(
".o_generator_menu_value .o_input"
);
const [floatInput, idInput] = target.querySelectorAll(".o_generator_menu_value .o_input");
// Default values
await editConditionValue(controlPanel, 0, "0.0");
await editConditionValue(target, 0, "0.0");
assert.strictEqual(floatInput.value, "0.0");
await editConditionValue(controlPanel, 1, "0");
await editConditionValue(target, 1, "0");
assert.strictEqual(idInput.value, "0");
// Float parsing
await editConditionValue(controlPanel, 0, "4.2");
await editConditionValue(target, 0, "4.2");
assert.strictEqual(floatInput.value, "4.2");
await editConditionValue(controlPanel, 0, "DefinitelyValidFloat");
await editConditionValue(target, 0, "DefinitelyValidFloat");
// "DefinitelyValidFloat" cannot be entered in a input type number so that the input value is reset to 0
assert.strictEqual(floatInput.value, "4.2");
// Number parsing
await editConditionValue(controlPanel, 1, "4");
await editConditionValue(target, 1, "4");
assert.strictEqual(idInput.value, "4");
await editConditionValue(controlPanel, 1, "4.2");
await editConditionValue(target, 1, "4.2");
assert.strictEqual(idInput.value, "4");
await editConditionValue(controlPanel, 1, "DefinitelyValidID");
await editConditionValue(target, 1, "DefinitelyValidID");
// "DefinitelyValidID" cannot be entered in a input type number so that the input value is reset to 0
assert.strictEqual(idInput.value, "0");
});
@@ -590,7 +582,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("input value parsing with language", async function (assert) {
assert.expect(5);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -605,27 +597,27 @@ QUnit.module("Search", (hooks) => {
grouping: [3, 0],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
await editConditionField(controlPanel, 0, "float_field");
await editConditionField(target, 0, "float_field");
const [floatInput] = controlPanel.el.querySelectorAll(".o_generator_menu_value .o_input");
const [floatInput] = target.querySelectorAll(".o_generator_menu_value .o_input");
// Default values
assert.strictEqual(floatInput.value, "0,0");
// Float parsing
await editConditionValue(controlPanel, 0, "4,");
await editConditionValue(target, 0, "4,");
assert.strictEqual(floatInput.value, "4,0");
await editConditionValue(controlPanel, 0, "4,2");
await editConditionValue(target, 0, "4,2");
assert.strictEqual(floatInput.value, "4,2");
await editConditionValue(controlPanel, 0, "4,2,");
await editConditionValue(target, 0, "4,2,");
assert.strictEqual(floatInput.value, "4,2");
await editConditionValue(controlPanel, 0, "DefinitelyValidFloat");
await editConditionValue(target, 0, "DefinitelyValidFloat");
// The input here is a string, resulting in a parsing error instead of 0
assert.strictEqual(floatInput.value, "4,2");
@@ -642,34 +634,34 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
for (let i = 0; i < 4; i++) {
await addCondition(controlPanel);
await addCondition(target);
}
await editConditionField(controlPanel, 0, "date_field");
await editConditionValue(controlPanel, 0, "01/09/1997");
await editConditionField(target, 0, "date_field");
await editConditionValue(target, 0, "01/09/1997");
await editConditionField(controlPanel, 1, "boolean_field");
await editConditionOperator(controlPanel, 1, "!=");
await editConditionField(target, 1, "boolean_field");
await editConditionOperator(target, 1, "!=");
await editConditionField(controlPanel, 2, "char_field");
await editConditionValue(controlPanel, 2, "I will be deleted anyway");
await editConditionField(target, 2, "char_field");
await editConditionValue(target, 2, "I will be deleted anyway");
await editConditionField(controlPanel, 3, "float_field");
await editConditionValue(controlPanel, 3, 7.2);
await editConditionField(target, 3, "float_field");
await editConditionValue(target, 3, 7.2);
await editConditionField(controlPanel, 4, "id");
await editConditionValue(controlPanel, 4, 9);
await editConditionField(target, 4, "id");
await editConditionValue(target, 4, 9);
const thirdcondition = controlPanel.el.querySelectorAll(".o_filter_condition")[2];
const thirdcondition = target.querySelectorAll(".o_filter_condition")[2];
await click(thirdcondition, ".o_generator_menu_delete");
await applyFilter(controlPanel);
await applyFilter(target);
assert.deepEqual(getFacetTexts(controlPanel), [
assert.deepEqual(getFacetTexts(target), [
[
'A date is equal to "01/09/1997"',
"Boolean Field is No",
@@ -689,7 +681,7 @@ QUnit.module("Search", (hooks) => {
});
QUnit.test("delete button is visible", async function (assert) {
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -697,24 +689,24 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
await toggleAddCustomFilter(controlPanel);
await toggleFilterMenu(target);
await toggleAddCustomFilter(target);
assert.containsNone(
controlPanel,
target,
".o_generator_menu_delete",
"There is no delete button by default"
);
await addCondition(controlPanel);
await addCondition(target);
assert.containsN(
controlPanel,
target,
".o_generator_menu_delete",
2,
"A delete button has been added to each condition"
);
assert.containsN(
controlPanel,
target,
"i.o_generator_menu_delete.fa-trash-o",
2,
"The delete button is shown as a trash icon"
@@ -2,7 +2,7 @@
import { browser } from "@web/core/browser/browser";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { patchWithCleanup } from "../helpers/utils";
import { getFixture, patchWithCleanup } from "../helpers/utils";
import {
applyGroup,
getFacetTexts,
@@ -15,6 +15,7 @@ import {
toggleMenuItem,
} from "./helpers";
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -40,6 +41,7 @@ QUnit.module("Search", (hooks) => {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
target = getFixture();
});
QUnit.module("CustomGroupByItem");
@@ -47,7 +49,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("simple rendering", async function (assert) {
assert.expect(5);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -55,20 +57,20 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
const customGroupByItem = controlPanel.el.querySelector(".o_add_custom_group_menu");
const customGroupByItem = target.querySelector(".o_add_custom_group_menu");
assert.strictEqual(customGroupByItem.innerText.trim(), "Add Custom Group");
assert.containsOnce(customGroupByItem, "button.dropdown-toggle");
assert.containsNone(customGroupByItem, ".dropdown-menu");
await toggleAddCustomGroup(controlPanel);
await toggleAddCustomGroup(target);
assert.containsOnce(customGroupByItem, ".dropdown-menu");
assert.deepEqual(
[...controlPanel.el.querySelectorAll(".o_add_custom_group_menu select option")].map(
[...target.querySelectorAll(".o_add_custom_group_menu select option")].map(
(el) => el.innerText
),
["Birthday", "Date", "Foo"]
@@ -80,7 +82,7 @@ QUnit.module("Search", (hooks) => {
async function (assert) {
assert.expect(1);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -92,12 +94,12 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleGroupByMenu(controlPanel);
await toggleAddCustomGroup(controlPanel);
await toggleGroupByMenu(target);
await toggleAddCustomGroup(target);
assert.deepEqual(
[
...controlPanel.el.querySelectorAll(
...target.querySelectorAll(
".o_add_custom_group_menu .dropdown-menu select option"
),
].map((el) => el.innerText),
@@ -122,28 +124,28 @@ QUnit.module("Search", (hooks) => {
id: { sortable: true, string: "ID", type: "integer" },
},
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.deepEqual(controlPanel.env.searchModel.groupBy, []);
assert.containsNone(controlPanel, ".o_menu_item");
assert.containsNone(target, ".o_menu_item");
await toggleAddCustomGroup(controlPanel);
await applyGroup(controlPanel);
await toggleAddCustomGroup(target);
await applyGroup(target);
assert.deepEqual(controlPanel.env.searchModel.groupBy, ["date_field:month"]);
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Month"]);
assert.ok(isItemSelected(controlPanel, "Date"));
assert.deepEqual(getFacetTexts(target), ["Date: Month"]);
assert.ok(isItemSelected(target, "Date"));
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItem(target, "Date");
assert.ok(isOptionSelected(controlPanel, "Date", "Month"));
assert.ok(isOptionSelected(target, "Date", "Month"));
}
);
QUnit.test("click on add custom group toggle group selector", async function (assert) {
assert.expect(4);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -153,25 +155,25 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
const addCustomGroupMenu = controlPanel.el.querySelector(".o_add_custom_group_menu");
const addCustomGroupMenu = target.querySelector(".o_add_custom_group_menu");
assert.strictEqual(addCustomGroupMenu.innerText.trim(), "Add Custom Group");
await toggleAddCustomGroup(controlPanel);
await toggleAddCustomGroup(target);
// Single select node with a single option
assert.containsOnce(controlPanel, ".o_add_custom_group_menu .dropdown-menu select");
assert.containsOnce(target, ".o_add_custom_group_menu .dropdown-menu select");
assert.strictEqual(
controlPanel.el
target
.querySelector(".o_add_custom_group_menu .dropdown-menu select option")
.innerText.trim(),
"Super Date"
);
// Button apply
assert.containsOnce(controlPanel, ".o_add_custom_group_menu .dropdown-menu .btn");
assert.containsOnce(target, ".o_add_custom_group_menu .dropdown-menu .btn");
});
QUnit.test(
@@ -179,7 +181,7 @@ QUnit.module("Search", (hooks) => {
async function (assert) {
assert.expect(4);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -193,14 +195,14 @@ QUnit.module("Search", (hooks) => {
},
});
await toggleGroupByMenu(controlPanel);
await toggleAddCustomGroup(controlPanel);
await applyGroup(controlPanel);
await toggleGroupByMenu(target);
await toggleAddCustomGroup(target);
await applyGroup(target);
assert.containsOnce(controlPanel, ".o_group_by_menu .o_menu_item");
assert.containsOnce(controlPanel, ".o_add_custom_group_menu .dropdown-toggle");
assert.containsOnce(controlPanel, ".o_add_custom_group_menu .dropdown-menu");
assert.deepEqual(getFacetTexts(controlPanel), ["Candlelight"]);
assert.containsOnce(target, ".o_group_by_menu .o_menu_item");
assert.containsOnce(target, ".o_add_custom_group_menu .dropdown-toggle");
assert.containsOnce(target, ".o_add_custom_group_menu .dropdown-menu");
assert.deepEqual(getFacetTexts(target), ["Candlelight"]);
}
);
});
@@ -18,6 +18,7 @@ import {
toggleFavoriteMenu,
toggleMenuItem,
} from "./helpers";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, onWillUpdateProps, xml } = owl;
const serviceRegistry = registry.category("services");
@@ -64,7 +65,7 @@ QUnit.module("Search", (hooks) => {
favoriteMenuRegistry.remove("custom-favorite-item");
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -75,29 +76,29 @@ QUnit.module("Search", (hooks) => {
},
});
assert.containsOnce(controlPanel, "div.o_favorite_menu > button i.oi.oi-star");
assert.containsOnce(target, "div.o_favorite_menu > button i.oi.oi-star");
assert.strictEqual(
controlPanel.el
target
.querySelector("div.o_favorite_menu > button span")
.innerText.trim()
.toUpperCase(),
"FAVORITES"
);
await toggleFavoriteMenu(controlPanel);
await toggleFavoriteMenu(target);
assert.containsOnce(
controlPanel,
target,
"div.o_favorite_menu > .dropdown-menu",
"the menu should be opened"
);
assert.containsNone(controlPanel, ".dropdown-menu *", "the menu should be empty");
assert.containsNone(target, ".dropdown-menu *", "the menu should be empty");
}
);
QUnit.test("simple rendering with no favorite", async function (assert) {
assert.expect(5);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -108,23 +109,23 @@ QUnit.module("Search", (hooks) => {
},
});
assert.containsOnce(controlPanel, "div.o_favorite_menu > button i.oi.oi-star");
assert.containsOnce(target, "div.o_favorite_menu > button i.oi.oi-star");
assert.strictEqual(
controlPanel.el
target
.querySelector("div.o_favorite_menu > button span")
.innerText.trim()
.toUpperCase(),
"FAVORITES"
);
await toggleFavoriteMenu(controlPanel);
await toggleFavoriteMenu(target);
assert.containsOnce(
controlPanel,
target,
"div.o_favorite_menu > .dropdown-menu",
"the menu should be opened"
);
assert.containsNone(controlPanel, ".dropdown-menu .dropdown-divider");
assert.containsOnce(controlPanel, ".dropdown-menu .o_add_favorite");
assert.containsNone(target, ".dropdown-menu .dropdown-divider");
assert.containsOnce(target, ".dropdown-menu .o_add_favorite");
});
QUnit.test(
@@ -221,11 +222,11 @@ QUnit.module("Search", (hooks) => {
activateFavorite: false,
});
await toggleFavoriteMenu(controlPanel);
await toggleFavoriteMenu(target);
assert.notOk(isItemSelected(controlPanel, "My favorite"));
assert.notOk(isItemSelected(target, "My favorite"));
assert.deepEqual(getDomain(controlPanel), []);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
}
);
@@ -288,15 +289,15 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(groupBy, ["date_field:month"]);
assert.deepEqual(comparison, null);
assert.deepEqual(getFacetTexts(controlPanel), [
assert.deepEqual(getFacetTexts(target), [
"Foo\na",
"Date Field Filter: 2019",
"Date Field Groupby: Month",
]);
// activate a comparison
await toggleComparisonMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date Field Filter: Previous Period");
await toggleComparisonMenu(target);
await toggleMenuItem(target, "Date Field Filter: Previous Period");
domain = controlPanel.env.searchModel.domain;
groupBy = controlPanel.env.searchModel.groupBy;
@@ -323,8 +324,8 @@ QUnit.module("Search", (hooks) => {
});
// activate the unique existing favorite
await toggleFavoriteMenu(controlPanel);
await toggleMenuItem(controlPanel, 0);
await toggleFavoriteMenu(target);
await toggleMenuItem(target, 0);
domain = controlPanel.env.searchModel.domain;
groupBy = controlPanel.env.searchModel.groupBy;
@@ -336,7 +337,7 @@ QUnit.module("Search", (hooks) => {
"favorite comparison content": "bla bla...",
});
assert.deepEqual(getFacetTexts(controlPanel), ["My favorite"]);
assert.deepEqual(getFacetTexts(target), ["My favorite"]);
}
);
@@ -1,6 +1,6 @@
/** @odoo-module **/
import { patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
import { getFixture, patchDate, patchWithCleanup } from "@web/../tests/helpers/utils";
import { browser } from "@web/core/browser/browser";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import {
@@ -22,6 +22,7 @@ function getContext(controlPanel) {
return controlPanel.env.searchModel.context;
}
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -50,6 +51,7 @@ QUnit.module("Search", (hooks) => {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
target = getFixture();
});
QUnit.module("FilterMenu");
@@ -57,23 +59,23 @@ QUnit.module("Search", (hooks) => {
QUnit.test("simple rendering with no filter", async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
searchMenuTypes: ["filter"],
});
await toggleFilterMenu(controlPanel);
assert.containsNone(controlPanel, ".o_menu_item");
assert.containsNone(controlPanel, ".dropdown-divider");
assert.containsOnce(controlPanel, ".o_add_custom_filter_menu");
await toggleFilterMenu(target);
assert.containsNone(target, ".o_menu_item");
assert.containsNone(target, ".dropdown-divider");
assert.containsOnce(target, ".o_add_custom_filter_menu");
});
QUnit.test("simple rendering with a single filter", async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -86,10 +88,10 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleFilterMenu(controlPanel);
assert.containsOnce(controlPanel, ".o_menu_item");
assert.containsOnce(controlPanel, ".dropdown-divider");
assert.containsOnce(controlPanel, ".o_add_custom_filter_menu");
await toggleFilterMenu(target);
assert.containsOnce(target, ".o_menu_item");
assert.containsOnce(target, ".dropdown-divider");
assert.containsOnce(target, ".o_add_custom_filter_menu");
});
QUnit.test('toggle a "simple" filter in filter menu works', async function (assert) {
@@ -108,25 +110,25 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleFilterMenu(controlPanel);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.notOk(isItemSelected(controlPanel, "Foo"));
await toggleFilterMenu(target);
assert.deepEqual(getFacetTexts(target), []);
assert.notOk(isItemSelected(target, "Foo"));
assert.deepEqual(getDomain(controlPanel), []);
await toggleMenuItem(controlPanel, "Foo");
await toggleMenuItem(target, "Foo");
assert.deepEqual(getFacetTexts(controlPanel), ["Foo"]);
assert.deepEqual(getFacetTexts(target), ["Foo"]);
assert.containsOnce(
controlPanel.el.querySelector(".o_searchview .o_searchview_facet"),
target.querySelector(".o_searchview .o_searchview_facet"),
"span.oi.oi-filter.o_searchview_facet_label"
);
assert.ok(isItemSelected(controlPanel, "Foo"));
assert.ok(isItemSelected(target, "Foo"));
assert.deepEqual(getDomain(controlPanel), [["foo", "=", "qsdf"]]);
await toggleMenuItem(controlPanel, "Foo");
await toggleMenuItem(target, "Foo");
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.notOk(isItemSelected(controlPanel, "Foo"));
assert.deepEqual(getFacetTexts(target), []);
assert.notOk(isItemSelected(target, "Foo"));
assert.deepEqual(getDomain(controlPanel), []);
});
@@ -149,10 +151,10 @@ QUnit.module("Search", (hooks) => {
context: { search_default_date_field: 1 },
});
await toggleFilterMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date");
await toggleFilterMenu(target);
await toggleMenuItem(target, "Date");
const optionEls = controlPanel.el.querySelectorAll(".dropdown .o_item_option");
const optionEls = target.querySelectorAll(".dropdown .o_item_option");
// default filter should be activated with the global default period 'this_month'
assert.deepEqual(getDomain(controlPanel), [
@@ -160,8 +162,8 @@ QUnit.module("Search", (hooks) => {
["date_field", ">=", "2017-03-01"],
["date_field", "<=", "2017-03-31"],
]);
assert.ok(isItemSelected(controlPanel, "Date"));
assert.ok(isOptionSelected(controlPanel, "Date", "March"));
assert.ok(isItemSelected(target, "Date"));
assert.ok(isOptionSelected(target, "Date", "March"));
// check option descriptions
const optionDescriptions = [...optionEls].map((e) => e.innerText.trim());
@@ -342,16 +344,16 @@ QUnit.module("Search", (hooks) => {
},
];
for (const s of steps) {
await toggleMenuItemOption(controlPanel, "Date", s.toggledOption);
await toggleMenuItemOption(target, "Date", s.toggledOption);
assert.deepEqual(getDomain(controlPanel), s.domain);
if (s.resultingFacet) {
assert.deepEqual(getFacetTexts(controlPanel), [s.resultingFacet]);
assert.deepEqual(getFacetTexts(target), [s.resultingFacet]);
} else {
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
}
s.selectedoptions.forEach((option) => {
assert.ok(
isOptionSelected(controlPanel, "Date", option),
isOptionSelected(target, "Date", option),
`at step ${steps.indexOf(s) + 1}, ${option} should be selected`
);
});
@@ -385,14 +387,14 @@ QUnit.module("Search", (hooks) => {
["date_field", "<=", "2016-12-31"],
]);
assert.deepEqual(getFacetTexts(controlPanel), ["Date: December 2016"]);
assert.deepEqual(getFacetTexts(target), ["Date: December 2016"]);
await toggleFilterMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date");
await toggleFilterMenu(target);
await toggleMenuItem(target, "Date");
assert.ok(isItemSelected(controlPanel, "Date"));
assert.ok(isOptionSelected(controlPanel, "Date", "December"));
assert.ok(isOptionSelected(controlPanel, "Date", "2016"));
assert.ok(isItemSelected(target, "Date"));
assert.ok(isOptionSelected(target, "Date", "December"));
assert.ok(isOptionSelected(target, "Date", "2016"));
}
);
@@ -452,7 +454,7 @@ QUnit.module("Search", (hooks) => {
patchDate(2019, 6, 31, 13, 43, 0);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -466,7 +468,7 @@ QUnit.module("Search", (hooks) => {
context: { search_default_date_field: true },
});
assert.deepEqual(getFacetTexts(controlPanel), ["Date: June 2019"]);
assert.deepEqual(getFacetTexts(target), ["Date: June 2019"]);
});
QUnit.test("filter domains are correcly combined by OR and AND", async function (assert) {
@@ -501,7 +503,7 @@ QUnit.module("Search", (hooks) => {
["foo", "=", "f2_g2"],
]);
assert.deepEqual(getFacetTexts(controlPanel), [
assert.deepEqual(getFacetTexts(target), [
"Filter Group 1",
"Filter 1 Group 2orFilter 2 GROUP 2",
]);
@@ -510,7 +512,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("arch order of groups of filters preserved", async function (assert) {
assert.expect(12);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -543,10 +545,10 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleFilterMenu(controlPanel);
assert.containsN(controlPanel, ".o_filter_menu .o_menu_item", 11);
await toggleFilterMenu(target);
assert.containsN(target, ".o_filter_menu .o_menu_item", 11);
const menuItemEls = controlPanel.el.querySelectorAll(".o_filter_menu .o_menu_item");
const menuItemEls = target.querySelectorAll(".o_filter_menu .o_menu_item");
[...menuItemEls].forEach((e, index) => {
assert.strictEqual(e.innerText.trim(), String(index + 1));
});
@@ -2,7 +2,7 @@
import { browser } from "@web/core/browser/browser";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { patchWithCleanup } from "../helpers/utils";
import { getFixture, patchWithCleanup } from "../helpers/utils";
import {
getFacetTexts,
isItemSelected,
@@ -15,6 +15,7 @@ import {
toggleMenuItemOption,
} from "./helpers";
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -40,6 +41,7 @@ QUnit.module("Search", (hooks) => {
setTimeout: (fn) => fn(),
clearTimeout: () => {},
});
target = getFixture();
});
QUnit.module("GroupByMenu");
@@ -49,7 +51,7 @@ QUnit.module("Search", (hooks) => {
async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -58,18 +60,18 @@ QUnit.module("Search", (hooks) => {
searchViewFields: {},
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.containsNone(controlPanel, ".o_menu_item");
assert.containsNone(controlPanel, ".dropdown-divider");
assert.containsNone(controlPanel, ".o_add_custom_group_menu");
assert.containsNone(target, ".o_menu_item");
assert.containsNone(target, ".dropdown-divider");
assert.containsNone(target, ".o_add_custom_group_menu");
}
);
QUnit.test("simple rendering with no groupby", async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -77,17 +79,17 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.containsNone(controlPanel, ".o_menu_item");
assert.containsNone(controlPanel, ".dropdown-divider");
assert.containsOnce(controlPanel, ".o_add_custom_group_menu");
assert.containsNone(target, ".o_menu_item");
assert.containsNone(target, ".dropdown-divider");
assert.containsOnce(target, ".o_add_custom_group_menu");
});
QUnit.test("simple rendering with a single groupby", async function (assert) {
assert.expect(4);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -100,12 +102,12 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.containsOnce(controlPanel, ".o_menu_item");
assert.strictEqual(controlPanel.el.querySelector(".o_menu_item").innerText.trim(), "Foo");
assert.containsOnce(controlPanel, ".dropdown-divider");
assert.containsOnce(controlPanel, ".o_add_custom_group_menu");
assert.containsOnce(target, ".o_menu_item");
assert.strictEqual(target.querySelector(".o_menu_item").innerText.trim(), "Foo");
assert.containsOnce(target, ".dropdown-divider");
assert.containsOnce(target, ".o_add_custom_group_menu");
});
QUnit.test('toggle a "simple" groupby in groupby menu works', async function (assert) {
@@ -124,33 +126,33 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.deepEqual(controlPanel.env.searchModel.groupBy, []);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.notOk(isItemSelected(controlPanel, "Foo"));
assert.deepEqual(getFacetTexts(target), []);
assert.notOk(isItemSelected(target, "Foo"));
await toggleMenuItem(controlPanel, "Foo");
await toggleMenuItem(target, "Foo");
assert.deepEqual(controlPanel.env.searchModel.groupBy, ["foo"]);
assert.deepEqual(getFacetTexts(controlPanel), ["Foo"]);
assert.deepEqual(getFacetTexts(target), ["Foo"]);
assert.containsOnce(
controlPanel.el.querySelector(".o_searchview .o_searchview_facet"),
target.querySelector(".o_searchview .o_searchview_facet"),
"span.oi.oi-layers.o_searchview_facet_label"
);
assert.ok(isItemSelected(controlPanel, "Foo"));
assert.ok(isItemSelected(target, "Foo"));
await toggleMenuItem(controlPanel, "Foo");
await toggleMenuItem(target, "Foo");
assert.deepEqual(controlPanel.env.searchModel.groupBy, []);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.notOk(isItemSelected(controlPanel, "Foo"));
assert.deepEqual(getFacetTexts(target), []);
assert.notOk(isItemSelected(target, "Foo"));
});
QUnit.test('toggle a "simple" groupby quickly does not crash', async function (assert) {
assert.expect(1);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -163,10 +165,10 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
toggleMenuItem(controlPanel, "Foo");
toggleMenuItem(controlPanel, "Foo");
toggleMenuItem(target, "Foo");
toggleMenuItem(target, "Foo");
assert.ok(true);
});
@@ -190,20 +192,20 @@ QUnit.module("Search", (hooks) => {
context: { search_default_group_by_foo: 1 },
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.deepEqual(getFacetTexts(controlPanel), ["Foo"]);
assert.deepEqual(getFacetTexts(target), ["Foo"]);
assert.deepEqual(controlPanel.env.searchModel.groupBy, ["foo"]);
assert.ok(isItemSelected(controlPanel, "Foo"));
assert.ok(isItemSelected(target, "Foo"));
await removeFacet(controlPanel, "Foo");
await removeFacet(target, "Foo");
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
assert.deepEqual(controlPanel.env.searchModel.groupBy, []);
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.notOk(isItemSelected(controlPanel, "Foo"));
assert.notOk(isItemSelected(target, "Foo"));
}
);
@@ -224,16 +226,16 @@ QUnit.module("Search", (hooks) => {
context: { search_default_date: 1 },
});
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
assert.deepEqual(controlPanel.env.searchModel.groupBy, ["date_field:week"]);
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItem(target, "Date");
assert.ok(isOptionSelected(controlPanel, "Date", "Week"));
assert.ok(isOptionSelected(target, "Date", "Week"));
assert.deepEqual(
[...controlPanel.el.querySelectorAll(".o_item_option")].map((el) => el.innerText),
[...target.querySelectorAll(".o_item_option")].map((el) => el.innerText),
["Year", "Quarter", "Month", "Week", "Day"]
);
@@ -265,12 +267,12 @@ QUnit.module("Search", (hooks) => {
{ description: "Year", facetTexts: [], selectedoptions: [], groupBy: [] },
];
for (const s of steps) {
await toggleMenuItemOption(controlPanel, "Date", s.description);
await toggleMenuItemOption(target, "Date", s.description);
assert.deepEqual(controlPanel.env.searchModel.groupBy, s.groupBy);
assert.deepEqual(getFacetTexts(controlPanel), s.facetTexts);
assert.deepEqual(getFacetTexts(target), s.facetTexts);
s.selectedoptions.forEach((description) => {
assert.ok(isOptionSelected(controlPanel, "Date", description));
assert.ok(isOptionSelected(target, "Date", description));
});
}
});
@@ -278,7 +280,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("interval options are correctly grouped and ordered", async function (assert) {
assert.expect(8);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -294,53 +296,53 @@ QUnit.module("Search", (hooks) => {
context: { search_default_bar: 1 },
});
assert.deepEqual(getFacetTexts(controlPanel), ["Bar"]);
assert.deepEqual(getFacetTexts(target), ["Bar"]);
// open menu 'Group By'
await toggleGroupByMenu(controlPanel);
await toggleGroupByMenu(target);
// Open the groupby 'Date'
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItem(target, "Date");
// select option 'week'
await toggleMenuItemOption(controlPanel, "Date", "Week");
await toggleMenuItemOption(target, "Date", "Week");
assert.deepEqual(getFacetTexts(controlPanel), ["Bar>Date: Week"]);
assert.deepEqual(getFacetTexts(target), ["Bar>Date: Week"]);
// select option 'day'
await toggleMenuItemOption(controlPanel, "Date", "Day");
await toggleMenuItemOption(target, "Date", "Day");
assert.deepEqual(getFacetTexts(controlPanel), ["Bar>Date: Week>Date: Day"]);
assert.deepEqual(getFacetTexts(target), ["Bar>Date: Week>Date: Day"]);
// select option 'year'
await toggleMenuItemOption(controlPanel, "Date", "Year");
await toggleMenuItemOption(target, "Date", "Year");
assert.deepEqual(getFacetTexts(controlPanel), ["Bar>Date: Year>Date: Week>Date: Day"]);
assert.deepEqual(getFacetTexts(target), ["Bar>Date: Year>Date: Week>Date: Day"]);
// select 'Foo'
await toggleMenuItem(controlPanel, "Foo");
await toggleMenuItem(target, "Foo");
assert.deepEqual(getFacetTexts(controlPanel), ["Bar>Date: Year>Date: Week>Date: Day>Foo"]);
assert.deepEqual(getFacetTexts(target), ["Bar>Date: Year>Date: Week>Date: Day>Foo"]);
// select option 'quarter'
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItemOption(controlPanel, "Date", "Quarter");
await toggleMenuItem(target, "Date");
await toggleMenuItemOption(target, "Date", "Quarter");
assert.deepEqual(getFacetTexts(controlPanel), [
assert.deepEqual(getFacetTexts(target), [
"Bar>Date: Year>Date: Quarter>Date: Week>Date: Day>Foo",
]);
// unselect 'Bar'
await toggleMenuItem(controlPanel, "Bar");
await toggleMenuItem(target, "Bar");
assert.deepEqual(getFacetTexts(controlPanel), [
assert.deepEqual(getFacetTexts(target), [
"Date: Year>Date: Quarter>Date: Week>Date: Day>Foo",
]);
// unselect option 'week'
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItemOption(controlPanel, "Date", "Week");
await toggleMenuItem(target, "Date");
await toggleMenuItemOption(target, "Date", "Week");
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Year>Date: Quarter>Date: Day>Foo"]);
assert.deepEqual(getFacetTexts(target), ["Date: Year>Date: Quarter>Date: Day>Foo"]);
});
QUnit.test("default groupbys can be ordered", async function (assert) {
@@ -366,13 +368,13 @@ QUnit.module("Search", (hooks) => {
"date_field:week",
"birthday:month",
]);
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Week>Birthday: Month"]);
assert.deepEqual(getFacetTexts(target), ["Date: Week>Birthday: Month"]);
});
QUnit.test("a separator in groupbys does not cause problems", async function (assert) {
assert.expect(23);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: ControlPanel,
@@ -387,51 +389,51 @@ QUnit.module("Search", (hooks) => {
`,
});
await toggleGroupByMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItemOption(controlPanel, "Date", "Day");
await toggleGroupByMenu(target);
await toggleMenuItem(target, "Date");
await toggleMenuItemOption(target, "Date", "Day");
assert.ok(isItemSelected(controlPanel, "Date"));
assert.notOk(isItemSelected(controlPanel, "Bar"));
assert.ok(isOptionSelected(controlPanel, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Day"]);
assert.ok(isItemSelected(target, "Date"));
assert.notOk(isItemSelected(target, "Bar"));
assert.ok(isOptionSelected(target, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(target), ["Date: Day"]);
await toggleMenuItem(controlPanel, "Bar");
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItem(target, "Bar");
await toggleMenuItem(target, "Date");
assert.ok(isItemSelected(controlPanel, "Date"));
assert.ok(isItemSelected(controlPanel, "Bar"));
assert.ok(isOptionSelected(controlPanel, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Day>Bar"]);
assert.ok(isItemSelected(target, "Date"));
assert.ok(isItemSelected(target, "Bar"));
assert.ok(isOptionSelected(target, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(target), ["Date: Day>Bar"]);
await toggleMenuItemOption(controlPanel, "Date", "Quarter");
await toggleMenuItemOption(target, "Date", "Quarter");
assert.ok(isItemSelected(controlPanel, "Date"));
assert.ok(isItemSelected(controlPanel, "Bar"));
assert.ok(isOptionSelected(controlPanel, "Date", "Quarter"), "selected");
assert.ok(isOptionSelected(controlPanel, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Quarter>Date: Day>Bar"]);
assert.ok(isItemSelected(target, "Date"));
assert.ok(isItemSelected(target, "Bar"));
assert.ok(isOptionSelected(target, "Date", "Quarter"), "selected");
assert.ok(isOptionSelected(target, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(target), ["Date: Quarter>Date: Day>Bar"]);
await toggleMenuItem(controlPanel, "Bar");
await toggleMenuItem(controlPanel, "Date");
await toggleMenuItem(target, "Bar");
await toggleMenuItem(target, "Date");
assert.ok(isItemSelected(controlPanel, "Date"));
assert.notOk(isItemSelected(controlPanel, "Bar"));
assert.ok(isOptionSelected(controlPanel, "Date", "Quarter"), "selected");
assert.ok(isOptionSelected(controlPanel, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(controlPanel), ["Date: Quarter>Date: Day"]);
assert.ok(isItemSelected(target, "Date"));
assert.notOk(isItemSelected(target, "Bar"));
assert.ok(isOptionSelected(target, "Date", "Quarter"), "selected");
assert.ok(isOptionSelected(target, "Date", "Day"), "selected");
assert.deepEqual(getFacetTexts(target), ["Date: Quarter>Date: Day"]);
await removeFacet(controlPanel);
await removeFacet(target);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
await toggleGroupByMenu(controlPanel);
await toggleMenuItem(controlPanel, "Date");
await toggleGroupByMenu(target);
await toggleMenuItem(target, "Date");
assert.notOk(isItemSelected(controlPanel, "Date"));
assert.notOk(isItemSelected(controlPanel, "Bar"));
assert.notOk(isOptionSelected(controlPanel, "Date", "Quarter"), "selected");
assert.notOk(isOptionSelected(controlPanel, "Date", "Day"), "selected");
assert.notOk(isItemSelected(target, "Date"));
assert.notOk(isItemSelected(target, "Bar"));
assert.notOk(isOptionSelected(target, "Date", "Quarter"), "selected");
assert.notOk(isOptionSelected(target, "Date", "Day"), "selected");
});
QUnit.test("falsy search default groupbys are not activated", async function (assert) {
@@ -453,6 +455,6 @@ QUnit.module("Search", (hooks) => {
});
assert.deepEqual(controlPanel.env.searchModel.groupBy, []);
assert.deepEqual(getFacetTexts(controlPanel), []);
assert.deepEqual(getFacetTexts(target), []);
});
});
@@ -2,11 +2,12 @@
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { usePager } from "@web/search/pager_hook";
import { click, nextTick } from "../helpers/utils";
import { click, getFixture, nextTick } from "../helpers/utils";
import { makeWithSearch, setupControlPanelServiceRegistry } from "./helpers";
const { Component, useState, xml } = owl;
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -21,6 +22,7 @@ QUnit.module("Search", (hooks) => {
},
};
setupControlPanelServiceRegistry();
target = getFixture();
});
QUnit.module("usePager");
@@ -39,20 +41,20 @@ QUnit.module("Search", (hooks) => {
TestComponent.components = { ControlPanel };
TestComponent.template = xml`<ControlPanel />`;
const comp = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "foo",
Component: TestComponent,
searchMenuTypes: [],
});
assert.containsOnce(comp, ".o_pager");
assert.containsOnce(target, ".o_pager");
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"1-10"
);
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
target.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
"50"
);
});
@@ -81,13 +83,13 @@ QUnit.module("Search", (hooks) => {
searchMenuTypes: [],
});
assert.containsOnce(comp, ".o_pager");
assert.containsOnce(target, ".o_pager");
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"1-10"
);
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
target.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
"50"
);
assert.deepEqual(comp.state, {
@@ -95,15 +97,15 @@ QUnit.module("Search", (hooks) => {
limit: 10,
});
await click(comp.el.querySelector(`.o_pager button.o_pager_next`));
await click(target.querySelector(`.o_pager button.o_pager_next`));
assert.containsOnce(comp, ".o_pager");
assert.containsOnce(target, ".o_pager");
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"11-20"
);
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
target.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
"50"
);
assert.deepEqual(comp.state, {
@@ -114,13 +116,13 @@ QUnit.module("Search", (hooks) => {
comp.state.offset = 20;
await nextTick();
assert.containsOnce(comp, ".o_pager");
assert.containsOnce(target, ".o_pager");
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
target.querySelector(`.o_pager_counter .o_pager_value`).textContent.trim(),
"21-30"
);
assert.strictEqual(
comp.el.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
target.querySelector(`.o_pager_counter span.o_pager_limit`).textContent.trim(),
"50"
);
assert.deepEqual(comp.state, {
+114 -120
View File
@@ -2,7 +2,14 @@
import { registerCleanup } from "@web/../tests/helpers/cleanup";
import { ControlPanel } from "@web/search/control_panel/control_panel";
import { click, makeDeferred, nextTick, patchWithCleanup, triggerEvent } from "../helpers/utils";
import {
click,
getFixture,
makeDeferred,
nextTick,
patchWithCleanup,
triggerEvent,
} from "../helpers/utils";
import {
editSearch,
getFacetTexts,
@@ -18,6 +25,7 @@ function getDomain(controlPanel) {
const { onWillUpdateProps } = owl;
let target;
let serverData;
QUnit.module("Search", (hooks) => {
hooks.beforeEach(async () => {
@@ -105,6 +113,7 @@ QUnit.module("Search", (hooks) => {
},
};
setupControlPanelServiceRegistry();
target = getFixture();
});
QUnit.module("SearchBar");
@@ -112,7 +121,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("basic rendering", async function (assert) {
assert.expect(1);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -122,7 +131,7 @@ QUnit.module("Search", (hooks) => {
assert.strictEqual(
document.activeElement,
controlPanel.el.querySelector(".o_searchview input"),
target.querySelector(".o_searchview input"),
"searchview input should be focused"
);
});
@@ -130,7 +139,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("navigation with facets", async function (assert) {
assert.expect(4);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -140,28 +149,22 @@ QUnit.module("Search", (hooks) => {
});
assert.containsOnce(
controlPanel,
target,
".o_searchview .o_searchview_facet",
"there should be one facet"
);
assert.strictEqual(
document.activeElement,
controlPanel.el.querySelector(".o_searchview input")
);
assert.strictEqual(document.activeElement, target.querySelector(".o_searchview input"));
// press left to focus the facet
await triggerEvent(document.activeElement, null, "keydown", { key: "ArrowLeft" });
assert.strictEqual(
document.activeElement,
controlPanel.el.querySelector(".o_searchview .o_searchview_facet")
target.querySelector(".o_searchview .o_searchview_facet")
);
// press right to focus the input
await triggerEvent(document.activeElement, null, "keydown", { key: "ArrowRight" });
assert.strictEqual(
document.activeElement,
controlPanel.el.querySelector(".o_searchview input")
);
assert.strictEqual(document.activeElement, target.querySelector(".o_searchview input"));
});
QUnit.test("search date and datetime fields. Support of timezones", async function (assert) {
@@ -182,13 +185,13 @@ QUnit.module("Search", (hooks) => {
});
// Date case
await editSearch(controlPanel, "07/15/1983");
let searchInput = controlPanel.el.querySelector(".o_searchview input");
await editSearch(target, "07/15/1983");
let searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "Enter" }); // select
assert.deepEqual(
getFacetTexts(controlPanel).map((str) => str.replace(/\s+/, " ")),
getFacetTexts(target).map((str) => str.replace(/\s+/, " ")),
["Birthday 07/15/1983"],
"The format of the date in the facet should be in locale"
);
@@ -196,17 +199,17 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getDomain(controlPanel), [["birthday", "=", "1983-07-15"]]);
// Close Facet
await click(controlPanel.el.querySelector(".o_searchview_facet .o_facet_remove"));
await click(target.querySelector(".o_searchview_facet .o_facet_remove"));
// DateTime case
await editSearch(controlPanel, "07/15/1983 00:00:00");
searchInput = controlPanel.el.querySelector(".o_searchview input");
await editSearch(target, "07/15/1983 00:00:00");
searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "Enter" }); // select
assert.deepEqual(
getFacetTexts(controlPanel).map((str) => str.replace(/\s+/, " ")),
getFacetTexts(target).map((str) => str.replace(/\s+/, " ")),
["Birth DateTime\n07/15/1983 00:00:00"],
"The format of the datetime in the facet should be in locale"
);
@@ -217,7 +220,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("autocomplete menu clickout interactions", async function (assert) {
assert.expect(9);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -234,29 +237,29 @@ QUnit.module("Search", (hooks) => {
`,
});
const input = controlPanel.el.querySelector(".o_searchview input");
const input = target.querySelector(".o_searchview input");
assert.containsNone(controlPanel, ".o_searchview_autocomplete");
assert.containsNone(target, ".o_searchview_autocomplete");
await editSearch(controlPanel, "Hello there");
await editSearch(target, "Hello there");
assert.strictEqual(input.value, "Hello there", "input value should be updated");
assert.containsOnce(controlPanel, ".o_searchview_autocomplete");
assert.containsOnce(target, ".o_searchview_autocomplete");
await triggerEvent(input, null, "keydown", { key: "Escape" });
assert.strictEqual(input.value, "", "input value should be empty");
assert.containsNone(controlPanel, ".o_searchview_autocomplete");
assert.containsNone(target, ".o_searchview_autocomplete");
await editSearch(controlPanel, "General Kenobi");
await editSearch(target, "General Kenobi");
assert.strictEqual(input.value, "General Kenobi", "input value should be updated");
assert.containsOnce(controlPanel, ".o_searchview_autocomplete");
assert.containsOnce(target, ".o_searchview_autocomplete");
await click(document.body);
assert.strictEqual(input.value, "", "input value should be empty");
assert.containsNone(controlPanel, ".o_searchview_autocomplete");
assert.containsNone(target, ".o_searchview_autocomplete");
});
QUnit.test("select an autocomplete field", async function (assert) {
@@ -270,20 +273,18 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
await editSearch(controlPanel, "a");
await editSearch(target, "a");
assert.containsN(
controlPanel,
target,
".o_searchview_autocomplete li",
2,
"there should be 2 result for 'a' in search bar autocomplete"
);
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "Enter" });
assert.strictEqual(
controlPanel.el
.querySelector(".o_searchview_input_container .o_facet_values")
.innerText.trim(),
target.querySelector(".o_searchview_input_container .o_facet_values").innerText.trim(),
"a",
"There should be a field facet with label 'a'"
);
@@ -313,15 +314,15 @@ QUnit.module("Search", (hooks) => {
});
// 'r' key to filter on bar "First Record"
await editSearch(controlPanel, "record");
const searchInput = controlPanel.el.querySelector(".o_searchview input");
await editSearch(target, "record");
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowRight" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "Enter" });
assert.deepEqual(
getFacetTexts(controlPanel).map((str) => str.replace(/\s+/, "")),
getFacetTexts(target).map((str) => str.replace(/\s+/, "")),
["BarFirst record"]
);
@@ -331,7 +332,7 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(controlPanel.env.searchModel.context.bar, [1]);
// 'r' key to filter on bar "Second Record"
await editSearch(controlPanel, "record");
await editSearch(target, "record");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowRight" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
@@ -339,7 +340,7 @@ QUnit.module("Search", (hooks) => {
await triggerEvent(searchInput, null, "keydown", { key: "Enter" });
assert.deepEqual(
getFacetTexts(controlPanel).map((str) => str.replace(/\s+/, "")),
getFacetTexts(target).map((str) => str.replace(/\s+/, "")),
["BarFirst recordorSecond record"]
);
@@ -362,7 +363,7 @@ QUnit.module("Search", (hooks) => {
},
});
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -370,17 +371,17 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "Enter" });
assert.containsNone(controlPanel, ".o_searchview_facet_label");
assert.containsNone(target, ".o_searchview_facet_label");
assert.strictEqual(updateCount, 1, "should have been updated once");
});
QUnit.test("selecting (no result) triggers a search bar rendering", async function (assert) {
assert.expect(3);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -393,27 +394,25 @@ QUnit.module("Search", (hooks) => {
`,
});
await editSearch(controlPanel, "hello there");
await editSearch(target, "hello there");
// 'a' key to filter nothing on bar
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowRight" });
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
assert.strictEqual(
controlPanel.el
.querySelector(".o_searchview_autocomplete .o_selection_focus")
.innerText.trim(),
target.querySelector(".o_searchview_autocomplete .o_selection_focus").innerText.trim(),
"(no result)",
"there should be no result for 'a' in bar"
);
await triggerEvent(searchInput, null, "keydown", { key: "Enter" });
assert.containsNone(controlPanel, ".o_searchview_facet_label");
assert.containsNone(target, ".o_searchview_facet_label");
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview input").value,
target.querySelector(".o_searchview input").value,
"",
"the search input should be re-rendered"
);
@@ -429,7 +428,7 @@ QUnit.module("Search", (hooks) => {
// not handled but are triggered to ensure they do not interfere.
const TEST = "TEST";
const テスト = "テスト";
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -437,7 +436,7 @@ QUnit.module("Search", (hooks) => {
searchViewId: false,
});
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
// Simulate typing "TEST" on search view.
for (let i = 0; i < TEST.length; i++) {
@@ -462,12 +461,12 @@ QUnit.module("Search", (hooks) => {
});
}
assert.containsOnce(
controlPanel.el,
target,
".o_searchview_autocomplete",
"should display autocomplete dropdown menu on typing something in search view"
);
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview_autocomplete li").innerText.trim(),
target.querySelector(".o_searchview_autocomplete li").innerText.trim(),
"Search Foo for: TEST",
`1st filter suggestion should be based on typed word "TEST"`
);
@@ -492,7 +491,7 @@ QUnit.module("Search", (hooks) => {
});
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview_autocomplete li").innerText.trim(),
target.querySelector(".o_searchview_autocomplete li").innerText.trim(),
"Search Foo for: テスト",
`1st filter suggestion should be updated with soft-selection typed word "テスト"`
);
@@ -520,7 +519,7 @@ QUnit.module("Search", (hooks) => {
await triggerEvent(searchInput, null, "compositionend");
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview_autocomplete li").innerText.trim(),
target.querySelector(".o_searchview_autocomplete li").innerText.trim(),
"Search Foo for: TEST",
`1st filter suggestion should finally be updated with click selection on word "TEST" from IME`
);
@@ -530,7 +529,7 @@ QUnit.module("Search", (hooks) => {
QUnit.test("open search view autocomplete on paste value using mouse", async function (assert) {
assert.expect(1);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -539,11 +538,11 @@ QUnit.module("Search", (hooks) => {
});
// Simulate paste text through the mouse.
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
searchInput.value = "ABC";
await triggerEvent(searchInput, null, "input", { inputType: "insertFromPaste" });
assert.containsOnce(
controlPanel,
target,
".o_searchview_autocomplete",
"should display autocomplete dropdown menu on paste in search view"
);
@@ -570,20 +569,18 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "rec");
await click(controlPanel.el.querySelector(".o_searchview_autocomplete li:last-child"));
await editSearch(target, "rec");
await click(target.querySelector(".o_searchview_autocomplete li:last-child"));
assert.deepEqual(getDomain(controlPanel), [["bar", "child_of", "rec"]]);
await removeFacet(controlPanel);
await removeFacet(target);
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "rec");
await click(controlPanel.el.querySelector(".o_expand"));
await click(
controlPanel.el.querySelector(".o_searchview_autocomplete li.o_menu_item.o_indent")
);
await editSearch(target, "rec");
await click(target.querySelector(".o_expand"));
await click(target.querySelector(".o_searchview_autocomplete li.o_menu_item.o_indent"));
assert.deepEqual(getDomain(controlPanel), [["bar", "child_of", 1]]);
});
@@ -601,17 +598,14 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "null");
await editSearch(target, "null");
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview_autocomplete .o_selection_focus")
.innerText,
target.querySelector(".o_searchview_autocomplete .o_selection_focus").innerText,
"Search Foo for: null"
);
await click(
controlPanel.el.querySelector(".o_searchview_autocomplete li.o_selection_focus a")
);
await click(target.querySelector(".o_searchview_autocomplete li.o_selection_focus a"));
assert.deepEqual(getDomain(controlPanel), [["foo", "ilike", "null"]]);
});
@@ -634,33 +628,33 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "y");
await editSearch(target, "y");
assert.containsN(controlPanel, ".o_searchview_autocomplete li", 1);
assert.containsN(target, ".o_searchview_autocomplete li", 1);
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview_autocomplete li:last-child").innerText,
target.querySelector(".o_searchview_autocomplete li:last-child").innerText,
"Search Bool for: Yes"
);
// select "Yes"
await click(controlPanel.el.querySelector(".o_searchview_autocomplete li:last-child"));
await click(target.querySelector(".o_searchview_autocomplete li:last-child"));
assert.deepEqual(getDomain(controlPanel), [["bool", "=", true]]);
await removeFacet(controlPanel);
await removeFacet(target);
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "No");
await editSearch(target, "No");
assert.containsN(controlPanel, ".o_searchview_autocomplete li", 1);
assert.containsN(target, ".o_searchview_autocomplete li", 1);
assert.strictEqual(
controlPanel.el.querySelector(".o_searchview_autocomplete li:last-child").innerText,
target.querySelector(".o_searchview_autocomplete li:last-child").innerText,
"Search Bool for: No"
);
// select "No"
await click(controlPanel.el.querySelector(".o_searchview_autocomplete li:last-child"));
await click(target.querySelector(".o_searchview_autocomplete li:last-child"));
assert.deepEqual(getDomain(controlPanel), [["bool", "=", false]]);
});
@@ -678,17 +672,17 @@ QUnit.module("Search", (hooks) => {
</search>
`,
});
await editSearch(controlPanel, "bar");
await validateSearch(controlPanel);
await editSearch(target, "bar");
await validateSearch(target);
assert.deepEqual(getDomain(controlPanel), [["foo", "ilike", "bar"]]);
await removeFacet(controlPanel);
await removeFacet(target);
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, " bar ");
await validateSearch(controlPanel);
await editSearch(target, " bar ");
await validateSearch(target);
assert.deepEqual(
getDomain(controlPanel),
@@ -721,17 +715,17 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "ref");
await validateSearch(controlPanel);
await editSearch(target, "ref");
await validateSearch(target);
assert.deepEqual(getDomain(controlPanel), [["ref", "ilike", "ref"]]);
await removeFacet(controlPanel);
await removeFacet(target);
assert.deepEqual(getDomain(controlPanel), []);
await editSearch(controlPanel, "ref002");
await validateSearch(controlPanel);
await editSearch(target, "ref002");
await validateSearch(target);
assert.deepEqual(getDomain(controlPanel), [["ref", "ilike", "ref002"]]);
});
@@ -747,7 +741,7 @@ QUnit.module("Search", (hooks) => {
await def;
}
};
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC,
resModel: "partner",
@@ -760,18 +754,18 @@ QUnit.module("Search", (hooks) => {
</search>
`,
});
await editSearch(controlPanel, "rec");
await click(controlPanel.el.querySelector(".o_expand"));
await editSearch(target, "rec");
await click(target.querySelector(".o_expand"));
await triggerEvent(
controlPanel.el,
target,
".o_searchview_autocomplete li.o_menu_item:first-child",
"mousemove"
);
assert.containsNone(controlPanel, ".o_searchview_autocomplete li.o_menu_item.o_indent");
assert.containsNone(target, ".o_searchview_autocomplete li.o_menu_item.o_indent");
def.resolve();
await nextTick();
assert.containsN(controlPanel, ".o_searchview_autocomplete li.o_menu_item.o_indent", 5);
assert.containsN(target, ".o_searchview_autocomplete li.o_menu_item.o_indent", 5);
}
);
@@ -786,7 +780,7 @@ QUnit.module("Search", (hooks) => {
await def;
}
};
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC,
resModel: "partner",
@@ -799,22 +793,22 @@ QUnit.module("Search", (hooks) => {
</search>
`,
});
await editSearch(controlPanel, "rec");
await click(controlPanel.el.querySelector(".o_expand"));
const searchInput = controlPanel.el.querySelector(".o_searchview input");
await editSearch(target, "rec");
await click(target.querySelector(".o_expand"));
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
assert.containsNone(controlPanel, ".o_searchview_autocomplete li.o_menu_item.o_indent");
assert.containsNone(target, ".o_searchview_autocomplete li.o_menu_item.o_indent");
def.resolve();
await nextTick();
assert.containsN(controlPanel, ".o_searchview_autocomplete li.o_menu_item.o_indent", 5);
assert.containsN(target, ".o_searchview_autocomplete li.o_menu_item.o_indent", 5);
}
);
QUnit.test("checks that an arrowDown always selects an item", async function (assert) {
assert.expect(1);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -826,23 +820,23 @@ QUnit.module("Search", (hooks) => {
</search>
`,
});
await editSearch(controlPanel, "rec");
await click(controlPanel.el.querySelector(".o_expand"));
click(controlPanel.el.querySelector(".o_expand"));
await editSearch(target, "rec");
await click(target.querySelector(".o_expand"));
click(target.querySelector(".o_expand"));
triggerEvent(
controlPanel.el,
target,
".o_searchview_autocomplete li.o_menu_item.o_indent:last-child",
"mousemove"
);
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowDown" });
assert.containsOnce(controlPanel, ".o_selection_focus");
assert.containsOnce(target, ".o_selection_focus");
});
QUnit.test("checks that an arrowUp always selects an item", async function (assert) {
assert.expect(1);
const controlPanel = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "partner",
Component: ControlPanel,
@@ -854,16 +848,16 @@ QUnit.module("Search", (hooks) => {
</search>
`,
});
await editSearch(controlPanel, "rec");
await click(controlPanel.el.querySelector(".o_expand"));
click(controlPanel.el.querySelector(".o_expand"));
await editSearch(target, "rec");
await click(target.querySelector(".o_expand"));
click(target.querySelector(".o_expand"));
triggerEvent(
controlPanel.el,
target,
".o_searchview_autocomplete li.o_menu_item.o_indent:last-child",
"mousemove"
);
const searchInput = controlPanel.el.querySelector(".o_searchview input");
const searchInput = target.querySelector(".o_searchview input");
await triggerEvent(searchInput, null, "keydown", { key: "ArrowUp" });
assert.containsOnce(controlPanel, ".o_selection_focus");
assert.containsOnce(target, ".o_selection_focus");
});
});
File diff suppressed because it is too large Load Diff
@@ -22,6 +22,7 @@ const { Component, onWillUpdateProps, onWillStart, useState, xml } = owl;
const serviceRegistry = registry.category("services");
let target;
let serverData;
QUnit.module("Search", (hooks) => {
@@ -57,6 +58,7 @@ QUnit.module("Search", (hooks) => {
serviceRegistry.add("hotkey", hotkeyService);
serviceRegistry.add("orm", ormService);
serviceRegistry.add("view", viewService);
target = getFixture();
});
QUnit.module("WithSearch");
@@ -67,13 +69,16 @@ QUnit.module("Search", (hooks) => {
class TestComponent extends Component {}
TestComponent.template = xml`<div class="o_test_component">Test component content</div>`;
const component = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "animal",
Component: TestComponent,
});
assert.hasClass(component.el, "o_test_component");
assert.strictEqual(component.el.innerText, "Test component content");
assert.containsOnce(target, ".o_test_component");
assert.strictEqual(
target.querySelector(".o_test_component").innerText,
"Test component content"
);
});
QUnit.test("search model in sub env", async function (assert) {
@@ -245,7 +250,7 @@ QUnit.module("Search", (hooks) => {
</div>
`;
const component = await makeWithSearch({
await makeWithSearch({
serverData,
mockRPC: function (_, args) {
if (args.method === "load_views") {
@@ -256,11 +261,11 @@ QUnit.module("Search", (hooks) => {
Component: TestComponent,
searchViewId: 1,
});
await toggleFilterMenu(component);
await assert.ok(getMenuItemTexts(component), ["True Domain"]);
await toggleFilterMenu(target);
await assert.ok(getMenuItemTexts(target), ["True Domain"]);
await toggleGroupByMenu(component);
await assert.ok(getMenuItemTexts(component), ["Name"]);
await toggleGroupByMenu(target);
await assert.ok(getMenuItemTexts(target), ["Name"]);
}
);
@@ -286,14 +291,14 @@ QUnit.module("Search", (hooks) => {
</div>
`;
const component = await makeWithSearch({
await makeWithSearch({
serverData,
resModel: "animal",
Component: TestComponent,
searchViewId: 1,
});
await toggleFilterMenu(component);
await toggleMenuItem(component, "True domain");
await toggleFilterMenu(target);
await toggleMenuItem(target, "True domain");
}
);
+41 -38
View File
@@ -12,6 +12,7 @@ const { Component, xml, useChildSubEnv } = owl;
const serviceRegistry = registry.category("services");
let target;
let serverData;
QUnit.module("Views", (hooks) => {
@@ -43,6 +44,8 @@ QUnit.module("Views", (hooks) => {
setupControlPanelServiceRegistry();
serviceRegistry.add("dialog", dialogService);
target = getFixture();
});
QUnit.module("Layout");
@@ -58,13 +61,13 @@ QUnit.module("Views", (hooks) => {
ToyComponent.components = { Layout };
const env = await makeTestEnv({ config: {} });
const comp = await mount(ToyComponent, getFixture(), { env });
await mount(ToyComponent, getFixture(), { env });
assert.hasClass(comp.el, "o_toy_view o_view_sample_data");
assert.containsNone(comp, ".o_control_panel");
assert.containsNone(comp, ".o_component_with_search_panel");
assert.containsNone(comp, ".o_search_panel");
assert.containsOnce(comp, ".o_content > .toy_content");
assert.containsOnce(target, ".o_toy_view.o_view_sample_data");
assert.containsNone(target, ".o_control_panel");
assert.containsNone(target, ".o_component_with_search_panel");
assert.containsNone(target, ".o_search_panel");
assert.containsOnce(target, ".o_content > .toy_content");
});
QUnit.test("Simple rendering: with search", async (assert) => {
@@ -80,19 +83,19 @@ QUnit.module("Views", (hooks) => {
</Layout>`;
ToyComponent.components = { Layout };
const root = await makeWithSearch({
await makeWithSearch({
serverData,
Component: ToyComponent,
resModel: "foo",
searchViewId: false,
});
assert.hasClass(root.el, "o_toy_view");
assert.doesNotHaveClass(root.el, "o_view_sample_data");
assert.containsOnce(root, ".o_control_panel .o_cp_top_right .toy_search_bar");
assert.containsOnce(root, ".o_component_with_search_panel .o_search_panel");
assert.containsNone(root, ".o_cp_searchview");
assert.containsOnce(root, ".o_content > .toy_content");
assert.containsOnce(target, ".o_toy_view");
assert.containsNone(target, ".o_view_sample_data");
assert.containsOnce(target, ".o_control_panel .o_cp_top_right .toy_search_bar");
assert.containsOnce(target, ".o_component_with_search_panel .o_search_panel");
assert.containsNone(target, ".o_cp_searchview");
assert.containsOnce(target, ".o_content > .toy_content");
});
QUnit.test("Nested layouts", async (assert) => {
@@ -154,23 +157,23 @@ QUnit.module("Views", (hooks) => {
</Layout>`;
ToyA.components = { Layout, ToyB };
const root = await makeWithSearch({
await makeWithSearch({
serverData,
Component: ToyA,
resModel: "foo",
searchViewId: false,
});
assert.hasClass(root.el, "o_toy_a_view");
assert.doesNotHaveClass(root.el, "o_view_sample_data");
assert.containsOnce(root, ".o_content .o_toy_b_view .o_content .o_toy_c_view .o_content"); // Full chain of contents
assert.containsN(root, ".o_control_panel", 2); // Component C has hidden its control panel
assert.containsN(root, ".o_content.o_component_with_search_panel", 3);
assert.containsOnce(root, ".o_search_panel"); // Standard search panel
assert.containsN(root, ".o_toy_search_panel", 2); // Custom search panels
assert.containsOnce(root, ".toy_a_search");
assert.containsOnce(root, ".toy_b_breadcrumbs");
assert.containsOnce(root, ".toy_c_content");
assert.containsOnce(target, ".o_toy_a_view");
assert.containsNone(target, ".o_view_sample_data");
assert.containsOnce(target, ".o_content .o_toy_b_view .o_content .o_toy_c_view .o_content"); // Full chain of contents
assert.containsN(target, ".o_control_panel", 2); // Component C has hidden its control panel
assert.containsN(target, ".o_content.o_component_with_search_panel", 3);
assert.containsOnce(target, ".o_search_panel"); // Standard search panel
assert.containsN(target, ".o_toy_search_panel", 2); // Custom search panels
assert.containsOnce(target, ".toy_a_search");
assert.containsOnce(target, ".toy_b_breadcrumbs");
assert.containsOnce(target, ".toy_c_content");
});
QUnit.test("Custom control panel", async (assert) => {
@@ -186,7 +189,7 @@ QUnit.module("Views", (hooks) => {
class ControlPanel extends Component {}
ControlPanel.template = xml`<div class="o_toy_search_panel" />`;
const root = await makeWithSearch({
await makeWithSearch({
serverData,
Component: ToyComponent,
resModel: "foo",
@@ -194,9 +197,9 @@ QUnit.module("Views", (hooks) => {
config: { ControlPanel },
});
assert.containsOnce(root, ".o_toy_content");
assert.containsOnce(root, ".o_toy_search_panel");
assert.containsNone(root, ".o_control_panel");
assert.containsOnce(target, ".o_toy_content");
assert.containsOnce(target, ".o_toy_search_panel");
assert.containsNone(target, ".o_control_panel");
});
QUnit.test("Custom search panel", async (assert) => {
@@ -212,7 +215,7 @@ QUnit.module("Views", (hooks) => {
class SearchPanel extends Component {}
SearchPanel.template = xml`<div class="o_toy_search_panel" />`;
const root = await makeWithSearch({
await makeWithSearch({
serverData,
Component: ToyComponent,
resModel: "foo",
@@ -220,9 +223,9 @@ QUnit.module("Views", (hooks) => {
config: { SearchPanel },
});
assert.containsOnce(root, ".o_toy_content");
assert.containsOnce(root, ".o_toy_search_panel");
assert.containsNone(root, ".o_search_panel");
assert.containsOnce(target, ".o_toy_content");
assert.containsOnce(target, ".o_toy_search_panel");
assert.containsNone(target, ".o_search_panel");
});
QUnit.test("Custom banner: no bannerRoute in env", async (assert) => {
@@ -238,7 +241,7 @@ QUnit.module("Views", (hooks) => {
class Banner extends Component {}
Banner.template = xml`<div class="o_toy_banner" />`;
const root = await makeWithSearch({
await makeWithSearch({
serverData,
Component: ToyComponent,
resModel: "foo",
@@ -246,8 +249,8 @@ QUnit.module("Views", (hooks) => {
config: { Banner },
});
assert.containsOnce(root, ".o_toy_content");
assert.containsNone(root, ".o_toy_banner");
assert.containsOnce(target, ".o_toy_content");
assert.containsNone(target, ".o_toy_banner");
});
QUnit.test("Custom banner: with bannerRoute in env", async (assert) => {
@@ -263,7 +266,7 @@ QUnit.module("Views", (hooks) => {
class Banner extends Component {}
Banner.template = xml`<div class="o_toy_banner" />`;
const root = await makeWithSearch({
await makeWithSearch({
serverData,
Component: ToyComponent,
resModel: "foo",
@@ -271,7 +274,7 @@ QUnit.module("Views", (hooks) => {
config: { Banner, bannerRoute: "toy/banner/route" },
});
assert.containsOnce(root, ".o_toy_content");
assert.containsOnce(root, ".o_toy_banner");
assert.containsOnce(target, ".o_toy_content");
assert.containsOnce(target, ".o_toy_banner");
});
});
+145 -91
View File
@@ -22,6 +22,7 @@ const serviceRegistry = registry.category("services");
const viewRegistry = registry.category("views");
let serverData;
let target;
QUnit.module("Views", (hooks) => {
hooks.beforeEach(async () => {
@@ -102,6 +103,8 @@ QUnit.module("Views", (hooks) => {
},
};
serviceRegistry.add("action", fakeActionService, { force: true });
target = getFixture();
});
QUnit.module("View component");
@@ -126,7 +129,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.strictEqual(args.model, "animal");
@@ -141,8 +144,11 @@ QUnit.module("Views", (hooks) => {
resModel: "animal",
type: "toy",
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, serverData.views["animal,false,toy"]);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
serverData.views["animal,false,toy"]
);
});
QUnit.test("rendering with given viewId", async function (assert) {
@@ -160,7 +166,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.deepEqual(args.kwargs.views, [[1, "toy"]]);
@@ -174,8 +180,11 @@ QUnit.module("Views", (hooks) => {
type: "toy",
viewId: 1,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, serverData.views["animal,1,toy"]);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
serverData.views["animal,1,toy"]
);
});
QUnit.test("rendering with given 'views' param", async function (assert) {
@@ -193,7 +202,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
console.log(_);
@@ -210,8 +219,11 @@ QUnit.module("Views", (hooks) => {
views: [[1, "toy"]],
},
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, serverData.views["animal,1,toy"]);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
serverData.views["animal,1,toy"]
);
});
QUnit.test(
@@ -231,7 +243,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.deepEqual(args.kwargs.views, [
@@ -250,8 +262,11 @@ QUnit.module("Views", (hooks) => {
views: [[false, "other"]],
},
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, serverData.views["animal,false,toy"]);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
serverData.views["animal,false,toy"]
);
}
);
@@ -270,7 +285,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.deepEqual(args.kwargs.views, [
@@ -293,8 +308,11 @@ QUnit.module("Views", (hooks) => {
],
},
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, serverData.views["animal,1,toy"]);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
serverData.views["animal,1,toy"]
);
});
QUnit.test("rendering with given arch and fields", async function (assert) {
@@ -312,7 +330,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: () => {
throw new Error("no RPC expected");
@@ -322,8 +340,11 @@ QUnit.module("Views", (hooks) => {
arch: `<toy>Specific arch content</toy>`,
fields: {},
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, `<toy>Specific arch content</toy>`);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
`<toy>Specific arch content</toy>`
);
});
QUnit.test("rendering with loadActionMenus='true'", async function (assert) {
@@ -341,7 +362,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
// the rpc is done for fields
@@ -356,8 +377,11 @@ QUnit.module("Views", (hooks) => {
type: "toy",
loadActionMenus: true,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, serverData.views["animal,false,toy"]);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
serverData.views["animal,false,toy"]
);
});
QUnit.test(
@@ -377,7 +401,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
// the rpc is done for fields
@@ -394,8 +418,11 @@ QUnit.module("Views", (hooks) => {
fields: {},
loadActionMenus: true,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, `<toy>Specific arch content</toy>`);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
`<toy>Specific arch content</toy>`
);
}
);
@@ -416,7 +443,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: () => {
throw new Error("no RPC expected");
@@ -430,8 +457,11 @@ QUnit.module("Views", (hooks) => {
},
loadActionMenus: true,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerHTML, `<toy>Specific arch content</toy>`);
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerHTML,
`<toy>Specific arch content</toy>`
);
}
);
@@ -455,7 +485,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
// the rpc is done for fields
@@ -473,8 +503,11 @@ QUnit.module("Views", (hooks) => {
type: "toy",
searchViewId: false,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerText, "Arch content (id=false)");
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerText,
"Arch content (id=false)"
);
});
QUnit.test(
@@ -512,8 +545,11 @@ QUnit.module("Views", (hooks) => {
searchViewArch: `<search/>`,
searchViewFields: {},
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerText, "Specific arch content");
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerText,
"Specific arch content"
);
}
);
@@ -539,7 +575,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: () => {
throw new Error("no RPC expected");
@@ -551,8 +587,11 @@ QUnit.module("Views", (hooks) => {
searchViewArch: `<search/>`,
searchViewFields: {},
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerText, "Specific arch content");
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerText,
"Specific arch content"
);
}
);
@@ -578,7 +617,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
// the rpc is done for fields
@@ -601,8 +640,11 @@ QUnit.module("Views", (hooks) => {
searchViewFields: {},
loadIrFilters: true,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerText, "Specific arch content");
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerText,
"Specific arch content"
);
}
);
@@ -639,7 +681,7 @@ QUnit.module("Views", (hooks) => {
},
});
const view = await makeView({
await makeView({
serverData,
mockRPC: () => {
throw new Error("no RPC expected");
@@ -653,8 +695,11 @@ QUnit.module("Views", (hooks) => {
loadIrFilters: true,
irFilters,
});
assert.hasClass(view.el, "o_toy_view");
assert.strictEqual(view.el.innerText, "Specific arch content");
assert.containsOnce(target, ".o_toy_view");
assert.strictEqual(
target.querySelector(".o_toy_view").innerText,
"Specific arch content"
);
}
);
@@ -698,7 +743,7 @@ QUnit.module("Views", (hooks) => {
}
};
const toy = await makeView({
await makeView({
serverData,
mockRPC,
resModel: "animal",
@@ -708,8 +753,8 @@ QUnit.module("Views", (hooks) => {
},
});
assert.containsOnce(toy, "a");
await click(toy.el.querySelector("a"));
assert.containsOnce(target, "a");
await click(target.querySelector("a"));
assert.verifySteps(["/web/dataset/call_kw/animal/setTheControl"]);
});
@@ -744,7 +789,7 @@ QUnit.module("Views", (hooks) => {
<a type="action" name="myLittleAction" data-context="{ &quot;somekey&quot;: &quot;somevalue&quot; }"/>
</toy>`;
const toy = await makeView({
await makeView({
serverData,
resModel: "animal",
type: "toy",
@@ -753,8 +798,8 @@ QUnit.module("Views", (hooks) => {
},
});
assert.containsOnce(toy, "a");
await click(toy.el.querySelector("a"));
assert.containsOnce(target, "a");
await click(target.querySelector("a"));
});
QUnit.test("can click on action-bound links -- 3", async (assert) => {
@@ -796,7 +841,7 @@ QUnit.module("Views", (hooks) => {
<a type="action" title="myTitle" data-model="animal" data-resId="66" data-views="[[55, 'toy']]" data-domain="[['field', '=', 'val']]" data-context="{ &quot;somekey&quot;: &quot;somevalue&quot; }"/>
</toy>`;
const toy = await makeView({
await makeView({
serverData,
resModel: "animal",
type: "toy",
@@ -805,8 +850,8 @@ QUnit.module("Views", (hooks) => {
},
});
assert.containsOnce(toy, "a");
await click(toy.el.querySelector("a"));
assert.containsOnce(target, "a");
await click(target.querySelector("a"));
});
QUnit.test("renders banner_route", async (assert) => {
@@ -823,7 +868,7 @@ QUnit.module("Views", (hooks) => {
}
};
const toy = await makeView({
await makeView({
serverData,
mockRPC,
resModel: "animal",
@@ -834,7 +879,7 @@ QUnit.module("Views", (hooks) => {
});
assert.verifySteps(["/mybody/isacage"]);
assert.containsOnce(toy, ".setmybodyfree");
assert.containsOnce(target, ".setmybodyfree");
});
QUnit.test("renders banner_route with js and css assets", async (assert) => {
@@ -885,7 +930,7 @@ QUnit.module("Views", (hooks) => {
patchWithCleanup(document, { createElement });
const toy = await makeView({
await makeView({
serverData,
mockRPC,
resModel: "animal",
@@ -896,9 +941,9 @@ QUnit.module("Views", (hooks) => {
});
assert.verifySteps(["/mybody/isacage", "js loaded", "css loaded"]);
assert.containsOnce(toy, ".setmybodyfree");
assert.containsNone(toy, "script");
assert.containsNone(toy, "link");
assert.containsOnce(target, ".setmybodyfree");
assert.containsNone(target, "script");
assert.containsNone(target, "link");
});
QUnit.test("banner can re-render with new HTML", async (assert) => {
@@ -932,7 +977,7 @@ QUnit.module("Views", (hooks) => {
}
};
const toy = await makeView({
await makeView({
serverData,
mockRPC,
resModel: "animal",
@@ -943,12 +988,12 @@ QUnit.module("Views", (hooks) => {
});
assert.verifySteps(["/mybody/isacage"]);
assert.containsOnce(toy, ".banner1");
assert.containsNone(toy, ".banner2");
await click(toy.el.querySelector("a"));
assert.containsOnce(target, ".banner1");
assert.containsNone(target, ".banner2");
await click(target.querySelector("a"));
assert.verifySteps(["/mybody/isacage"]);
assert.containsNone(toy, ".banner1");
assert.containsOnce(toy, ".banner2");
assert.containsNone(target, ".banner1");
assert.containsOnce(target, ".banner2");
});
QUnit.test("banner does not reload on render", async (assert) => {
@@ -981,11 +1026,11 @@ QUnit.module("Views", (hooks) => {
});
assert.verifySteps(["/mybody/isacage"]);
assert.containsOnce(toy, ".setmybodyfree");
assert.containsOnce(target, ".setmybodyfree");
await toy.render();
await nextTick();
assert.verifySteps([]);
assert.containsOnce(toy, ".setmybodyfree");
assert.containsOnce(target, ".setmybodyfree");
});
QUnit.test("click on action-bound links in banner (concurrency)", async (assert) => {
@@ -1038,7 +1083,7 @@ QUnit.module("Views", (hooks) => {
}
};
const toy = await makeView({
await makeView({
mockRPC,
serverData,
resModel: "animal",
@@ -1048,8 +1093,8 @@ QUnit.module("Views", (hooks) => {
},
});
await click(toy.el.querySelector("a[data-method='setTheControl']"));
click(toy.el.querySelector("a[data-method='heartOfTheSun']"));
await click(target.querySelector("a[data-method='setTheControl']"));
click(target.querySelector("a[data-method='heartOfTheSun']"));
prom.resolve();
await nextTick();
});
@@ -1104,7 +1149,7 @@ QUnit.module("Views", (hooks) => {
}
};
const toy = await makeView({
await makeView({
serverData,
mockRPC,
resModel: "animal",
@@ -1122,23 +1167,23 @@ QUnit.module("Views", (hooks) => {
};
// We need to handle both events, because the transition is not
// always executed
toy.el.addEventListener("transitionend", complete);
toy.el.addEventListener("transitioncancel", complete);
target.addEventListener("transitionend", complete);
target.addEventListener("transitioncancel", complete);
});
assert.verifySteps(["/mybody/isacage"]);
assert.isNotVisible(toy.el.querySelector(".modal"));
assert.hasClass(toy.el.querySelector(".o_onboarding_container"), "collapse show");
assert.isNotVisible(target.querySelector(".modal"));
assert.hasClass(target.querySelector(".o_onboarding_container"), "collapse show");
await click(toy.el.querySelector("#closeOnboarding"));
assert.isVisible(toy.el.querySelector(".modal"));
await click(target.querySelector("#closeOnboarding"));
assert.isVisible(target.querySelector(".modal"));
await click(toy.el.querySelector(".modal a[type='action']"));
await click(target.querySelector(".modal a[type='action']"));
assert.verifySteps(["mah_method"]);
await prom;
assert.doesNotHaveClass(toy.el.querySelector(".o_onboarding_container"), "show");
assert.hasClass(toy.el.querySelector(".o_onboarding_container"), "collapse");
assert.isNotVisible(toy.el.querySelector(".modal"));
assert.doesNotHaveClass(target.querySelector(".o_onboarding_container"), "show");
assert.hasClass(target.querySelector(".o_onboarding_container"), "collapse");
assert.isNotVisible(target.querySelector(".modal"));
});
////////////////////////////////////////////////////////////////////////////
@@ -1147,7 +1192,7 @@ QUnit.module("Views", (hooks) => {
QUnit.test("rendering with given jsClass", async function (assert) {
assert.expect(4);
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.deepEqual(args.kwargs.views, [[false, "toy"]]);
@@ -1160,13 +1205,16 @@ QUnit.module("Views", (hooks) => {
resModel: "animal",
type: "toy_imp",
});
assert.hasClass(view.el, "o_toy_view_imp");
assert.strictEqual(view.el.innerText, "Arch content (id=false)");
assert.containsOnce(target, ".o_toy_view_imp");
assert.strictEqual(
target.querySelector(".o_toy_view_imp").innerText,
"Arch content (id=false)"
);
});
QUnit.test("rendering with loaded arch attribute 'js_class'", async function (assert) {
assert.expect(4);
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.deepEqual(args.kwargs.views, [[2, "toy"]]);
@@ -1180,13 +1228,16 @@ QUnit.module("Views", (hooks) => {
type: "toy",
viewId: 2,
});
assert.hasClass(view.el, "o_toy_view_imp");
assert.strictEqual(view.el.innerText, "Arch content (id=2)");
assert.containsOnce(target, ".o_toy_view_imp");
assert.strictEqual(
target.querySelector(".o_toy_view_imp").innerText,
"Arch content (id=2)"
);
});
QUnit.test("rendering with given arch attribute 'js_class'", async function (assert) {
assert.expect(2);
const view = await makeView({
await makeView({
serverData,
mockRPC: () => {
throw new Error("no RPC expected");
@@ -1196,8 +1247,11 @@ QUnit.module("Views", (hooks) => {
arch: `<toy js_class="toy_imp">Specific arch content for specific class</toy>`,
fields: {},
});
assert.hasClass(view.el, "o_toy_view_imp");
assert.strictEqual(view.el.innerText, "Specific arch content for specific class");
assert.containsOnce(target, ".o_toy_view_imp");
assert.strictEqual(
target.querySelector(".o_toy_view_imp").innerText,
"Specific arch content for specific class"
);
});
QUnit.test(
@@ -1210,7 +1264,7 @@ QUnit.module("Views", (hooks) => {
ToyView2.type = "toy";
viewRegistry.add("toy_2", ToyView2);
const view = await makeView({
await makeView({
serverData,
mockRPC: (_, args) => {
assert.deepEqual(args.kwargs.views, [[2, "toy"]]);
@@ -1224,7 +1278,7 @@ QUnit.module("Views", (hooks) => {
type: "toy_2",
viewId: 2,
});
assert.hasClass(view.el, "o_toy_view_imp", "jsClass from arch prefered");
assert.containsOnce(target, ".o_toy_view_imp", "jsClass from arch prefered");
}
);
@@ -1238,7 +1292,7 @@ QUnit.module("Views", (hooks) => {
ToyView2.type = "toy";
viewRegistry.add("toy_2", ToyView2);
const view = await makeView({
await makeView({
serverData,
mockRPC: () => {
throw new Error("no RPC expected");
@@ -1248,7 +1302,7 @@ QUnit.module("Views", (hooks) => {
arch: `<toy js_class="toy_imp"/>`,
fields: {},
});
assert.hasClass(view.el, "o_toy_view_imp", "jsClass from arch prefered");
assert.containsOnce(target, ".o_toy_view_imp", "jsClass from arch prefered");
}
);
@@ -8,6 +8,7 @@ import testUtils from "web.test_utils";
import { registerCleanup } from "../../helpers/cleanup";
import { click, getFixture, legacyExtraNextTick, patchWithCleanup } from "../../helpers/utils";
import { createWebClient, doAction, getActionManagerServerData } from "./../helpers";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
@@ -99,7 +100,7 @@ QUnit.module("ActionManager", (hooks) => {
QUnit.test("can execute client actions from tag name", async function (assert) {
assert.expect(4);
class ClientAction extends Component {}
class ClientAction extends LegacyComponent {}
ClientAction.template = xml`<div class="o_client_action_test">Hello World</div>`;
actionRegistry.add("HelloWorldTest", ClientAction);
@@ -231,7 +232,7 @@ QUnit.module("ActionManager", (hooks) => {
QUnit.test("action can use a custom control panel (legacy)", async function (assert) {
assert.expect(1);
class CustomControlPanel extends Component {}
class CustomControlPanel extends LegacyComponent {}
CustomControlPanel.template = xml`
<div class="custom-control-panel">My custom control panel</div>
`;
@@ -327,7 +328,7 @@ QUnit.module("ActionManager", (hooks) => {
QUnit.test("ClientAction receives breadcrumbs and exports title (wowl)", async (assert) => {
assert.expect(4);
class ClientAction extends Component {
class ClientAction extends LegacyComponent {
setup() {
this.breadcrumbTitle = "myOwlAction";
const { breadcrumbs } = this.env.config;
@@ -358,7 +359,7 @@ QUnit.module("ActionManager", (hooks) => {
QUnit.test("ClientAction receives arbitrary props from doAction (wowl)", async (assert) => {
assert.expect(1);
class ClientAction extends Component {
class ClientAction extends LegacyComponent {
setup() {
assert.strictEqual(this.props.division, "bell");
}
@@ -9,6 +9,7 @@ import { registry } from "@web/core/registry";
import testUtils from "web.test_utils";
import { useSetupView } from "@web/views/helpers/view_hook";
import * as cpHelpers from "@web/../tests/search/helpers";
import { LegacyComponent } from "@web/legacy/legacy_component";
const { Component, xml } = owl;
const actionRegistry = registry.category("actions");
@@ -439,7 +440,7 @@ QUnit.module("ActionManager", (hooks) => {
async function (assert) {
assert.expect(3);
const slowWillStartDef = testUtils.makeTestPromise();
class ClientAction extends Component {
class ClientAction extends LegacyComponent {
setup() {
owl.onWillStart(() => slowWillStartDef);
}
@@ -587,7 +588,7 @@ QUnit.module("ActionManager", (hooks) => {
let def = Promise.resolve();
let id = 1;
class ToyView extends Component {
class ToyView extends LegacyComponent {
setup() {
this.id = id++;
assert.step(JSON.stringify(this.props.state || "no state"));

Some files were not shown because too many files have changed in this diff Show More