19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:27 +01:00
parent d1963a3c3a
commit 2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions

View file

@ -1,5 +1,6 @@
import { expect, test } from "@odoo/hoot";
import {
advanceTime,
clear,
click,
edit,
@ -12,7 +13,7 @@ import {
queryFirst,
runAllTimers,
} from "@odoo/hoot-dom";
import { Deferred, animationFrame, mockTimeZone } from "@odoo/hoot-mock";
import { Deferred, animationFrame, mockTimeZone, mockTouch } from "@odoo/hoot-mock";
import { Component, onWillUpdateProps, xml } from "@odoo/owl";
import {
SELECTORS,
@ -46,7 +47,7 @@ import {
validateSearch,
} from "@web/../tests/web_test_helpers";
import { cookie } from "@web/core/browser/cookie";
import { SearchBar } from "@web/search/search_bar/search_bar";
import { SearchBar, DROPDOWN_CLOSE_DELAY } from "@web/search/search_bar/search_bar";
import { useSearchBarToggler } from "@web/search/search_bar/search_bar_toggler";
class Partner extends models.Model {
name = fields.Char();
@ -215,6 +216,45 @@ test("navigation with facets (2)", async () => {
expect(queryFirst`.o_searchview .o_searchview_facet:nth-child(1)`).toBeFocused();
});
test.tags("desktop");
test("navigation should move forward from search bar filter", async () => {
await mountWithSearch(SearchBar, {
resModel: "partner",
searchMenuTypes: ["groupBy"],
searchViewId: false,
context: { search_default_date_group_by: 1 },
});
expect(`.o_searchview .o_searchview_facet`).toHaveCount(1);
expect(queryFirst`.o_searchview input`).toBeFocused();
// press tab to navigate forward to the toggler
await keyDown("Tab");
await animationFrame();
expect(queryFirst`.o_searchview_dropdown_toggler`).toBeFocused();
});
test.tags("desktop");
test("navigation should move backward from search bar filter", async () => {
await mountWithSearch(SearchBar, {
resModel: "partner",
searchMenuTypes: ["groupBy"],
searchViewId: false,
context: { search_default_date_group_by: 1 },
});
expect(`.o_searchview .o_searchview_facet`).toHaveCount(1);
expect(queryFirst`.o_searchview input`).toBeFocused();
// press shift+tab to navigate backward to the search icon button
await keyDown("Shift");
await press("Tab");
await animationFrame();
await press("Tab");
await animationFrame();
expect(queryFirst`.d-print-none.btn`).toBeFocused();
});
test.tags("mobile");
test("search input is focused when being toggled", async () => {
class Parent extends Component {
@ -241,6 +281,18 @@ test("search input is focused when being toggled", async () => {
expect(queryFirst`.o_searchview input`).toBeFocused();
});
test.tags("desktop");
test("search input is not focused on larger touch devices", async () => {
mockTouch(true);
await mountWithSearch(SearchBar, {
resModel: "partner",
searchMenuTypes: [],
searchViewId: false,
});
expect(".o_searchview input").toHaveCount(1);
expect(".o_searchview input").not.toBeFocused();
});
test("search date and datetime fields. Support of timezones", async () => {
mockTimeZone(6);
@ -483,6 +535,44 @@ test("update suggested filters in autocomplete menu with Japanese IME", async ()
);
});
test("intermediate Backspace events from iOS Korean IME shouldn't close autocomplete", async () => {
// This test simulates the behavior of the iOS Korean IME during composition.
// On iOS, `isComposing` is not set, but the IME sends a Backspace before
// rewriting the composing syllable. Our component (SearchBar) must handle
// this without closing the autocomplete dropdown.
// Typing 'ㄱ' followed by 'ㅏ' produces the precomposed syllable '가'.
const COMPOSED_SYLLABLE = "가";
await mountWithSearch(SearchBar, {
resModel: "partner",
searchMenuTypes: [],
searchViewId: false,
});
await click(".o_searchview input");
// User types the initial consonant 'ㄱ'
await press("ㄱ");
// Wait search autocomplete
await animationFrame();
// User types the second character 'ㅏ'
// iOS sends Backspace to remove previous char and inserts the precomposed syllable
await press("Backspace");
await press("가");
// Autocomplete should remain open even after composition with backspace.
await animationFrame();
await advanceTime(DROPDOWN_CLOSE_DELAY);
await animationFrame();
expect(queryFirst`.o_searchview input`).toHaveValue(COMPOSED_SYLLABLE);
expect(`.o_searchview_autocomplete .o-dropdown-item:first`).toHaveText(
`Search Foo for: ${COMPOSED_SYLLABLE}`
);
});
test("open search view autocomplete on paste value using mouse", async () => {
await mountWithSearch(SearchBar, {
resModel: "partner",
@ -1028,6 +1118,8 @@ test("search a property", async () => {
// search for a partner, and expand the many2many property
await contains(`.o_searchview_input`).clear();
// wait for autocomplete to close to make sure it updates its state
await advanceTime(DROPDOWN_CLOSE_DELAY);
await editSearch("Bo");
await contains(".o_expand").click();
await contains(".o_searchview_autocomplete .o-dropdown-item:nth-child(3) .o_expand").click();
@ -1927,3 +2019,21 @@ test("no crash when search component is destroyed with input", async () => {
await runAllTimers();
expect(".o_form_view").toHaveCount(1);
});
test("search on full query without waiting for display synchronisation", async () => {
/* Typically a barcode scan where the dropdown display doesn't have the time to update */
const searchBar = await mountWithSearch(SearchBar, {
resModel: "partner",
searchMenuTypes: [],
searchViewId: false,
});
await editSearch("01234");
expect(".o-dropdown-item:first").toHaveText("Search Foo for: 01234");
await press("5");
expect(".o-dropdown-item:first").toHaveText("Search Foo for: 01234");
await press("6");
expect(".o-dropdown-item:first").toHaveText("Search Foo for: 01234");
await keyDown("Enter");
expect(searchBar.env.searchModel.domain).toEqual([["foo", "ilike", "0123456"]]);
});