[FIX] web: menus missing aria attributes

Some missing aria attributes from 14.0 are reintroduced.

They are required for screen reader users to be able to know if menus
are opened and if menuitems are checked (e.g. if a filter is applied).

closes odoo/odoo#106277

Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
Signed-off-by: Bruno Boi (boi) <boi@odoo.com>
Co-authored-by: Luis González <lgonzalez@vauxoo.com>
This commit is contained in:
Bruno Boi
2022-11-23 13:24:51 +01:00
co-authored by Luis González
parent 192e80c03e
commit 29ca002ee5
28 changed files with 189 additions and 63 deletions
@@ -147,6 +147,13 @@ export class Dropdown extends Component {
() => []
);
useEffect(
(open) => {
this.rootRef.el.parentElement.ariaExpanded = open ? "true" : "false";
},
() => [this.state.open]
);
// Position menu relatively to parent element
usePosition(() => this.rootRef.el.parentElement, positioningOptions);
} else {
@@ -25,6 +25,7 @@
t-att-data-hotkey="props.hotkey"
t-att-data-tooltip="props.tooltip"
t-att-tabindex="props.skipTogglerTabbing ? -1 : 0"
t-att-aria-expanded="state.open ? 'true' : 'false'"
t-ref="togglerRef"
>
<t t-slot="toggler" />
@@ -33,6 +34,7 @@
t-if="state.open"
class="o-dropdown--menu dropdown-menu d-block"
t-att-class="props.menuClass"
role="menu"
t-ref="menuRef"
>
<t t-slot="default" />
@@ -7,6 +7,7 @@
t-att-href="props.href"
class="dropdown-item"
t-att-class="props.class"
role="menuitem"
t-on-click.stop="onClick"
t-att-title="props.title"
t-att-data-hotkey="props.hotkey"
@@ -2,7 +2,7 @@ odoo.define("web.ComparisonMenu", function (require) {
"use strict";
const { Dropdown } = require("@web/core/dropdown/dropdown");
const { DropdownItem } = require("@web/core/dropdown/dropdown_item");
const { SearchDropdownItem } = require("@web/search/search_dropdown_item/search_dropdown_item");
const { FACET_ICONS } = require("web.searchUtils");
const { useModel } = require("web.Model");
const { LegacyComponent } = require("@web/legacy/legacy_component");
@@ -29,7 +29,7 @@ odoo.define("web.ComparisonMenu", function (require) {
}
}
ComparisonMenu.template = "web.ComparisonMenu";
ComparisonMenu.components = { Dropdown, DropdownItem };
ComparisonMenu.components = { Dropdown, SearchDropdownItem };
return ComparisonMenu;
});
@@ -2,7 +2,7 @@ odoo.define('web.FavoriteMenu', function (require) {
"use strict";
const { Dropdown } = require("@web/core/dropdown/dropdown");
const { DropdownItem } = require("@web/core/dropdown/dropdown_item");
const { SearchDropdownItem } = require("@web/search/search_dropdown_item/search_dropdown_item");
const Dialog = require('web.OwlDialog');
const { FACET_ICONS } = require("web.searchUtils");
const Registry = require('web.Registry');
@@ -83,7 +83,7 @@ odoo.define('web.FavoriteMenu', function (require) {
}
FavoriteMenu.registry = new Registry();
FavoriteMenu.components = { Dialog, Dropdown, DropdownItem };
FavoriteMenu.components = { Dialog, Dropdown, SearchDropdownItem };
FavoriteMenu.template = 'web.Legacy.FavoriteMenu';
return FavoriteMenu;
@@ -2,7 +2,7 @@ odoo.define('web.FilterMenu', function (require) {
"use strict";
const { Dropdown } = require("@web/core/dropdown/dropdown");
const { DropdownItem } = require("@web/core/dropdown/dropdown_item");
const { SearchDropdownItem } = require("@web/search/search_dropdown_item/search_dropdown_item");
const CustomFilterItem = require('web.CustomFilterItem');
const { FACET_ICONS } = require("web.searchUtils");
const { useModel } = require('web.Model');
@@ -52,7 +52,6 @@ odoo.define('web.FilterMenu', function (require) {
}
}
FilterMenu.components = { CustomFilterItem };
FilterMenu.defaultProps = {
class: "",
};
@@ -61,7 +60,7 @@ odoo.define('web.FilterMenu', function (require) {
class: { String, optional: true },
};
FilterMenu.template = "web.legacy.FilterMenu";
FilterMenu.components = { CustomFilterItem, Dropdown, DropdownItem };
FilterMenu.components = { CustomFilterItem, Dropdown, SearchDropdownItem };
return FilterMenu;
});
@@ -2,7 +2,7 @@ odoo.define('web.GroupByMenu', function (require) {
"use strict";
const { Dropdown } = require("@web/core/dropdown/dropdown");
const { DropdownItem } = require("@web/core/dropdown/dropdown_item");
const { SearchDropdownItem } = require("@web/search/search_dropdown_item/search_dropdown_item");
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');
@@ -70,7 +70,7 @@ odoo.define('web.GroupByMenu', function (require) {
}
}
GroupByMenu.components = { CustomGroupByItem, Dropdown, DropdownItem };
GroupByMenu.components = { CustomGroupByItem, Dropdown, SearchDropdownItem };
GroupByMenu.props = { fields: Object };
GroupByMenu.template = "web.GroupByMenu";
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { SearchDropdownItem } from "@web/search/search_dropdown_item/search_dropdown_item";
import { FACET_ICONS } from "../utils/misc";
import { useBus } from "@web/core/utils/hooks";
@@ -30,6 +30,5 @@ export class ComparisonMenu extends Component {
this.env.searchModel.toggleSearchItem(itemId);
}
}
ComparisonMenu.template = "web.ComparisonMenu";
ComparisonMenu.components = { Dropdown, DropdownItem };
ComparisonMenu.components = { Dropdown, SearchDropdownItem };
@@ -8,7 +8,8 @@
<span class="o_dropdown_title">Comparison</span>
</t>
<t t-foreach="items" t-as="item" t-key="item.id">
<DropdownItem class="{ o_menu_item: true, selected: item.isActive }"
<SearchDropdownItem class="{ o_menu_item: true, selected: item.isActive }"
checked="item.isActive"
parentClosingMode="'none'"
t-esc="item.description"
onSelected="() => this.onComparisonSelected(item.id)"
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { SearchDropdownItem } from "@web/search/search_dropdown_item/search_dropdown_item";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { FACET_ICONS } from "../utils/misc";
import { registry } from "@web/core/registry";
@@ -63,7 +63,6 @@ export class FavoriteMenu extends Component {
this.dialogService.add(ConfirmationDialog, dialogProps);
}
}
FavoriteMenu.template = "web.FavoriteMenu";
FavoriteMenu.components = { Dropdown, DropdownItem };
FavoriteMenu.components = { Dropdown, SearchDropdownItem };
FavoriteMenu.props = {};
@@ -13,7 +13,8 @@
<div role="separator" class="dropdown-divider"/>
</t>
<t t-if="item.type ==='favorite'">
<DropdownItem class="{ o_menu_item: true, selected: item.isActive }"
<SearchDropdownItem class="{ o_menu_item: true, selected: item.isActive }"
checked="item.isActive"
parentClosingMode="'none'"
onSelected="() => this.onFavoriteSelected(item.id)"
>
@@ -24,7 +25,7 @@
t-on-click.stop="() => this.openConfirmationDialog(item.id)"
/>
</span>
</DropdownItem>
</SearchDropdownItem>
</t>
<t t-else="">
<t t-component="item.Component"/>
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { SearchDropdownItem } from "@web/search/search_dropdown_item/search_dropdown_item";
import { CustomFilterItem } from "./custom_filter_item";
import { FACET_ICONS } from "../utils/misc";
import { useBus } from "@web/core/utils/hooks";
@@ -38,7 +38,7 @@ export class FilterMenu extends Component {
}
}
FilterMenu.components = { CustomFilterItem, Dropdown, DropdownItem };
FilterMenu.components = { CustomFilterItem, Dropdown, SearchDropdownItem };
FilterMenu.template = "web.FilterMenu";
FilterMenu.props = {
class: { type: String, optional: true },
@@ -22,8 +22,9 @@
<t t-if="subGroup !== null and subGroup !== option.groupNumber">
<div class="dropdown-divider" role="separator"/>
</t>
<DropdownItem class="{ o_item_option: true, selected: option.isActive }"
<SearchDropdownItem class="{ o_item_option: true, selected: option.isActive }"
t-esc="option.description"
checked="option.isActive"
parentClosingMode="'none'"
onSelected="() => this.onFilterSelected({ itemId: item.id, optionId: option.id })"
/>
@@ -32,7 +33,8 @@
</Dropdown>
</t>
<t t-else="">
<DropdownItem class="{ o_menu_item: true, selected: item.isActive }"
<SearchDropdownItem class="{ o_menu_item: true, selected: item.isActive }"
checked="item.isActive"
parentClosingMode="'none'"
t-esc="item.description"
onSelected="() => this.onFilterSelected({ itemId: item.id })"
@@ -1,7 +1,7 @@
/** @odoo-module **/
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { SearchDropdownItem } from "@web/search/search_dropdown_item/search_dropdown_item";
import { CustomGroupByItem } from "./custom_group_by_item";
import { FACET_ICONS, GROUPABLE_TYPES } from "../utils/misc";
import { sortBy } from "@web/core/utils/arrays";
@@ -77,7 +77,7 @@ export class GroupByMenu extends Component {
}
}
GroupByMenu.components = { CustomGroupByItem, Dropdown, DropdownItem };
GroupByMenu.components = { CustomGroupByItem, Dropdown, SearchDropdownItem };
GroupByMenu.template = "web.GroupByMenu";
GroupByMenu.defaultProps = {
showCaretDown: false,
@@ -25,7 +25,8 @@
<t t-if="subGroup !== null and subGroup !== option.groupNumber">
<div class="dropdown-divider" role="separator"/>
</t>
<DropdownItem class="{ o_item_option: true, selected: option.isActive }"
<SearchDropdownItem class="{ o_item_option: true, selected: option.isActive }"
checked="option.isActive ? true : false"
parentClosingMode="'none'"
t-esc="option.description"
onSelected="() => this.onGroupBySelected({ itemId: item.id, optionId: option.id})"
@@ -35,7 +36,8 @@
</Dropdown>
</t>
<t t-else="">
<DropdownItem class="{ o_menu_item: true, selected: item.isActive }"
<SearchDropdownItem class="{ o_menu_item: true, selected: item.isActive }"
checked="item.isActive"
parentClosingMode="'none'"
t-esc="item.description"
onSelected="() => this.onGroupBySelected({ itemId: item.id })"
@@ -0,0 +1,13 @@
/** @odoo-module **/
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
export class SearchDropdownItem extends DropdownItem {}
SearchDropdownItem.template = "web.SearchDropdownItem";
SearchDropdownItem.props = {
...DropdownItem.props,
checked: {
type: Boolean,
optional: false,
},
};
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="web.SearchDropdownItem" t-inherit="web.DropdownItem" t-inherit-mode="primary" owl="1">
<xpath expr="//t[@role='menuitem']" position="attributes">
<attribute name="role">menuitemcheckbox</attribute>
<attribute name="t-att-aria-checked">props.checked ? 'true' : 'false'</attribute>
</xpath>
</t>
</templates>
@@ -23,7 +23,7 @@
<div class="d-flex" data-menu="company" t-att-data-company-id="company.id">
<div
role="menuitemcheckbox"
t-att-aria-checked="isCompanySelected"
t-att-aria-checked="isCompanySelected ? 'true' : 'false'"
t-att-aria-label="company.name"
t-att-title="(isCompanySelected ? 'Hide ' : 'Show ') + company.name + ' content.'"
tabindex="0"
@@ -38,7 +38,7 @@
<div
role="button"
t-att-aria-pressed="isCurrent"
t-att-aria-pressed="isCurrent ? 'true' : 'false'"
t-att-aria-label="'Switch to ' + company.name "
t-att-title="'Switch to ' + company.name "
tabindex="0"
@@ -50,7 +50,7 @@ QUnit.module("Components", ({ beforeEach }) => {
await mount(Parent, target, { env });
assert.strictEqual(
target.querySelector(".dropdown").outerHTML,
'<div class="o-dropdown dropdown o-dropdown--no-caret"><button class="dropdown-toggle" tabindex="0"></button></div>'
'<div class="o-dropdown dropdown o-dropdown--no-caret"><button class="dropdown-toggle" tabindex="0" aria-expanded="false"></button></div>'
);
assert.containsOnce(target, "button.dropdown-toggle");
assert.containsNone(target, ".dropdown-menu");
@@ -64,7 +64,7 @@ QUnit.module("Components", ({ beforeEach }) => {
await mount(Parent, target, { env });
assert.strictEqual(
target.querySelector(".dropdown-item").outerHTML,
'<span class="dropdown-item" tabindex="0">coucou</span>'
'<span class="dropdown-item" role="menuitem" tabindex="0">coucou</span>'
);
});
@@ -76,7 +76,7 @@ QUnit.module("Components", ({ beforeEach }) => {
await mount(Parent, target, { env });
assert.strictEqual(
target.querySelector(".dropdown-item").outerHTML,
'<a class="dropdown-item" tabindex="0" href="#">coucou</a>'
'<a class="dropdown-item" role="menuitem" tabindex="0" href="#">coucou</a>'
);
});
@@ -132,7 +132,6 @@ QUnit.module("Components", ({ beforeEach }) => {
});
QUnit.test("menu can be toggled", async (assert) => {
assert.expect(5);
const beforeOpenProm = makeDeferred();
class Parent extends Component {
constructor() {
@@ -150,11 +149,15 @@ QUnit.module("Components", ({ beforeEach }) => {
await click(target, "button.dropdown-toggle");
assert.verifySteps(["beforeOpen"]);
assert.containsNone(target, ".dropdown-menu");
assert.strictEqual(target.querySelector("button.dropdown-toggle").ariaExpanded, "false");
beforeOpenProm.resolve();
await nextTick();
assert.containsOnce(target, ".dropdown-menu");
assert.strictEqual(target.querySelector(".dropdown-menu").getAttribute("role"), "menu");
assert.strictEqual(target.querySelector("button.dropdown-toggle").ariaExpanded, "true");
await click(target, "button.dropdown-toggle");
assert.containsNone(target, ".dropdown-menu");
assert.strictEqual(target.querySelector("button.dropdown-toggle").ariaExpanded, "false");
});
QUnit.test("initial open state can be true", async (assert) => {
@@ -760,9 +763,11 @@ QUnit.module("Components", ({ beforeEach }) => {
assert.containsOnce(target, ".dropdown");
assert.containsNone(target, ".dropdown .dropdown-menu");
assert.containsNone(target, ".dropdown button.dropdown-toggle");
assert.strictEqual(target.querySelector(".my_custom_toggler").ariaExpanded, "false");
await click(target, ".my_custom_toggler");
assert.containsOnce(target, ".dropdown .dropdown-menu");
assert.containsN(target, ".dropdown .dropdown-menu .dropdown-item", 2);
assert.strictEqual(target.querySelector(".my_custom_toggler").ariaExpanded, "true");
});
QUnit.test("props toggler='parent': refocus toggler on close with keynav", async (assert) => {
@@ -38,8 +38,6 @@ odoo.define('web.comparison_menu_tests', function (require) {
QUnit.module('ComparisonMenu (legacy)');
QUnit.test('simple rendering', async function (assert) {
assert.expect(6);
const unpatchDate = patchDate(1997, 0, 9, 12, 0, 0);
const params = {
cpModelConfig: this.cpModelConfig,
@@ -58,6 +56,12 @@ odoo.define('web.comparison_menu_tests', function (require) {
assert.strictEqual(controlPanel.el.querySelector('div.o_comparison_menu > button span').innerText.trim(), "Comparison");
await cpHelpers.toggleComparisonMenu(controlPanel);
assert.containsN(controlPanel.el, ".o_comparison_menu .dropdown-item", 2);
assert.containsN(
controlPanel.el,
".o_comparison_menu .dropdown-item[role=menuitemcheckbox]",
2
);
const comparisonOptions = [...controlPanel.el.querySelectorAll(
'.o_comparison_menu .o_menu_item'
@@ -67,13 +71,15 @@ odoo.define('web.comparison_menu_tests', function (require) {
comparisonOptions.map(e => e.innerText),
["Birthday: Previous Period", "Birthday: Previous Year"]
);
assert.deepEqual(
comparisonOptions.map((e) => e.ariaChecked),
["false", "false"]
);
unpatchDate();
});
QUnit.test('activate a comparison works', async function (assert) {
assert.expect(5);
const unpatchDate = patchDate(1997, 0, 9, 12, 0, 0);
const params = {
cpModelConfig: this.cpModelConfig,
@@ -113,6 +119,23 @@ odoo.define('web.comparison_menu_tests', function (require) {
await cpHelpers.toggleComparisonMenu(controlPanel);
await cpHelpers.toggleMenuItem(controlPanel, "Birthday: Previous Year");
assert.containsN(controlPanel.el, ".o_comparison_menu .dropdown-item", 2);
assert.containsN(
controlPanel.el,
".o_comparison_menu .dropdown-item[role=menuitemcheckbox]",
2
);
const comparisonOptions = [
...controlPanel.el.querySelectorAll(".o_comparison_menu .dropdown-item"),
];
assert.deepEqual(
comparisonOptions.map((e) => e.innerText.trim()),
["Birthday: Previous Period", "Birthday: Previous Year"]
);
assert.deepEqual(
comparisonOptions.map((e) => e.ariaChecked),
["false", "true"]
);
assert.deepEqual(cpHelpers.getFacetTexts(controlPanel), [
"Birthday: January 1997",
@@ -245,7 +245,7 @@ odoo.define('web.favorite_menu_tests', function (require) {
});
QUnit.test('delete an active favorite remove it both in list of favorite and in search bar', async function (assert) {
assert.expect(6);
assert.expect(9);
const favoriteFilters = [{
context: "{}",
@@ -276,6 +276,10 @@ odoo.define('web.favorite_menu_tests', function (require) {
const controlPanel = await createControlPanel(params);
await cpHelpers.toggleFavoriteMenu(controlPanel);
const favorite = controlPanel.el.querySelector(".o_favorite_menu .dropdown-item");
assert.equal(favorite.innerText, "My favorite");
assert.deepEqual(favorite.getAttribute("role"), "menuitemcheckbox");
assert.deepEqual(favorite.ariaChecked, "true");
const { domain } = controlPanel.getQuery();
assert.deepEqual(domain, [["foo", "=", "qsdf"]]);
@@ -321,7 +325,7 @@ odoo.define('web.favorite_menu_tests', function (require) {
});
QUnit.test('toggle favorite correctly clears filter, groupbys, comparison and field "options"', async function (assert) {
assert.expect(11);
assert.expect(15);
const unpatchDate = patchDate(2019, 6, 31, 13, 43, 0);
@@ -417,7 +421,12 @@ odoo.define('web.favorite_menu_tests', function (require) {
// activate the unique existing favorite
await cpHelpers.toggleFavoriteMenu(controlPanel);
const favorite = controlPanel.el.querySelector(".o_favorite_menu .dropdown-item");
assert.equal(favorite.innerText, "My favorite");
assert.deepEqual(favorite.getAttribute("role"), "menuitemcheckbox");
assert.deepEqual(favorite.ariaChecked, "false");
await cpHelpers.toggleMenuItem(controlPanel, 0);
assert.deepEqual(favorite.ariaChecked, "true");
assert.deepEqual(
cpHelpers.getFacetTexts(controlPanel),
@@ -40,8 +40,6 @@ odoo.define('web.filter_menu_tests', function (require) {
});
QUnit.test('simple rendering with a single filter', async function (assert) {
assert.expect(3);
const arch = `
<search>
<filter string="Foo" name="foo" domain="[]"/>
@@ -54,6 +52,8 @@ odoo.define('web.filter_menu_tests', function (require) {
await cpHelpers.toggleFilterMenu(controlPanel);
assert.containsOnce(controlPanel, '.o_menu_item');
assert.containsOnce(controlPanel, ".o_menu_item[role=menuitemcheckbox]");
assert.deepEqual(controlPanel.el.querySelector(".o_menu_item").ariaChecked, "false");
assert.containsOnce(controlPanel, '.dropdown-divider');
assert.containsOnce(controlPanel, 'div.o_add_custom_filter_menu');
});
@@ -75,7 +75,7 @@ odoo.define('web.filter_menu_tests', function (require) {
});
QUnit.test('toggle a "simple" filter in filter menu works', async function (assert) {
assert.expect(9);
assert.expect(12);
const domains = [
[['foo', '=', 'qsdf']],
@@ -99,7 +99,10 @@ odoo.define('web.filter_menu_tests', function (require) {
assert.deepEqual(cpHelpers.getFacetTexts(controlPanel), []);
assert.notOk(cpHelpers.isItemSelected(controlPanel, 0));
assert.containsOnce(controlPanel, ".o_menu_item[role=menuitemcheckbox]");
assert.deepEqual(controlPanel.el.querySelector(".o_menu_item").ariaChecked, "false");
await cpHelpers.toggleMenuItem(controlPanel, "Foo");
assert.deepEqual(controlPanel.el.querySelector(".o_menu_item").ariaChecked, "true");
assert.deepEqual(cpHelpers.getFacetTexts(controlPanel), ['Foo']);
assert.containsOnce(controlPanel.el.querySelector('.o_searchview .o_searchview_facet'),
@@ -68,8 +68,6 @@ odoo.define('web.groupby_menu_tests', function (require) {
});
QUnit.test('simple rendering with a single groupby', async function (assert) {
assert.expect(4);
const arch = `
<search>
<filter string="Groupby Foo" name="gb_foo" context="{'group_by': 'foo'}"/>
@@ -82,13 +80,16 @@ odoo.define('web.groupby_menu_tests', function (require) {
await cpHelpers.toggleGroupByMenu(controlPanel);
assert.containsOnce(controlPanel, '.o_menu_item');
assert.strictEqual(controlPanel.el.querySelector('.o_menu_item').innerText.trim(), "Groupby Foo");
const menuItem = controlPanel.el.querySelector(".o_menu_item");
assert.strictEqual(menuItem.innerText.trim(), "Groupby Foo");
assert.strictEqual(menuItem.getAttribute("role"), "menuitemcheckbox");
assert.strictEqual(menuItem.ariaChecked, "false");
assert.containsOnce(controlPanel, '.dropdown-divider');
assert.containsOnce(controlPanel, '.o_add_custom_group_menu');
});
QUnit.test('toggle a "simple" groupby in groupby menu works', async function (assert) {
assert.expect(9);
assert.expect(13);
const groupBys = [['foo'], []];
const arch = `
@@ -109,8 +110,13 @@ odoo.define('web.groupby_menu_tests', function (require) {
assert.deepEqual(cpHelpers.getFacetTexts(controlPanel), []);
assert.notOk(cpHelpers.isItemSelected(controlPanel, 0));
const menuItem = controlPanel.el.querySelector(".o_menu_item");
assert.strictEqual(menuItem.innerText.trim(), "Groupby Foo");
assert.strictEqual(menuItem.getAttribute("role"), "menuitemcheckbox");
assert.strictEqual(menuItem.ariaChecked, "false");
await cpHelpers.toggleMenuItem(controlPanel, 0);
assert.strictEqual(menuItem.ariaChecked, "true");
assert.deepEqual(cpHelpers.getFacetTexts(controlPanel), ['Groupby Foo']);
assert.containsOnce(controlPanel.el.querySelector('.o_searchview .o_searchview_facet'),
'span.oi.oi-group.o_searchview_facet_label');
@@ -47,7 +47,6 @@ QUnit.module("Search", (hooks) => {
QUnit.module("Comparison");
QUnit.test("simple rendering", async function (assert) {
assert.expect(6);
patchDate(1997, 0, 9, 12, 0, 0);
await makeWithSearch({
serverData,
@@ -70,16 +69,20 @@ QUnit.module("Search", (hooks) => {
"COMPARISON"
);
await toggleComparisonMenu(target);
assert.containsN(target, ".o_comparison_menu .dropdown-item", 2);
assert.containsN(target, ".o_comparison_menu .dropdown-item[role=menuitemcheckbox]", 2);
const comparisonOptions = [...target.querySelectorAll(".o_comparison_menu .dropdown-item")];
assert.strictEqual(comparisonOptions.length, 2);
assert.deepEqual(
comparisonOptions.map((e) => e.innerText.trim()),
["Birthday: Previous Period", "Birthday: Previous Year"]
);
assert.deepEqual(
comparisonOptions.map((e) => e.ariaChecked),
["false", "false"]
);
});
QUnit.test("activate a comparison works", async function (assert) {
assert.expect(5);
patchDate(1997, 0, 9, 12, 0, 0);
await makeWithSearch({
serverData,
@@ -112,6 +115,17 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getFacetTexts(target), ["Birthday: January 1997"]);
await toggleComparisonMenu(target);
await toggleMenuItem(target, "Birthday: Previous Year");
assert.containsN(target, ".o_comparison_menu .dropdown-item", 2);
assert.containsN(target, ".o_comparison_menu .dropdown-item[role=menuitemcheckbox]", 2);
const comparisonOptions = [...target.querySelectorAll(".o_comparison_menu .dropdown-item")];
assert.deepEqual(
comparisonOptions.map((e) => e.innerText.trim()),
["Birthday: Previous Period", "Birthday: Previous Year"]
);
assert.deepEqual(
comparisonOptions.map((e) => e.ariaChecked),
["false", "true"]
);
assert.deepEqual(getFacetTexts(target), [
"Birthday: January 1997",
"Birthday: Previous Year",
@@ -128,7 +128,7 @@ QUnit.module("Search", (hooks) => {
});
QUnit.test("delete an active favorite", async function (assert) {
assert.expect(11);
assert.expect(14);
class ToyController extends Component {
setup() {
@@ -183,6 +183,10 @@ QUnit.module("Search", (hooks) => {
});
await toggleFavoriteMenu(target);
const favorite = target.querySelector(".o_favorite_menu .dropdown-item");
assert.equal(favorite.innerText, "My favorite");
assert.deepEqual(favorite.getAttribute("role"), "menuitemcheckbox");
assert.deepEqual(favorite.ariaChecked, "true");
assert.deepEqual(getFacetTexts(target), ["My favorite"]);
assert.hasClass(target.querySelector(".o_favorite_menu .o_menu_item"), "selected");
@@ -235,8 +239,6 @@ QUnit.module("Search", (hooks) => {
QUnit.test(
'toggle favorite correctly clears filter, groupbys, comparison and field "options"',
async function (assert) {
assert.expect(11);
patchDate(2019, 6, 31, 13, 43, 0);
const controlPanel = await makeWithSearch({
@@ -327,7 +329,12 @@ QUnit.module("Search", (hooks) => {
// activate the unique existing favorite
await toggleFavoriteMenu(target);
const favorite = target.querySelector(".o_favorite_menu .dropdown-item");
assert.equal(favorite.innerText, "My favorite");
assert.deepEqual(favorite.getAttribute("role"), "menuitemcheckbox");
assert.deepEqual(favorite.ariaChecked, "false");
await toggleMenuItem(target, 0);
assert.deepEqual(favorite.ariaChecked, "true");
domain = controlPanel.env.searchModel.domain;
groupBy = controlPanel.env.searchModel.groupBy;
@@ -73,8 +73,6 @@ QUnit.module("Search", (hooks) => {
});
QUnit.test("simple rendering with a single filter", async function (assert) {
assert.expect(3);
await makeWithSearch({
serverData,
resModel: "foo",
@@ -90,13 +88,13 @@ QUnit.module("Search", (hooks) => {
await toggleFilterMenu(target);
assert.containsOnce(target, ".o_menu_item");
assert.containsOnce(target, ".o_menu_item[role=menuitemcheckbox]");
assert.deepEqual(target.querySelector(".o_menu_item").ariaChecked, "false");
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) {
assert.expect(10);
const controlPanel = await makeWithSearch({
serverData,
resModel: "foo",
@@ -114,8 +112,11 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(getFacetTexts(target), []);
assert.notOk(isItemSelected(target, "Foo"));
assert.deepEqual(getDomain(controlPanel), []);
assert.containsOnce(target, ".o_menu_item[role=menuitemcheckbox]");
assert.deepEqual(target.querySelector(".o_menu_item").ariaChecked, "false");
await toggleMenuItem(target, "Foo");
assert.deepEqual(target.querySelector(".o_menu_item").ariaChecked, "true");
assert.deepEqual(getFacetTexts(target), ["Foo"]);
assert.containsOnce(
@@ -87,8 +87,6 @@ QUnit.module("Search", (hooks) => {
});
QUnit.test("simple rendering with a single groupby", async function (assert) {
assert.expect(4);
await makeWithSearch({
serverData,
resModel: "foo",
@@ -105,14 +103,15 @@ QUnit.module("Search", (hooks) => {
await toggleGroupByMenu(target);
assert.containsOnce(target, ".o_menu_item");
assert.strictEqual(target.querySelector(".o_menu_item").innerText.trim(), "Foo");
const menuItem = target.querySelector(".o_menu_item");
assert.strictEqual(menuItem.innerText.trim(), "Foo");
assert.strictEqual(menuItem.getAttribute("role"), "menuitemcheckbox");
assert.strictEqual(menuItem.ariaChecked, "false");
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) {
assert.expect(10);
const controlPanel = await makeWithSearch({
serverData,
resModel: "foo",
@@ -131,8 +130,12 @@ QUnit.module("Search", (hooks) => {
assert.deepEqual(controlPanel.env.searchModel.groupBy, []);
assert.deepEqual(getFacetTexts(target), []);
assert.notOk(isItemSelected(target, "Foo"));
const menuItem = target.querySelector(".o_menu_item");
assert.strictEqual(menuItem.innerText.trim(), "Foo");
assert.strictEqual(menuItem.getAttribute("role"), "menuitemcheckbox");
assert.strictEqual(menuItem.ariaChecked, "false");
await toggleMenuItem(target, "Foo");
assert.strictEqual(menuItem.ariaChecked, "true");
assert.deepEqual(controlPanel.env.searchModel.groupBy, ["foo"]);
assert.deepEqual(getFacetTexts(target), ["Foo"]);
@@ -78,8 +78,6 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
});
QUnit.test("companies can be toggled: toggle a second company", async (assert) => {
assert.expect(10);
const prom = makeDeferred();
function onPushState(url) {
assert.step(url.split("#")[1]);
@@ -98,6 +96,16 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
assert.containsN(target, "[data-company-id]", 3);
assert.containsN(target, "[data-company-id] .fa-check-square", 1);
assert.containsN(target, "[data-company-id] .fa-square-o", 2);
assert.deepEqual(
[...target.querySelectorAll("[data-company-id] .toggle_company")].map(
(el) => el.ariaChecked
),
["true", "false", "false"]
);
assert.deepEqual(
[...target.querySelectorAll("[data-company-id] .log_into")].map((el) => el.ariaPressed),
["true", "false", "false"]
);
/**
* [x] **Hermit**
@@ -108,6 +116,16 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
assert.containsOnce(target, ".dropdown-menu", "dropdown is still opened");
assert.containsN(target, "[data-company-id] .fa-check-square", 2);
assert.containsN(target, "[data-company-id] .fa-square-o", 1);
assert.deepEqual(
[...target.querySelectorAll("[data-company-id] .toggle_company")].map(
(el) => el.ariaChecked
),
["true", "true", "false"]
);
assert.deepEqual(
[...target.querySelectorAll("[data-company-id] .log_into")].map((el) => el.ariaPressed),
["true", "false", "false"]
);
await prom;
assert.verifySteps(["cids=3%2C2"]);
});