diff --git a/addons/crm/static/tests/crm_rainbowman_tests.js b/addons/crm/static/tests/crm_rainbowman_tests.js index 7dec19e7574..5c7fc10ab48 100644 --- a/addons/crm/static/tests/crm_rainbowman_tests.js +++ b/addons/crm/static/tests/crm_rainbowman_tests.js @@ -7,9 +7,7 @@ import { dragAndDrop, getFixture, } from '@web/../tests/helpers/utils'; -import testUtils from 'web.test_utils'; import { serializeDateTime } from "@web/core/l10n/dates"; -const find = testUtils.dom.find; let target; @@ -222,7 +220,7 @@ QUnit.module('Crm Rainbowman Triggers', { mockRPC: getMockRpc(assert), }); - await dragAndDrop(find(target, ".o_kanban_record", "Lead 6"), target.querySelector('.o_kanban_group:nth-of-type(3)')); + await dragAndDrop($(target).find(".o_kanban_record:contains(Lead 6)")[0], target.querySelector('.o_kanban_group:nth-of-type(3)')); assert.verifySteps(['Go, go, go! Congrats for your first deal.']); }); @@ -234,7 +232,7 @@ QUnit.module('Crm Rainbowman Triggers', { mockRPC: getMockRpc(assert), }); - await dragAndDrop(find(target, ".o_kanban_record", "Lead 2"), target.querySelector('.o_kanban_group:nth-of-type(3)')); + await dragAndDrop($(target).find(".o_kanban_record:contains(Lead 2)")[0], target.querySelector('.o_kanban_group:nth-of-type(3)')); assert.verifySteps(['Boom! Team record for the past 30 days.']); }); @@ -246,7 +244,7 @@ QUnit.module('Crm Rainbowman Triggers', { mockRPC: getMockRpc(assert), }); - await dragAndDrop(find(target, ".o_kanban_record", "Lead 1"), target.querySelector('.o_kanban_group:nth-of-type(3)')); + await dragAndDrop($(target).find(".o_kanban_record:contains(Lead 1)")[0], target.querySelector('.o_kanban_group:nth-of-type(3)')); assert.verifySteps(['Yeah! Deal of the last 7 days for the team.']); }); @@ -258,7 +256,7 @@ QUnit.module('Crm Rainbowman Triggers', { mockRPC: getMockRpc(assert), }); - await dragAndDrop(find(target, ".o_kanban_record", "Lead 8"), target.querySelector('.o_kanban_group:nth-of-type(3)')); + await dragAndDrop($(target).find(".o_kanban_record:contains(Lead 8)")[0], target.querySelector('.o_kanban_group:nth-of-type(3)')); assert.verifySteps(['You just beat your personal record for the past 30 days.']); }); @@ -270,7 +268,7 @@ QUnit.module('Crm Rainbowman Triggers', { mockRPC: getMockRpc(assert), }); - await dragAndDrop(find(target, ".o_kanban_record", "Lead 10"), target.querySelector('.o_kanban_group:nth-of-type(3)')); + await dragAndDrop($(target).find(".o_kanban_record:contains(Lead 10)")[0], target.querySelector('.o_kanban_group:nth-of-type(3)')); assert.verifySteps(['You just beat your personal record for the past 7 days.']); }); @@ -282,7 +280,7 @@ QUnit.module('Crm Rainbowman Triggers', { mockRPC: getMockRpc(assert), }); - await dragAndDrop(find(target, ".o_kanban_record", "Lead 8"), target.querySelector('.o_kanban_group:nth-of-type(2)')); + await dragAndDrop($(target).find(".o_kanban_record:contains(Lead 8)")[0], target.querySelector('.o_kanban_group:nth-of-type(2)')); assert.verifySteps(["no rainbowman"]); }); diff --git a/addons/crm/static/tests/forecast_kanban_tests.js b/addons/crm/static/tests/forecast_kanban_tests.js index 7fa63f063b7..c89ad9fb238 100644 --- a/addons/crm/static/tests/forecast_kanban_tests.js +++ b/addons/crm/static/tests/forecast_kanban_tests.js @@ -8,8 +8,6 @@ import { getFixture, patchDate, } from '@web/../tests/helpers/utils'; -import testUtils from 'web.test_utils'; -const find = testUtils.dom.find; const serviceRegistry = registry.category("services"); @@ -85,7 +83,7 @@ QUnit.module('Crm Forecast Model Extension', { "2nd column March should contain 2 records"); // remove the filter - await click(find(target, '.o_searchview_facet', "Forecast"), '.o_facet_remove'); + await click($(target).find(".o_searchview_facet:contains(Forecast)")[0], ".o_facet_remove"); assert.containsN(target, '.o_kanban_group', 3, "There should be 3 columns"); assert.containsN(target, '.o_kanban_group:nth-child(1) .o_kanban_record', 2, @@ -118,7 +116,7 @@ QUnit.module('Crm Forecast Model Extension', { "2nd column March should contain 2 records"); // remove the filter - await click(find(target, '.o_searchview_facet', "Forecast"), '.o_facet_remove'); + await click($(target).find(".o_searchview_facet:contains(Forecast)")[0], ".o_facet_remove"); assert.containsN(target, '.o_kanban_group', 3, "There should be 3 columns"); assert.containsN(target, '.o_kanban_group:nth-child(1) .o_kanban_record', 2, diff --git a/addons/point_of_sale/static/tests/unit/number_buffer_service_tests.js b/addons/point_of_sale/static/tests/unit/number_buffer_service_tests.js index 437a2fb8a0a..faec50eb6cd 100644 --- a/addons/point_of_sale/static/tests/unit/number_buffer_service_tests.js +++ b/addons/point_of_sale/static/tests/unit/number_buffer_service_tests.js @@ -1,13 +1,12 @@ /** @odoo-module */ import testUtils from "web.test_utils"; -import { mount } from "@web/../tests/helpers/utils"; +import { makeTestEnv } from "@web/../tests/helpers/mock_env"; +import { getFixture, mount } from "@web/../tests/helpers/utils"; import { useService } from "@web/core/utils/hooks"; import { numberBufferService } from "@point_of_sale/app/utils/number_buffer_service"; import { registry } from "@web/core/registry"; -import { makeTestEnv } from "@web/../tests/helpers/mock_env"; - import { Component, useState, xml } from "@odoo/owl"; QUnit.module("unit tests for NumberBuffer", { @@ -19,7 +18,7 @@ QUnit.module("unit tests for NumberBuffer", { QUnit.test("simple fast inputs with capture in between", async function (assert) { assert.expect(3); - const target = testUtils.prepareTarget(); + const target = getFixture(); const env = await makeTestEnv(); class Root extends Component { diff --git a/addons/web/static/tests/legacy/core/popover_tests.js b/addons/web/static/tests/legacy/core/popover_tests.js index 26e58d90728..83fdfc9f48e 100644 --- a/addons/web/static/tests/legacy/core/popover_tests.js +++ b/addons/web/static/tests/legacy/core/popover_tests.js @@ -3,7 +3,7 @@ import makeTestEnvironment from "web.test_env"; import Popover from "web.Popover"; import testUtils from "web.test_utils"; - import { click, mount } from "@web/../tests/helpers/utils"; + import { click, getFixture, mount } from "@web/../tests/helpers/utils"; import { LegacyComponent } from "@web/legacy/legacy_component"; const { useState, xml } = owl; @@ -46,7 +46,7 @@ `; - const target = testUtils.prepareTarget(); + const target = getFixture(); const env = makeTestEnvironment(); /** @@ -164,7 +164,7 @@ 💀 `; - const target = testUtils.prepareTarget(); + const target = getFixture(); const env = makeTestEnvironment(); const body = document.querySelector('body'); @@ -204,7 +204,7 @@ `; Parent.components = { Popover }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const env = makeTestEnvironment(); await mount(Parent, target, { env }); @@ -248,7 +248,7 @@ `; - const target = testUtils.prepareTarget(); + const target = getFixture(); const env = makeTestEnvironment(); await mount(Parent, target, { env }); diff --git a/addons/web/static/tests/legacy/helpers/test_utils.js b/addons/web/static/tests/legacy/helpers/test_utils.js index 8ca657a35bb..ca1c1723304 100644 --- a/addons/web/static/tests/legacy/helpers/test_utils.js +++ b/addons/web/static/tests/legacy/helpers/test_utils.js @@ -4,23 +4,14 @@ * Test Utils * * In this module, we define various utility functions to help simulate a mock - * environment as close as possible as a real environment. The main function is - * certainly createView, which takes a bunch of parameters and give you back an - * instance of a view, appended in the dom, ready to be tested. + * environment as close as possible as a real environment. */ - import testUtilsCreate from "web.test_utils_create"; - import testUtilsControlPanel from "web.test_utils_control_panel"; import testUtilsDom from "web.test_utils_dom"; import testUtilsFields from "web.test_utils_fields"; import testUtilsFile from "web.test_utils_file"; - import testUtilsForm from "web.test_utils_form"; - import testUtilsGraph from "web.test_utils_graph"; - import testUtilsKanban from "web.test_utils_kanban"; import testUtilsMock from "web.test_utils_mock"; - import testUtilsModal from "web.test_utils_modal"; - import testUtilsPivot from "web.test_utils_pivot"; - + import Widget from "web.Widget"; function deprecated(fn, type) { return function () { @@ -31,6 +22,19 @@ }; } + /** + * Create a widget parent from given parameters. + * + * @param {Object} params This object will be given to addMockEnvironment, so + * any parameters from that method applies + * @returns {Promise} + */ + async function createParent(params) { + const widget = new Widget(); + await testUtilsMock.addMockEnvironment(widget, params); + return widget; + } + /** * Helper function, make a promise with a public resolve function. Note that * this is not standard and should not be used outside of tests... @@ -94,25 +98,6 @@ return testUtilsDom.returnAfterNextAnimationFrame(); } - /** - * Awaits for an additionnal rendering frame initiated by the Owl - * compatibility layer processing. - * - * By default a simple "nextTick" will handle the rendering of any widget/ - * component stuctures having at most 1 switch between the type of - * entities (Component > Widget or Widget > Component). However more time - * must be spent rendering in case we have additionnal switches. In such - * cases this function must be used (1 call for each additionnal switch) - * since it will be removed along with the compatiblity layer once the - * framework has been entirely converted, and using this helper will make - * it easier to wipe it from the code base. - * - * @returns {Promise} - */ - async function owlCompatibilityExtraNextTick() { - return testUtilsDom.returnAfterNextAnimationFrame(); - } - export default { mock: { addMockEnvironment: testUtilsMock.addMockEnvironment, @@ -122,106 +107,19 @@ patchDate: testUtilsMock.patchDate, unpatch: testUtilsMock.unpatch, getView: testUtilsMock.getView, - patchSetTimeout: testUtilsMock.patchSetTimeout, - }, - controlPanel: { - // Generic interactions - toggleMenu: testUtilsControlPanel.toggleMenu, - toggleMenuItem: testUtilsControlPanel.toggleMenuItem, - toggleMenuItemOption: testUtilsControlPanel.toggleMenuItemOption, - isItemSelected: testUtilsControlPanel.isItemSelected, - isOptionSelected: testUtilsControlPanel.isOptionSelected, - getMenuItemTexts: testUtilsControlPanel.getMenuItemTexts, - // Button interactions - getButtons: testUtilsControlPanel.getButtons, - // FilterMenu interactions - toggleFilterMenu: testUtilsControlPanel.toggleFilterMenu, - toggleAddCustomFilter: testUtilsControlPanel.toggleAddCustomFilter, - applyFilter: testUtilsControlPanel.applyFilter, - addCondition: testUtilsControlPanel.addCondition, - // GroupByMenu interactions - toggleGroupByMenu: testUtilsControlPanel.toggleGroupByMenu, - toggleAddCustomGroup: testUtilsControlPanel.toggleAddCustomGroup, - selectGroup: testUtilsControlPanel.selectGroup, - applyGroup: testUtilsControlPanel.applyGroup, - // FavoriteMenu interactions - toggleFavoriteMenu: testUtilsControlPanel.toggleFavoriteMenu, - toggleSaveFavorite: testUtilsControlPanel.toggleSaveFavorite, - editFavoriteName: testUtilsControlPanel.editFavoriteName, - saveFavorite: testUtilsControlPanel.saveFavorite, - deleteFavorite: testUtilsControlPanel.deleteFavorite, - // ComparisonMenu interactions - toggleComparisonMenu: testUtilsControlPanel.toggleComparisonMenu, - // SearchBar interactions - getFacetTexts: testUtilsControlPanel.getFacetTexts, - removeFacet: testUtilsControlPanel.removeFacet, - editSearch: testUtilsControlPanel.editSearch, - validateSearch: testUtilsControlPanel.validateSearch, - // Action menus interactions - toggleActionMenu: testUtilsControlPanel.toggleActionMenu, - // Pager interactions - pagerPrevious: testUtilsControlPanel.pagerPrevious, - pagerNext: testUtilsControlPanel.pagerNext, - getPagerValue: testUtilsControlPanel.getPagerValue, - getPagerSize: testUtilsControlPanel.getPagerSize, - setPagerValue: testUtilsControlPanel.setPagerValue, - // View switcher - switchView: testUtilsControlPanel.switchView, }, dom: { - triggerKeypressEvent: testUtilsDom.triggerKeypressEvent, - triggerMouseEvent: testUtilsDom.triggerMouseEvent, - triggerPositionalMouseEvent: testUtilsDom.triggerPositionalMouseEvent, - triggerPositionalTapEvents: testUtilsDom.triggerPositionalTapEvents, dragAndDrop: testUtilsDom.dragAndDrop, find: testUtilsDom.findItem, - getNode: testUtilsDom.getNode, - openDatepicker: testUtilsDom.openDatepicker, click: testUtilsDom.click, clickFirst: testUtilsDom.clickFirst, - clickLast: testUtilsDom.clickLast, triggerEvents: testUtilsDom.triggerEvents, triggerEvent: testUtilsDom.triggerEvent, }, - form: { - clickEdit: testUtilsForm.clickEdit, - clickSave: testUtilsForm.clickSave, - clickCreate: testUtilsForm.clickCreate, - clickDiscard: testUtilsForm.clickDiscard, - reload: testUtilsForm.reload, - }, - graph: { - reload: testUtilsGraph.reload, - }, - kanban: { - reload: testUtilsKanban.reload, - clickCreate: testUtilsKanban.clickCreate, - quickCreate: testUtilsKanban.quickCreate, - toggleGroupSettings: testUtilsKanban.toggleGroupSettings, - toggleRecordDropdown: testUtilsKanban.toggleRecordDropdown, - }, - modal: { - clickButton: testUtilsModal.clickButton, - }, - pivot: { - clickMeasure: testUtilsPivot.clickMeasure, - toggleMeasuresDropdown: testUtilsPivot.toggleMeasuresDropdown, - reload: testUtilsPivot.reload, - }, fields: { - many2one: { - createAndEdit: testUtilsFields.clickM2OCreateAndEdit, - clickOpenDropdown: testUtilsFields.clickOpenM2ODropdown, - clickHighlightedItem: testUtilsFields.clickM2OHighlightedItem, - clickItem: testUtilsFields.clickM2OItem, - searchAndClickItem: testUtilsFields.searchAndClickM2OItem, - }, editInput: testUtilsFields.editInput, - editSelect: testUtilsFields.editSelect, editAndTrigger: testUtilsFields.editAndTrigger, - triggerKey: testUtilsFields.triggerKey, triggerKeydown: testUtilsFields.triggerKeydown, - triggerKeyup: testUtilsFields.triggerKeyup, }, file: { createFile: testUtilsFile.createFile, @@ -231,19 +129,11 @@ inputFiles: testUtilsFile.inputFiles, }, - createComponent: testUtilsCreate.createComponent, - createAsyncView: testUtilsCreate.createView, - createCalendarView: testUtilsCreate.createCalendarView, - createView: testUtilsCreate.createView, - createModel: testUtilsCreate.createModel, - createParent: testUtilsCreate.createParent, + createParent, makeTestPromise: makeTestPromise, makeTestPromiseWithAssert: makeTestPromiseWithAssert, nextMicrotaskTick: nextMicrotaskTick, nextTick: nextTick, - owlCompatibilityExtraNextTick, - prepareTarget: testUtilsCreate.prepareTarget, - returnAfterNextAnimationFrame: testUtilsDom.returnAfterNextAnimationFrame, // backward-compatibility addMockEnvironment: deprecated(testUtilsMock.addMockEnvironment, 'mock'), @@ -253,8 +143,5 @@ openDatepicker: deprecated(testUtilsDom.openDatepicker, 'dom'), patch: deprecated(testUtilsMock.patch, 'mock'), patchDate: deprecated(testUtilsMock.patchDate, 'mock'), - triggerKeypressEvent: deprecated(testUtilsDom.triggerKeypressEvent, 'dom'), - triggerMouseEvent: deprecated(testUtilsDom.triggerMouseEvent, 'dom'), - triggerPositionalMouseEvent: deprecated(testUtilsDom.triggerPositionalMouseEvent, 'dom'), unpatch: deprecated(testUtilsMock.unpatch, 'mock'), }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_control_panel.js b/addons/web/static/tests/legacy/helpers/test_utils_control_panel.js deleted file mode 100644 index 8c13fbb809a..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_control_panel.js +++ /dev/null @@ -1,358 +0,0 @@ -/** @odoo-module alias=web.test_utils_control_panel **/ - - import { click, findItem, getNode, triggerEvent } from "web.test_utils_dom"; - import { editInput, editSelect, editAndTrigger } from "web.test_utils_fields"; - - //------------------------------------------------------------------------- - // Exported functions - //------------------------------------------------------------------------- - - /** - * @param {EventTarget} el - * @param {(number|string)} menuFinder - * @returns {Promise} - */ - async function toggleMenu(el, menuFinder) { - const menu = findItem(el, `.dropdown > button`, menuFinder); - await click(menu); - } - - /** - * @param {EventTarget} el - * @param {(number|string)} itemFinder - * @returns {Promise} - */ - async function toggleMenuItem(el, itemFinder) { - const item = findItem(el, `.o_menu_item > a`, itemFinder); - await click(item); - } - - /** - * @param {EventTarget} el - * @param {(number|string)} itemFinder - * @param {(number|string)} optionFinder - * @returns {Promise} - */ - async function toggleMenuItemOption(el, itemFinder, optionFinder) { - const item = findItem(el, `.o_menu_item > a`, itemFinder); - const option = findItem(item.parentNode, '.o_item_option > a', optionFinder); - await click(option); - } - - /** - * @param {EventTarget} el - * @param {(number|string)} itemFinder - * @returns {boolean} - */ - function isItemSelected(el, itemFinder) { - const item = findItem(el, `.o_menu_item > a`, itemFinder); - return item.classList.contains('selected'); - } - - /** - * @param {EventTarget} el - * @param {(number|string)} itemuFinder - * @param {(number|string)} optionFinder - * @returns {boolean} - */ - function isOptionSelected(el, itemFinder, optionFinder) { - const item = findItem(el, `.o_menu_item > a`, itemFinder); - const option = findItem(item.parentNode, '.o_item_option > a', optionFinder); - return option.classList.contains('selected'); - } - - /** - * @param {EventTarget} el - * @returns {string[]} - */ - function getMenuItemTexts(el) { - return [...getNode(el).querySelectorAll(`.dropdown ul .o_menu_item`)].map( - e => e.innerText.trim() - ); - } - - /** - * @param {EventTarget} el - * @returns {HTMLButtonElement[]} - */ - function getButtons(el) { - return [...getNode(el).querySelector((`div.o_cp_bottom div.o_cp_buttons`)).children]; - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleFilterMenu(el) { - await click(getNode(el).querySelector(`.o_filter_menu button`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleAddCustomFilter(el) { - await click(getNode(el).querySelector(`button.o_add_custom_filter`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function applyFilter(el) { - await click(getNode(el).querySelector(`div.o_add_filter_menu > button.o_apply_filter`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function addCondition(el) { - await click(getNode(el).querySelector(`div.o_add_filter_menu > button.o_add_condition`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleGroupByMenu(el) { - await click(getNode(el).querySelector(`.o_group_by_menu button`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleAddCustomGroup(el) { - await click(getNode(el).querySelector(`span.o_add_custom_group_by`)); - } - - /** - * @param {EventTarget} el - * @param {string} fieldName - * @returns {Promise} - */ - async function selectGroup(el, fieldName) { - await editSelect( - getNode(el).querySelector(`select.o_group_by_selector`), - fieldName - ); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function applyGroup(el) { - await click(getNode(el).querySelector(`div.o_add_group_by_menu > button.o_apply_group_by`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleFavoriteMenu(el) { - await click(getNode(el).querySelector(`.o_favorite_menu button`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleSaveFavorite(el) { - await click(getNode(el).querySelector(`.o_favorite_menu .o_add_favorite .dropdown-item`)); - } - - /** - * @param {EventTarget} el - * @param {string} name - * @returns {Promise} - */ - async function editFavoriteName(el, name) { - await editInput(getNode(el).querySelector(`.o_favorite_menu .o_add_favorite input[type="text"]`), name); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function saveFavorite(el) { - await click(getNode(el).querySelector(`.o_favorite_menu .o_add_favorite button.o_save_favorite`)); - } - - /** - * @param {EventTarget} el - * @param {(string|number)} favoriteFinder - * @returns {Promise} - */ - async function deleteFavorite(el, favoriteFinder) { - const favorite = findItem(el, `.o_favorite_menu .o_menu_item`, favoriteFinder); - await click(favorite.querySelector('i.fa-trash')); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function toggleComparisonMenu(el) { - await click(getNode(el).querySelector(`div.o_comparison_menu > button`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - function getFacetTexts(el) { - return [...getNode(el).querySelectorAll(`.o_searchview .o_searchview_facet`)].map( - facet => facet.innerText.trim() - ); - } - - /** - * @param {EventTarget} el - * @param {(string|number)} facetFinder - * @returns {Promise} - */ - async function removeFacet(el, facetFinder = 0) { - const facet = findItem(el, `.o_searchview .o_searchview_facet`, facetFinder); - await click(facet.querySelector('.o_facet_remove')); - } - - /** - * @param {EventTarget} el - * @param {string} value - * @returns {Promise} - */ - async function editSearch(el, value) { - await editInput(getNode(el).querySelector(`.o_searchview_input`), value); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function validateSearch(el) { - await triggerEvent( - getNode(el).querySelector(`.o_searchview_input`), - 'keydown', { key: 'Enter' } - ); - } - - /** - * @param {EventTarget} el - * @param {string} [menuFinder="Action"] - * @returns {Promise} - */ - async function toggleActionMenu(el, menuFinder = "Action") { - const dropdown = findItem(el, `.o_cp_action_menus button`, menuFinder); - await click(dropdown); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function pagerPrevious(el) { - await click(getNode(el).querySelector(`.o_pager button.o_pager_previous`)); - } - - /** - * @param {EventTarget} el - * @returns {Promise} - */ - async function pagerNext(el) { - await click(getNode(el).querySelector(`.o_pager button.o_pager_next`)); - } - - /** - * @param {EventTarget} el - * @returns {string} - */ - function getPagerValue(el) { - const pagerValue = getNode(el).querySelector(`.o_pager_counter .o_pager_value`); - switch (pagerValue.tagName) { - case 'INPUT': - return pagerValue.value; - case 'SPAN': - return pagerValue.innerText.trim(); - } - } - - /** - * @param {EventTarget} el - * @returns {string} - */ - function getPagerSize(el) { - return getNode(el).querySelector(`.o_pager_counter span.o_pager_limit`).innerText.trim(); - } - - /** - * @param {EventTarget} el - * @param {string} value - * @returns {Promise} - */ - async function setPagerValue(el, value) { - let pagerValue = getNode(el).querySelector(`.o_pager_counter .o_pager_value`); - if (pagerValue.tagName === 'SPAN') { - await click(pagerValue); - } - pagerValue = getNode(el).querySelector(`.o_pager_counter input.o_pager_value`); - if (!pagerValue) { - throw new Error("Pager value is being edited and cannot be changed."); - } - await editAndTrigger(pagerValue, value, ['change', 'blur']); - } - - /** - * @param {EventTarget} el - * @param {string} viewType - * @returns {Promise} - */ - async function switchView(el, viewType) { - await click(getNode(el).querySelector(`button.o_switch_view.o_${viewType}`)); - } - - export default { - // Generic interactions - toggleMenu, - toggleMenuItem, - toggleMenuItemOption, - isItemSelected, - isOptionSelected, - getMenuItemTexts, - // Button interactions - getButtons, - // FilterMenu interactions - toggleFilterMenu, - toggleAddCustomFilter, - applyFilter, - addCondition, - // GroupByMenu interactions - toggleGroupByMenu, - toggleAddCustomGroup, - selectGroup, - applyGroup, - // FavoriteMenu interactions - toggleFavoriteMenu, - toggleSaveFavorite, - editFavoriteName, - saveFavorite, - deleteFavorite, - // ComparisonMenu interactions - toggleComparisonMenu, - // SearchBar interactions - getFacetTexts, - removeFacet, - editSearch, - validateSearch, - // Action menus interactions - toggleActionMenu, - // Pager interactions - pagerPrevious, - pagerNext, - getPagerValue, - getPagerSize, - setPagerValue, - // View switcher - switchView, - }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_create.js b/addons/web/static/tests/legacy/helpers/test_utils_create.js deleted file mode 100644 index 4a7bff0ffc8..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_create.js +++ /dev/null @@ -1,297 +0,0 @@ -/** @odoo-module alias=web.test_utils_create **/ - - /** - * Create Test Utils - * - * This module defines various utility functions to help creating mock widgets - * - * Note that all methods defined in this module are exported in the main - * testUtils file. - */ - - import concurrency from "web.concurrency"; - import { useListener } from "@web/core/utils/hooks"; - import dom from "web.dom"; - import testUtilsMock from "web.test_utils_mock"; - import Widget from "web.Widget"; - import { destroy, getFixture, mount, useChild } from "@web/../tests/helpers/utils"; - import { registerCleanup } from "@web/../tests/helpers/cleanup"; - import { LegacyComponent } from "@web/legacy/legacy_component"; - - const { Component, useState, xml } = owl; - - /** - * Similar as createView, but specific for calendar views. Some calendar - * tests need to trigger positional clicks on the DOM produced by fullcalendar. - * Those tests must use this helper with option positionalClicks set to true. - * This will move the rendered calendar to the body (required to do positional - * clicks), and wait for a setTimeout(0) before returning, because fullcalendar - * makes the calendar scroll to 6:00 in a setTimeout(0), which might have an - * impact according to where we want to trigger positional clicks. - * - * @param {Object} params @see createView - * @param {Object} [options] - * @param {boolean} [options.positionalClicks=false] - * @returns {Promise} - */ - async function createCalendarView(params, options) { - const calendar = await createView(params); - if (!options || !options.positionalClicks) { - return calendar; - } - const viewElements = [...document.getElementById('qunit-fixture').children]; - // prepend reset the scrollTop to zero so we restore it manually - let fcScroller = document.querySelector('.fc-scroller'); - const scrollPosition = fcScroller.scrollTop; - viewElements.forEach(el => document.body.prepend(el)); - fcScroller = document.querySelector('.fc-scroller'); - fcScroller.scrollTop = scrollPosition; - - const destroy = calendar.destroy; - calendar.destroy = () => { - viewElements.forEach(el => el.remove()); - destroy(); - }; - await concurrency.delay(0); - return calendar; - } - - /** - * Create a simple component environment with a basic Parent component, an - * extensible env and a mocked server. The returned value is the instance of - * the given constructor. - * @param {class} constructor Component class to instantiate - * @param {Object} [params = {}] - * @param {boolean} [params.debug] - * @param {Object} [params.env] - * @param {Object} [params.intercepts] object in which the keys represent the - * intercepted event names and the values are their callbacks. - * @param {Object} [params.props] - * @returns {Promise} instance of `constructor` - */ - async function createComponent(constructor, params = {}) { - if (!constructor) { - throw new Error(`Missing argument "constructor".`); - } - if (!(constructor.prototype instanceof Component)) { - throw new Error(`Argument "constructor" must be an Owl Component.`); - } - const cleanUp = await testUtilsMock.addMockEnvironmentOwl(Component, params); - class Parent extends LegacyComponent { - setup() { - this.Component = constructor; - this.state = useState(params.props || {}); - for (const eventName in params.intercepts || {}) { - useListener(eventName, params.intercepts[eventName]); - } - useChild(); - } - } - Parent.template = xml``; - - const target = getFixture(); - const env = Component.env; - const parent = await mount(Parent, target, { env }); - registerCleanup(cleanUp); - registerCleanup(() => { - destroy(parent); - }); - return parent.child; - } - - /** - * Create a model from given parameters. - * - * @param {Object} params This object will be given to addMockEnvironment, so - * any parameters from that method applies - * @param {Class} params.Model the model class to use - * @returns {Model} - */ - async function createModel(params) { - const widget = new Widget(); - - const model = new params.Model(widget, params); - - await testUtilsMock.addMockEnvironment(widget, params); - - // override the model's 'destroy' so that it calls 'destroy' on the widget - // instead, as the widget is the parent of the model and the mockServer. - model.destroy = function () { - // remove the override to properly destroy the model when it will be - // called the second time (by its parent) - delete model.destroy; - widget.destroy(); - }; - - return model; - } - - /** - * Create a widget parent from given parameters. - * - * @param {Object} params This object will be given to addMockEnvironment, so - * any parameters from that method applies - * @returns {Promise} - */ - async function createParent(params) { - const widget = new Widget(); - await testUtilsMock.addMockEnvironment(widget, params); - return widget; - } - - /** - * Create a view from various parameters. Here, a view means a javascript - * instance of an AbstractView class, such as a form view, a list view or a - * kanban view. - * - * It returns the instance of the view, properly created, with all rpcs going - * through a mock method using the data object as source, and already loaded/ - * started. - * - * @param {Object} params - * @param {string} params.arch the xml (arch) of the view to be instantiated - * @param {any[]} [params.domain] the initial domain for the view - * @param {Object} [params.context] the initial context for the view - * @param {string[]} [params.groupBy] the initial groupBy for the view - * @param {Object[]} [params.favoriteFilters] the favorite filters one would like to have at initialization - * @param {integer} [params.fieldDebounce=0] the debounce value to use for the - * duration of the test. - * @param {AbstractView} params.View the class that will be instantiated - * @param {string} params.model a model name, will be given to the view - * @param {Object} params.intercepts an object with event names as key, and - * callback as value. Each key,value will be used to intercept the event. - * Note that this is particularly useful if you want to intercept events going - * up in the init process of the view, because there are no other way to do it - * after this method returns - * @param {Boolean} [params.doNotDisableAHref=false] will not preventDefault on the A elements of the view if true. - * Default is false. - * @param {Boolean} [params.touchScreen=false] will add the o_touch_device to the webclient (flag used to define a - * device with a touch screen. Default value is false - * @returns {Promise} the instance of the view - */ - async function createView(params) { - const target = prepareTarget(params.debug); - const widget = new Widget(); - // reproduce the DOM environment of views - const webClient = Object.assign(document.createElement('div'), { - className: params.touchScreen ? 'o_web_client o_touch_device' : 'o_web_client', - }); - const actionManager = Object.assign(document.createElement('div'), { - className: 'o_action_manager', - }); - const dialogContainer = Object.assign(document.createElement('div'), { - className: 'o_dialog_container', - }); - target.prepend(webClient); - webClient.append(actionManager); - webClient.append(dialogContainer); - - // add mock environment: mock server, session, fieldviewget, ... - const mockServer = await testUtilsMock.addMockEnvironment(widget, params); - const viewInfo = testUtilsMock.getView(mockServer, params); - - params.server = mockServer; - - // create the view - const View = params.View; - const modelName = params.model || 'foo'; - const defaultAction = { - res_model: modelName, - context: {}, - type: 'ir.actions.act_window', - }; - const viewOptions = Object.assign({ - action: Object.assign(defaultAction, params.action), - view: { ...viewInfo, fields: mockServer.fieldsGet(params.model) }, - modelName: modelName, - ids: 'res_id' in params ? [params.res_id] : undefined, - currentId: 'res_id' in params ? params.res_id : undefined, - domain: params.domain || [], - context: params.context || {}, - hasActionMenus: false, - }, params.viewOptions); - // patch the View to handle the groupBy given in params, as we can't give it - // in init (unlike the domain and context which can be set in the action) - testUtilsMock.patch(View, { - _updateMVCParams() { - this._super(...arguments); - this.loadParams.groupedBy = params.groupBy || viewOptions.groupBy || []; - testUtilsMock.unpatch(View); - }, - }); - if ('hasSelectors' in params) { - viewOptions.hasSelectors = params.hasSelectors; - } - - let view; - if (viewInfo.type === 'controlpanel' || viewInfo.type === 'search') { - // TODO: probably needs to create an helper just for that - view = new params.View({ viewInfo, modelName }); - } else { - viewOptions.controlPanelFieldsView = Object.assign(testUtilsMock.getView(mockServer, { - arch: params.archs && params.archs[params.model + ',false,search'] || '', - fields: viewInfo.fields, - model: params.model, - }), { favoriteFilters: params.favoriteFilters }); - - view = new params.View(viewInfo, viewOptions); - } - - if (params.interceptsPropagate) { - for (const name in params.interceptsPropagate) { - testUtilsMock.intercept(widget, name, params.interceptsPropagate[name], true); - } - } - - const viewController = await view.getController(widget); - // override the view's 'destroy' so that it calls 'destroy' on the widget - // instead, as the widget is the parent of the view and the mockServer. - viewController.__destroy = viewController.destroy; - viewController.destroy = function () { - // remove the override to properly destroy the viewController and its children - // when it will be called the second time (by its parent) - delete viewController.destroy; - widget.destroy(); - webClient.remove(); - }; - - // render the viewController in a fragment as they must be able to render correctly - // without being in the DOM - const fragment = document.createDocumentFragment(); - await viewController.appendTo(fragment); - dom.prepend(actionManager, fragment, { - callbacks: [{ widget: viewController }], - in_DOM: true, - }); - - if (!params.doNotDisableAHref) { - [...viewController.el.getElementsByTagName('A')].forEach(elem => { - elem.addEventListener('click', ev => { - ev.preventDefault(); - }); - }); - } - return viewController; - } - - /** - * Get the target (fixture or body) of the document and adds event listeners - * to intercept custom or DOM events. - * - * @param {boolean} [debug=false] if true, the widget will be appended in - * the DOM. Also, RPCs and uncaught OdooEvent will be logged - * @returns {HTMLElement} - */ - function prepareTarget(debug = false) { - document.body.classList.toggle('debug', debug); - return debug ? document.body : document.getElementById('qunit-fixture'); - } - - export default { - createCalendarView, - createComponent, - createModel, - createParent, - createView, - prepareTarget, - }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_dom.js b/addons/web/static/tests/legacy/helpers/test_utils_dom.js index 27cd3485e94..49933da02f4 100644 --- a/addons/web/static/tests/legacy/helpers/test_utils_dom.js +++ b/addons/web/static/tests/legacy/helpers/test_utils_dom.js @@ -1,9 +1,6 @@ /** @odoo-module alias=web.test_utils_dom **/ import concurrency from "web.concurrency"; - import Widget from "web.Widget"; - - const { Component } = owl; /** * DOM Test Utils @@ -192,21 +189,6 @@ return click(el, Object.assign({}, options, { first: true })); } - /** - * Click on the last element of a list of elements. Note that if the list has - * only one visible element, we trigger an error. In that case, it is better to - * use the click helper instead. - * - * @param {string|EventTarget|EventTarget[]} el (if string: it is a (jquery) selector) - * @param {boolean} [options={}] click options - * @param {boolean} [options.allowInvisible=false] if true, clicks on the - * element event if it is invisible - * @returns {Promise} - */ - async function clickLast(el, options) { - return click(el, Object.assign({}, options, { last: true })); - } - /** * Simulate a drag and drop operation between 2 jquery nodes: $el and $to. * This is a crude simulation, with only the mousedown, mousemove and mouseup @@ -314,94 +296,6 @@ return returnAfterNextAnimationFrame(); } - /** - * Helper method to retrieve a distinct item from a collection of elements defined - * by the given "selector" string. It can either be the index of the item or its - * inner text. - * @param {Element} el - * @param {string} selector - * @param {number | string} [elFinder=0] - * @returns {Element | null} - */ - function findItem(el, selector, elFinder = 0) { - const elements = [...getNode(el).querySelectorAll(selector)]; - if (!elements.length) { - throw new Error(`No element found with selector "${selector}".`); - } - switch (typeof elFinder) { - case "number": { - const match = elements[elFinder]; - if (!match) { - throw new Error( - `No element with selector "${selector}" at index ${elFinder}.` - ); - } - return match; - } - case "string": { - const match = elements.find( - (el) => el.innerText.trim().toLowerCase() === elFinder.toLowerCase() - ); - if (!match) { - throw new Error( - `No element with selector "${selector}" containing "${elFinder}". - `); - } - return match; - } - default: throw new Error( - `Invalid provided element finder: must be a number|string|function.` - ); - } - } - - /** - * Helper function used to extract an HTML EventTarget element from a given - * target. The extracted element will depend on the target type: - * - Component|Widget -> el - * - jQuery -> associated element (must have 1) - * - HTMLCollection (or similar) -> first element (must have 1) - * - string -> result of document.querySelector with string - * - else -> as is - * @private - * @param {(Component|Widget|jQuery|HTMLCollection|HTMLElement|string)} target - * @returns {EventTarget} - */ - function getNode(target) { - let nodes; - if (target instanceof Component || target instanceof Widget) { - nodes = [target.el]; - } else if (typeof target === 'string') { - nodes = document.querySelectorAll(target); - } else if (target === jQuery) { // jQuery (or $) - nodes = [document.body]; - } else if (target.length) { // jQuery instance, HTMLCollection or array - nodes = target; - } else { - nodes = [target]; - } - if (nodes.length !== 1) { - throw new Error(`Found ${nodes.length} nodes instead of 1.`); - } - const node = nodes[0]; - if (!node) { - throw new Error(`Expected a node and got ${node}.`); - } - if (!_isEventTarget(node)) { - throw new Error(`Expected node to be an instance of EventTarget and got ${node.constructor.name}.`); - } - return node; - } - - /** - * Open the datepicker of a given element. - * - * @param {jQuery} $datepickerEl element to which a datepicker is attached - */ - async function openDatepicker($datepickerEl) { - return click($datepickerEl.find('.o_datepicker_input')); - } - /** * Returns a promise that will be resolved after the nextAnimationFrame after * the next tick @@ -484,122 +378,11 @@ } } - /** - * Simulate a keypress event for a given character - * - * @param {string} char the character, or 'ENTER' - * @returns {Promise} - */ - async function triggerKeypressEvent(char) { - let keycode; - if (char === 'Enter') { - keycode = $.ui.keyCode.ENTER; - } else if (char === "Tab") { - keycode = $.ui.keyCode.TAB; - } else { - keycode = char.charCodeAt(0); - } - return triggerEvent(document.body, 'keypress', { - key: char, - keyCode: keycode, - which: keycode, - }); - } - - /** - * simulate a mouse event with a custom event who add the item position. This is - * sometimes necessary because the basic way to trigger an event (such as - * $el.trigger('mousemove')); ) is too crude for some uses. - * - * @param {jQuery|EventTarget} $el - * @param {string} type a mouse event type, such as 'mousedown' or 'mousemove' - * @returns {Promise} - */ - async function triggerMouseEvent($el, type) { - const el = $el instanceof jQuery ? $el[0] : $el; - if (!el) { - throw new Error(`no target found to trigger MouseEvent`); - } - const rect = el.getBoundingClientRect(); - // try to click around the center of the element, biased to the bottom - // right as chrome messes up when clicking on the top-left corner... - const left = rect.x + Math.ceil(rect.width / 2); - const top = rect.y + Math.ceil(rect.height / 2); - return triggerEvent(el, type, {which: 1, clientX: left, clientY: top}); - } - - /** - * simulate a mouse event with a custom event on a position x and y. This is - * sometimes necessary because the basic way to trigger an event (such as - * $el.trigger('mousemove')); ) is too crude for some uses. - * - * @param {integer} x - * @param {integer} y - * @param {string} type a mouse event type, such as 'mousedown' or 'mousemove' - * @returns {HTMLElement} - */ - async function triggerPositionalMouseEvent(x, y, type) { - const ev = document.createEvent("MouseEvent"); - const el = document.elementFromPoint(x, y); - ev.initMouseEvent( - type, - true /* bubble */, - true /* cancelable */, - window, null, - x, y, x, y, /* coordinates */ - false, false, false, false, /* modifier keys */ - 0 /*left button*/, null - ); - el.dispatchEvent(ev); - return el; - } - - /** - * Simulate a "TAP" (touch) event with a custom position x and y. - * - * @param {number} x - * @param {number} y - * @returns {HTMLElement} - */ - async function triggerPositionalTapEvents(x, y) { - const element = document.elementFromPoint(x, y); - const touch = new Touch({ - identifier: 0, - target: element, - clientX: x, - clientY: y, - pageX: x, - pageY: y, - }); - await triggerEvent(element, 'touchstart', { - touches: [touch], - targetTouches: [touch], - changedTouches: [touch], - }); - await triggerEvent(element, 'touchmove', { - touches: [touch], - targetTouches: [touch], - changedTouches: [touch], - }); - await triggerEvent(element, 'touchend', { - changedTouches: [touch], - }); - return element; - } - export default { click, clickFirst, - clickLast, dragAndDrop, - findItem, - getNode, - openDatepicker, returnAfterNextAnimationFrame, triggerEvent, triggerEvents, - triggerKeypressEvent, - triggerMouseEvent, - triggerPositionalMouseEvent, - triggerPositionalTapEvents, }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_fields.js b/addons/web/static/tests/legacy/helpers/test_utils_fields.js index 7b84a131f95..568a8e5060f 100644 --- a/addons/web/static/tests/legacy/helpers/test_utils_fields.js +++ b/addons/web/static/tests/legacy/helpers/test_utils_fields.js @@ -22,77 +22,6 @@ // Public functions //------------------------------------------------------------------------- - /** - * Autofills the input of a many2one field and clicks on the "Create and Edit" option. - * - * @param {string} fieldName - * @param {string} text Used as default value for the record name - * @see clickM2OItem - */ - async function clickM2OCreateAndEdit(fieldName, text = "ABC") { - await clickOpenM2ODropdown(fieldName); - const match = document.querySelector(`.o_field_many2one[name=${fieldName}] input`); - await editInput(match, text); - return clickM2OItem(fieldName, "Create and Edit"); - } - - /** - * Click on the active (highlighted) selection in a m2o dropdown. - * - * @param {string} fieldName - * @param {[string]} selector if set, this will restrict the search for the m2o - * input - * @returns {Promise} - */ - async function clickM2OHighlightedItem(fieldName, selector) { - const m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`; - const $dropdown = $(m2oSelector).autocomplete('widget'); - // clicking on an li (no matter which one), will select the focussed one - return testUtilsDom.click($dropdown[0].querySelector('li')); - } - - /** - * Click on a menuitem in the m2o dropdown. This helper will target an element - * which contains some specific text. Note that it assumes that the dropdown - * is currently open. - * - * Example: - * testUtils.fields.many2one.clickM2OItem('partner_id', 'George'); - * - * @param {string} fieldName - * @param {string} searchText - * @returns {Promise} - */ - async function clickM2OItem(fieldName, searchText) { - const m2oSelector = `.o_field_many2one[name=${fieldName}] input`; - const $dropdown = $(m2oSelector).autocomplete('widget'); - const $target = $dropdown.find(`li:contains(${searchText})`).first(); - if ($target.length !== 1 || !$target.is(':visible')) { - throw new Error('Menu item should be visible'); - } - $target.mouseenter(); // This is NOT a mouseenter event. See jquery.js:5516 for more headaches. - return testUtilsDom.click($target); - } - - /** - * Click to open the dropdown on a many2one - * - * @param {string} fieldName - * @param {[string]} selector if set, this will restrict the search for the m2o - * input - * @returns {Promise} the main many2one input - */ - async function clickOpenM2ODropdown(fieldName, selector) { - const m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`; - const matches = document.querySelectorAll(m2oSelector); - if (matches.length !== 1) { - throw new Error(`cannot open m2o: selector ${selector} has been found ${matches.length} instead of 1`); - } - - await testUtilsDom.click(matches[0]); - return matches[0]; - } - /** * Sets the value of an element and then, trigger all specified events. * Note that this helper also checks the unicity of the target. @@ -133,51 +62,6 @@ return editAndTrigger(el, value, ['input']); } - /** - * Sets the value of a select. - * - * Note that this helper also checks the unicity of the target. - * - * Example: - * testUtils.fields.editSelect($('selector'), 'somevalue'); - * - * @param {jQuery|EventTarget} el should target an input, textarea or select - * @param {string|number} value - * @returns {Promise} - */ - function editSelect(el, value) { - return editAndTrigger(el, value, ['change']); - } - - /** - * This helper is useful to test many2one fields. Here is what it does: - * - click to open the dropdown - * - enter a search string in the input - * - wait for the selection - * - click on the requested menuitem, or the active one by default - * - * Example: - * testUtils.fields.many2one.searchAndClickM2OItem('partner_id', {search: 'George'}); - * - * @param {string} fieldName - * @param {[Object]} [options = {}] - * @param {[string]} [options.selector] - * @param {[string]} [options.search] - * @param {[string]} [options.item] - * @returns {Promise} - */ - async function searchAndClickM2OItem(fieldName, options = {}) { - const input = await clickOpenM2ODropdown(fieldName, options.selector); - if (options.search) { - await editInput(input, options.search); - } - if (options.item) { - return clickM2OItem(fieldName, options.item); - } else { - return clickM2OHighlightedItem(fieldName, options.selector); - } - } - /** * Helper to trigger a key event on an element. * @@ -222,27 +106,8 @@ return triggerKey('down', $el, keyCode); } - /** - * Helper to trigger a keyup event on an element. - * - * @param {jQuery} $el - * @param {number|string} keyCode @see triggerKey - * @returns {Promise} - */ - function triggerKeyup($el, keyCode) { - return triggerKey('up', $el, keyCode); - } - export default { - clickM2OCreateAndEdit, - clickM2OHighlightedItem, - clickM2OItem, - clickOpenM2ODropdown, editAndTrigger, editInput, - editSelect, - searchAndClickM2OItem, - triggerKey, triggerKeydown, - triggerKeyup, }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_form.js b/addons/web/static/tests/legacy/helpers/test_utils_form.js deleted file mode 100644 index 8b6f61c59e0..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_form.js +++ /dev/null @@ -1,71 +0,0 @@ -/** @odoo-module alias=web.test_utils_form **/ - -/** - * Form Test Utils - * - * This module defines various utility functions to help test form views. - * - * Note that all methods defined in this module are exported in the main - * testUtils file. - */ - -import testUtilsDom from "web.test_utils_dom"; - -/** - * Clicks on the Edit button in a form view, to set it to edit mode. Note that - * it checks that the button is visible, so calling this method in edit mode - * will fail. - * - * @param {FormController} form - */ -function clickEdit(form) { - return testUtilsDom.click(form.$buttons.find('.o_form_button_edit')); -} - -/** - * Clicks on the Save button in a form view. Note that this method checks that - * the Save button is visible. - * - * @param {FormController} form - */ -function clickSave(form) { - return testUtilsDom.click(form.$buttons.find('.o_form_button_save')); -} - -/** - * Clicks on the Create button in a form view. Note that this method checks that - * the Create button is visible. - * - * @param {FormController} form - */ -function clickCreate(form) { - return testUtilsDom.click(form.$buttons.find('.o_form_button_create')); -} - -/** - * Clicks on the Discard button in a form view. Note that this method checks that - * the Discard button is visible. - * - * @param {FormController} form - */ -function clickDiscard(form) { - return testUtilsDom.click(form.$buttons.find('.o_form_button_cancel')); -} - -/** - * Reloads a form view. - * - * @param {FormController} form - * @param {[Object]} params given to the controller reload method - */ -function reload(form, params) { - return form.reload(params); -} - -export default { - clickEdit: clickEdit, - clickSave: clickSave, - clickCreate: clickCreate, - clickDiscard: clickDiscard, - reload: reload, -}; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_graph.js b/addons/web/static/tests/legacy/helpers/test_utils_graph.js deleted file mode 100644 index 8549ffb6a16..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_graph.js +++ /dev/null @@ -1,25 +0,0 @@ -/** @odoo-module alias=web.test_utils_graph **/ - -/** - * Graph Test Utils - * - * This module defines various utility functions to help test graph views. - * - * Note that all methods defined in this module are exported in the main - * testUtils file. - */ - - -/** - * Reloads a graph view. - * - * @param {GraphController} graph - * @param {[Object]} params given to the controller reload method - */ -function reload(graph, params) { - return graph.reload(params); -} - -export default { - reload: reload, -}; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_kanban.js b/addons/web/static/tests/legacy/helpers/test_utils_kanban.js deleted file mode 100644 index 3ac5c2db0e5..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_kanban.js +++ /dev/null @@ -1,99 +0,0 @@ -/** @odoo-module alias=web.test_utils_kanban **/ - -/** - * Kanban Test Utils - * - * This module defines various utility functions to help testing kanban views. - * - * Note that all methods defined in this module are exported in the main - * testUtils file. - */ - -import testUtilsDom from "web.test_utils_dom"; -import testUtilsFields from "web.test_utils_fields"; - -/** - * Clicks on the Create button in a kanban view. Note that this method checks that - * the Create button is visible. - * - * @param {KanbanController} kanban - * @returns {Promise} - */ -function clickCreate(kanban) { - return testUtilsDom.click(kanban.$buttons.find('.o-kanban-button-new')); -} - -/** - * Open the settings menu for a column (in a grouped kanban view) - * - * @param {jQuery} $column - * @returns {Promise} - */ -function toggleGroupSettings($column) { - var $dropdownToggler = $column.find('.o_kanban_config > a.dropdown-toggle'); - if (!$dropdownToggler.is(':visible')) { - $dropdownToggler.css('display', 'block'); - } - return testUtilsDom.click($dropdownToggler); -} - -/** - * Edit a value in a quickcreate form view (this method assumes that the quick - * create feature is active, and a sub form view is open) - * - * @param {kanbanController} kanban - * @param {string|number} value - * @param {[string]} fieldName - * @returns {Promise} - */ -function quickCreate(kanban, value, fieldName) { - var additionalSelector = fieldName ? ('[name=' + fieldName + ']'): ''; - var enterEvent = $.Event( - 'keydown', - { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - } - ); - return testUtilsFields.editAndTrigger( - kanban.$('.o_kanban_quick_create input' + additionalSelector), - value, - ['input', enterEvent] - ); -} - -/** - * Reloads a kanban view. - * - * @param {KanbanController} kanban - * @param {[Object]} params given to the controller reload method - * @returns {Promise} - */ -function reload(kanban, params) { - return kanban.reload(params); -} - -/** - * Open the setting dropdown of a kanban record. Note that the template of a - * kanban record is not standardized, so this method will fail if the template - * does not comply with the usual dom structure. - * - * @param {jQuery} $record - * @returns {Promise} - */ -function toggleRecordDropdown($record) { - var $dropdownToggler = $record.find('.o_dropdown_kanban > a.dropdown-toggle'); - if (!$dropdownToggler.is(':visible')) { - $dropdownToggler.css('display', 'block'); - } - return testUtilsDom.click($dropdownToggler); -} - - -export default { - clickCreate: clickCreate, - quickCreate: quickCreate, - reload: reload, - toggleGroupSettings: toggleGroupSettings, - toggleRecordDropdown: toggleRecordDropdown, -}; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_mock.js b/addons/web/static/tests/legacy/helpers/test_utils_mock.js index 30e4789c5c1..fa2c0faa9cf 100644 --- a/addons/web/static/tests/legacy/helpers/test_utils_mock.js +++ b/addons/web/static/tests/legacy/helpers/test_utils_mock.js @@ -23,7 +23,6 @@ import session from "web.session"; import { patchWithCleanup, patchDate } from "@web/../tests/helpers/utils"; import { browser } from "@web/core/browser/browser"; import { assets } from "@web/core/assets"; -import { processArch } from "@web/legacy/legacy_load_views"; import { Component } from "@odoo/owl"; import { uniqueId } from "@web/core/utils/functions"; @@ -41,12 +40,10 @@ const DebouncedField = basic_fields.DebouncedField; * @private * @param {Object} params * @param {Bus} [params.bus] - * @param {boolean} [params.debug] * @param {Object} [params.env] * @param {Bus} [params.env.bus] * @param {Object} [params.env.dataManager] * @param {Object} [params.env.services] - * @param {Object[]} [params.favoriteFilters] * @param {Object} [params.services] * @param {Object} [params.session] * @param {MockServer} [mockServer] @@ -58,8 +55,6 @@ async function _getMockedOwlEnv(params, mockServer) { const database = {parameters: params.translateParameters || {}}; // build the env - const favoriteFilters = params.favoriteFilters; - const debug = params.debug; const services = {}; const env = Object.assign({}, params.env, { _t: params.env && params.env._t || Object.assign((s => s), { database }), @@ -248,35 +243,6 @@ function _observe(widget) { // Public functions //------------------------------------------------------------------------------ -/** - * performs a get_view, and mocks the postprocessing done by the - * data_manager to return an equivalent structure. - * - * @param {MockServer} server - * @param {Object} params - * @param {string} params.model - * @returns {Object} an object with 3 keys: arch, fields and viewFields - */ -function getView(server, params) { - var view = server.getView(params); - const fields = server.fieldsGet(params.model); - // mock the structure produced by the DataManager - const models = { [params.model]: fields }; - for (const modelName of view.models) { - models[modelName] = models[modelName] || server.fieldsGet(modelName); - } - const { arch, viewFields } = processArch(view.arch, view.type, params.model, models); - return { - arch, - fields, - model: view.model, - toolbar: view.toolbar, - type: view.type, - viewFields, - view_id: view.id, - }; -} - /** * intercepts an event bubbling up the widget hierarchy. The event intercepted * must be a "custom event", i.e. an event generated by the method 'trigger_up'. @@ -675,32 +641,11 @@ function unpatch(target) { delete target.__patchID; } -window.originalSetTimeout = window.setTimeout; -function patchSetTimeout() { - var original = window.setTimeout; - var self = this; - window.setTimeout = function (handler, delay) { - console.log("calling setTimeout on " + (handler.name || "some function") + "with delay of " + delay); - console.trace(); - var handlerArguments = Array.prototype.slice.call(arguments, 1); - return original(function () { - handler.bind(self, handlerArguments)(); - console.log('after doing the action of the setTimeout'); - }, delay); - }; - - return function () { - window.setTimeout = original; - }; -} - export default { addMockEnvironment: addMockEnvironment, - getView: getView, addMockEnvironmentOwl: addMockEnvironmentOwl, intercept: intercept, patchDate: legacyPatchDate, patch: patch, unpatch: unpatch, - patchSetTimeout: patchSetTimeout, }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_modal.js b/addons/web/static/tests/legacy/helpers/test_utils_modal.js deleted file mode 100644 index 010f88d0c91..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_modal.js +++ /dev/null @@ -1,24 +0,0 @@ -/** @odoo-module alias=web.test_utils_modal **/ - - /** - * Modal Test Utils - * - * This module defines various utility functions to help test pivot views. - * - * Note that all methods defined in this module are exported in the main - * testUtils file. - */ - - import { _t } from "web.core"; - import testUtilsDom from "web.test_utils_dom"; - - /** - * Click on a button in the footer of a modal (which contains a given string). - * - * @param {string} text (in english: this method will perform the translation) - */ - function clickButton(text) { - return testUtilsDom.click($(`.modal-footer button:contains(${_t(text)})`)); - } - - export default { clickButton }; diff --git a/addons/web/static/tests/legacy/helpers/test_utils_pivot.js b/addons/web/static/tests/legacy/helpers/test_utils_pivot.js deleted file mode 100644 index b041431a586..00000000000 --- a/addons/web/static/tests/legacy/helpers/test_utils_pivot.js +++ /dev/null @@ -1,54 +0,0 @@ -/** @odoo-module alias=web.test_utils_pivot **/ - -import testUtilsDom from "web.test_utils_dom"; - -/** - * Pivot Test Utils - * - * This module defines various utility functions to help test pivot views. - * - * Note that all methods defined in this module are exported in the main - * testUtils file. - */ - - -/** - * Select a measure by clicking on the corresponding dropdown item (in the - * control panel 'Measure' submenu). - * - * Note that this method assumes that the dropdown menu is open. - * @see toggleMeasuresDropdown - * - * @param {PivotController} pivot - * @param {string} measure - */ -function clickMeasure(pivot, measure) { - return testUtilsDom.click(pivot.$buttons.find(`.dropdown-item[data-field=${measure}]`)); -} - -/** - * Open the 'Measure' dropdown menu (in the control panel) - * - * @see clickMeasure - * - * @param {PivotController} pivot - */ -function toggleMeasuresDropdown(pivot) { - return testUtilsDom.click(pivot.$buttons.filter('.btn-group:first').find('> button')); -} - -/** - * Reloads a graph view. - * - * @param {PivotController} pivot - * @param {[Object]} params given to the controller reload method - */ -function reload(pivot, params) { - return pivot.reload(params); -} - -export default { - clickMeasure: clickMeasure, - reload: reload, - toggleMeasuresDropdown: toggleMeasuresDropdown, -}; diff --git a/addons/web/static/tests/legacy/owl_compatibility_tests.js b/addons/web/static/tests/legacy/owl_compatibility_tests.js index ded9e1e7107..13949d7049f 100644 --- a/addons/web/static/tests/legacy/owl_compatibility_tests.js +++ b/addons/web/static/tests/legacy/owl_compatibility_tests.js @@ -62,7 +62,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hello World!
'); @@ -92,7 +92,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hello World!
'); @@ -133,7 +133,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); await mount(Parent, target); }); @@ -167,7 +167,7 @@ `; Parent.components = { MyWidgetAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hello World!
'); @@ -198,7 +198,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hello World!
'); @@ -245,7 +245,7 @@ `; Parent.components = { MyWidgetAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hello World!
'); @@ -307,7 +307,7 @@ `; Parent.components = { AsyncComponent, MyWidgetAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hi World!
Hello World!
'); @@ -353,7 +353,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.verifySteps(['on_attach_callback']); @@ -385,7 +385,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
widget
component
'); @@ -417,7 +417,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); await mount(Parent, target); widget.trigger_up('some-event', { value: 'a' }); @@ -452,7 +452,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target, { env: owl.Component.env }); assert.strictEqual(parent.el.innerHTML, '
'); @@ -497,7 +497,7 @@ } }; - const target = testUtils.prepareTarget(); + const target = getFixture(); await mount(Parent, target, { env }); }); @@ -524,47 +524,11 @@ session: { key: 'value' }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); await mount(Parent, target, { env: owl.Component.env }); cleanUp(); }); - QUnit.test("sub widget that calls load_views", async function (assert) { - assert.expect(4); - - const MyWidget = Widget.extend({ - willStart: function () { - return this.loadViews('some_model', { x: 2 }, [[false, 'list']]); - }, - }); - class Parent extends LegacyComponent { - constructor() { - super(...arguments); - this.MyWidget = MyWidget; - } - } - Parent.template = xml` -
- -
`; - Parent.components = { ComponentAdapter }; - const cleanUp = await addMockEnvironmentOwl(Parent, { - mockRPC: function (route, args) { - assert.strictEqual(route, '/web/dataset/call_kw/some_model'); - assert.deepEqual(args.kwargs.context, { x: 2 }); - assert.deepEqual(args.kwargs.views, [[false, 'list']]); - return Promise.resolve(); - }, - }); - - const target = testUtils.prepareTarget(); - const parent = await mount(Parent, target, { env: owl.Component.env }); - - assert.strictEqual(parent.el.innerHTML, '
'); - - cleanUp(); - }); - QUnit.test("sub widgets in a t-if/t-else", async function (assert) { assert.expect(3); @@ -595,7 +559,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hi
'); @@ -639,7 +603,7 @@ `; Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Hi
'); @@ -708,7 +672,7 @@ `; Parent.components = { MyWidgetAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); const widgetEl = myWidget.el; @@ -779,7 +743,7 @@ `; Parent.components = { MyWidgetAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.containsOnce(target, ".widget_id_0"); @@ -824,7 +788,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -862,7 +826,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -914,7 +878,7 @@ }); const widget = new MyWidget(); - const target = testUtils.prepareTarget(); + const target = getFixture(); const iframe = document.createElement("iframe"); target.appendChild(iframe); await widget.appendTo(iframe.contentWindow.document.body); @@ -955,7 +919,7 @@ } }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -1017,7 +981,7 @@ } }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -1079,7 +1043,7 @@ } }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); const fragment = document.createElement("div"); await widget.appendTo(fragment); @@ -1130,7 +1094,7 @@ MyComponent.template = xml`
`; MyComponent.components = { MyChildComponent }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new ComponentWrapper(null, MyComponent, {}); await widget.mount(target); @@ -1205,7 +1169,7 @@ MyComponent.template = xml`
`; MyComponent.components = { MyChildComponent }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new ComponentWrapper(null, MyComponent, { text: "takeNoMess" }); @@ -1264,7 +1228,7 @@ MyComponent.template = xml`
`; MyComponent.components = { MyChildComponent }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new ComponentWrapper(null, MyComponent, { text: "takeNoMess" }); @@ -1336,7 +1300,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -1368,7 +1332,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); assert.verifySteps([ @@ -1425,7 +1389,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -1454,7 +1418,7 @@ }, }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const widget = new MyWidget(); await widget.appendTo(target); @@ -1495,7 +1459,7 @@ } }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = new Parent(); await parent.appendTo(target); @@ -1569,7 +1533,7 @@ Parent.components = { ComponentAdapter }; - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = await mount(Parent, target); assert.strictEqual(parent.el.innerHTML, '
Component
'); @@ -1633,7 +1597,7 @@ } }); - const target = testUtils.prepareTarget(); + const target = getFixture(); const parent = new Parent(); await parent.appendTo(target); diff --git a/addons/web/static/tests/webclient/actions/load_state_tests.js b/addons/web/static/tests/webclient/actions/load_state_tests.js index 8c83dff21e3..40c71be7508 100644 --- a/addons/web/static/tests/webclient/actions/load_state_tests.js +++ b/addons/web/static/tests/webclient/actions/load_state_tests.js @@ -3,7 +3,6 @@ import { browser } from "@web/core/browser/browser"; import { registry } from "@web/core/registry"; import { WebClient } from "@web/webclient/webclient"; -import testUtils from "web.test_utils"; import { registerCleanup } from "../../helpers/cleanup"; import { makeTestEnv } from "../../helpers/mock_env"; import { @@ -17,7 +16,7 @@ import { editInput, getNodesTextContent, } from "../../helpers/utils"; -import { pagerNext, toggleMenuItem, toggleSearchBarMenu } from "@web/../tests/search/helpers"; +import { pagerNext, switchView, toggleMenuItem, toggleSearchBarMenu } from "@web/../tests/search/helpers"; import { session } from "@web/session"; import { createWebClient, @@ -121,8 +120,8 @@ QUnit.module("ActionManager", (hooks) => { patchWithCleanup(session, { home_action_id: 1001 }); await createWebClient({ serverData }); - await testUtils.nextTick(); // wait for the navbar to be updated - await testUtils.nextTick(); // wait for the action to be displayed + await nextTick(); // wait for the navbar to be updated + await nextTick(); // wait for the action to be displayed assert.containsOnce(target, ".test_client_action"); assert.strictEqual(target.querySelector(".o_menu_brand").innerText, "App1"); @@ -196,8 +195,8 @@ QUnit.module("ActionManager", (hooks) => { webClient.env.bus.trigger("test:hashchange", { action: "HelloWorldTest", }); - await testUtils.nextTick(); - await testUtils.nextTick(); + await nextTick(); + await nextTick(); assert.strictEqual( $(target).find(".o_client_action_test").text(), "Hello World", @@ -215,7 +214,7 @@ QUnit.module("ActionManager", (hooks) => { webClient.env.bus.trigger("test:hashchange", { action: 1, }); - await testUtils.nextTick(); + await nextTick(); await legacyExtraNextTick(); assert.containsOnce(target, ".o_control_panel"); assert.containsOnce(target, ".o_kanban_view"); @@ -237,8 +236,8 @@ QUnit.module("ActionManager", (hooks) => { id: 2, model: "partner", }); - await testUtils.nextTick(); - await testUtils.nextTick(); + await nextTick(); + await nextTick(); assert.containsOnce(target, ".o_form_view"); assert.deepEqual(getBreadCrumbTexts(target), ["Second record"]); assert.verifySteps(["/web/webclient/load_menus", "get_views", "web_read"]); @@ -260,7 +259,7 @@ QUnit.module("ActionManager", (hooks) => { Object.assign(browser.location, { hash }); await createWebClient({ serverData, mockRPC }); - await testUtils.nextTick(); + await nextTick(); assert.containsOnce(target, ".o_form_view"); assert.deepEqual(getBreadCrumbTexts(target), ["Second record"]); assert.containsNone(target, ".o_menu_brand"); @@ -279,7 +278,7 @@ QUnit.module("ActionManager", (hooks) => { model: "partner", view_type: "form", }); - await testUtils.nextTick(); + await nextTick(); await legacyExtraNextTick(); assert.containsOnce(target, ".o_form_view"); assert.verifySteps([ @@ -300,7 +299,7 @@ QUnit.module("ActionManager", (hooks) => { action: 3, view_type: "kanban", }); - await testUtils.nextTick(); + await nextTick(); await legacyExtraNextTick(); assert.containsNone(target, ".o_list_view"); assert.containsOnce(target, ".o_kanban_view"); @@ -329,13 +328,13 @@ QUnit.module("ActionManager", (hooks) => { id: 2, view_type: "form", }); - await testUtils.nextTick(); + await nextTick(); await legacyExtraNextTick(); assert.containsNone(target, ".o_list_view"); assert.containsOnce(target, ".o_form_view"); assert.deepEqual(getBreadCrumbTexts(target), ["Partners", "Second record"]); // go back to List - await testUtils.dom.click($(target).find(".o_control_panel .breadcrumb a")); + await click(target.querySelector(".o_control_panel .breadcrumb a")); assert.containsOnce(target, ".o_list_view"); assert.containsNone(target, ".o_form_view"); assert.verifySteps([ @@ -362,7 +361,7 @@ QUnit.module("ActionManager", (hooks) => { "Second record", ]); // go back to List - await testUtils.dom.click($(target).find(".o_control_panel .breadcrumb a:last")); + await click(target.querySelector(".o_control_panel .breadcrumb .o_back_button a")); assert.deepEqual(getBreadCrumbTexts(target), ["Partners Action 4", "Partners"]); }); @@ -401,7 +400,7 @@ QUnit.module("ActionManager", (hooks) => { action: 3, view_type: "kanban", }); - await testUtils.nextTick(); + await nextTick(); await legacyExtraNextTick(); assert.containsNone(target, ".o_list_view"); assert.containsOnce(target, ".o_kanban_view"); @@ -411,7 +410,7 @@ QUnit.module("ActionManager", (hooks) => { id: 4, view_type: "form", }); - await testUtils.nextTick(); + await nextTick(); await legacyExtraNextTick(); assert.containsNone(target, ".o_kanban_view"); assert.containsOnce(target, ".o_form_view"); @@ -437,7 +436,7 @@ QUnit.module("ActionManager", (hooks) => { const webClient = await createWebClient({ serverData, mockRPC }); // execute action 3 and open the first record in a form view await doAction(webClient, 3); - await testUtils.dom.click($(target).find(".o_list_view .o_data_cell:first")); + await click(target.querySelector(".o_list_view .o_data_cell")); assert.containsOnce(target, ".o_form_view"); assert.deepEqual(getBreadCrumbTexts(target), ["Partners", "First record"]); // switch to record 4 @@ -446,7 +445,7 @@ QUnit.module("ActionManager", (hooks) => { id: 4, view_type: "form", }); - await testUtils.nextTick(); + await nextTick(); assert.containsOnce(target, ".o_form_view"); assert.deepEqual(getBreadCrumbTexts(target), ["Partners", "Fourth record"]); // verify steps to ensure that the whole action hasn't been re-executed @@ -485,7 +484,7 @@ QUnit.module("ActionManager", (hooks) => { view_type: "list", }); assert.verifySteps(["push_state"], "should have pushed the final state"); - await testUtils.dom.click($(target).find("tr .o_data_cell:first")); + await click(target.querySelector("tr .o_data_cell")); await legacyExtraNextTick(); currentHash = webClient.env.services.router.current.hash; assert.deepEqual(currentHash, { @@ -660,7 +659,7 @@ QUnit.module("ActionManager", (hooks) => { await doAction(webClient, 3); assert.containsOnce(target, ".o_list_view", "should now display the list view"); - await testUtils.controlPanel.switchView(target, "kanban"); + await switchView(target, "kanban"); await legacyExtraNextTick(); assert.containsOnce(target, ".o_kanban_view", "should now display the kanban view");