diff --git a/addons/board/static/tests/dashboard_tests.js b/addons/board/static/tests/dashboard_tests.js index 905a0ff87f1..1473823946d 100644 --- a/addons/board/static/tests/dashboard_tests.js +++ b/addons/board/static/tests/dashboard_tests.js @@ -702,7 +702,7 @@ QUnit.test('dashboard intercepts custom events triggered by sub controllers', as QUnit.test("save actions to dashboard", async function (assert) { assert.expect(6); - testUtils.patch(ListController, { + testUtils.mock.patch(ListController, { getOwnedQueryParams: function () { var result = this._super.apply(this, arguments); result.context = { @@ -773,7 +773,7 @@ QUnit.test("save actions to dashboard", async function (assert) { await testUtils.fields.editInput($(".o_add_to_board input"), "a name"); await testUtils.dom.click($(".o_add_to_board div button")); - testUtils.unpatch(ListController); + testUtils.mock.unpatch(ListController); }); QUnit.test("save two searches to dashboard", async function (assert) { diff --git a/addons/bus/static/tests/bus_tests.js b/addons/bus/static/tests/bus_tests.js index 449e3ba2c93..90bc31dcc61 100644 --- a/addons/bus/static/tests/bus_tests.js +++ b/addons/bus/static/tests/bus_tests.js @@ -316,7 +316,7 @@ QUnit.module('Bus', { assert.expect(5); let id = 1; - testUtils.patch(CrossTabBus, { + testUtils.mock.patch(CrossTabBus, { init: function () { this._super.apply(this, arguments); this.__tabId__ = id++; @@ -333,7 +333,7 @@ QUnit.module('Bus', { let pollPromise; const parentTab1 = new Widget(); - await testUtils.addMockEnvironment(parentTab1, { + await testUtils.mock.addMockEnvironment(parentTab1, { data: {}, services: { local_storage: LocalStorageServiceMock, @@ -350,7 +350,7 @@ QUnit.module('Bus', { } }); const parentTab2 = new Widget(); - await testUtils.addMockEnvironment(parentTab2, { + await testUtils.mock.addMockEnvironment(parentTab2, { data: {}, services: { local_storage: LocalStorageServiceMock, @@ -382,7 +382,7 @@ QUnit.module('Bus', { "Tab 2: addChannel beta", ]); - testUtils.unpatch(CrossTabBus); + testUtils.mock.unpatch(CrossTabBus); parentTab1.destroy(); parentTab2.destroy(); }); diff --git a/addons/hr_holidays/static/tests/test_leave_stats_widget.js b/addons/hr_holidays/static/tests/test_leave_stats_widget.js index 157459dc61d..e7d2299326d 100644 --- a/addons/hr_holidays/static/tests/test_leave_stats_widget.js +++ b/addons/hr_holidays/static/tests/test_leave_stats_widget.js @@ -64,8 +64,8 @@ odoo.define('hr_holidays.leave_stats_widget_tests', function (require) { id: 13, employee_id: 100, department_id: 11, - date_from: "2016-10-2 09:00:00", - date_to: "2016-10-2 18:00:00", + date_from: "2016-10-02 09:00:00", + date_to: "2016-10-02 18:00:00", holiday_status_id: 55, state: 'validate', number_of_days: 1, diff --git a/addons/web/static/lib/owl/owl.js b/addons/web/static/lib/owl/owl.js index 29aa09cebb5..fc748477910 100644 --- a/addons/web/static/lib/owl/owl.js +++ b/addons/web/static/lib/owl/owl.js @@ -2818,8 +2818,10 @@ set(mode) { QWeb.dev = mode === "dev"; if (QWeb.dev) { - const url = `https://github.com/odoo/owl/blob/master/doc/reference/config.md#mode`; - console.warn(`Owl is running in 'dev' mode. This is not suitable for production use. See ${url} for more information.`); + console.info(`Owl is running in 'dev' mode. + +This is not suitable for production use. +See https://github.com/odoo/owl/blob/master/doc/reference/config.md#mode for more information.`); } else { console.log(`Owl is now running in 'prod' mode.`); diff --git a/addons/web/static/src/legacy/js/fields/basic_fields.js b/addons/web/static/src/legacy/js/fields/basic_fields.js index 16e433da52b..3d4df0cb0a1 100644 --- a/addons/web/static/src/legacy/js/fields/basic_fields.js +++ b/addons/web/static/src/legacy/js/fields/basic_fields.js @@ -926,8 +926,8 @@ var FieldDate = InputField.extend({ * @returns {boolean} */ _isSameValue: function (value) { - if (value === false) { - return this.value === false; + if (this.value === false || value === false) { + return this.value === value; } return value.isSame(this.value, 'day'); }, @@ -1005,8 +1005,8 @@ var FieldDateTime = FieldDate.extend({ * @private */ _isSameValue: function (value) { - if (value === false) { - return this.value === false; + if (this.value === false || value === false) { + return this.value === value; } return value.isSame(this.value); }, diff --git a/addons/web/static/tests/core/l10n/dates_tests.js b/addons/web/static/tests/core/l10n/dates_tests.js index 6395b340236..e535bc12688 100644 --- a/addons/web/static/tests/core/l10n/dates_tests.js +++ b/addons/web/static/tests/core/l10n/dates_tests.js @@ -59,7 +59,11 @@ function runTestSet(assert, testSet, options) { } } -QUnit.module("utils", () => { + +QUnit.module("utils", { + before() {moment.suppressDeprecationWarnings = true;}, + after() {moment.suppressDeprecationWarnings = false;}, + }, () => { QUnit.module("dates"); QUnit.test("formatDateTime", async (assert) => { diff --git a/addons/web/static/tests/helpers/cleanup.js b/addons/web/static/tests/helpers/cleanup.js index 814410d0392..d68bc467ee3 100644 --- a/addons/web/static/tests/helpers/cleanup.js +++ b/addons/web/static/tests/helpers/cleanup.js @@ -79,24 +79,18 @@ QUnit.on("OdooAfterTestHook", function (info) { (e) => e.tagName === bodyChild.tagName && bodyChild.getAttribute(e.attr) === e.value ); if (!tolerated) { - console.error(`Test ${info.moduleName} > ${info.testName}`); console.error( - "Body still contains undesirable elements:" + - "\nInvalid element:\n" + - bodyChild.outerHTML - ); +`Test ${info.moduleName} > ${info.testName}: body still contains undesirable elements: + ${bodyChild.outerHTML}`); QUnit.pushFailure(`Body still contains undesirable elements`); } if (!tolerated || !tolerated.keep) { toRemove.push(bodyChild); } } - // check for leftovers in #qunit-fixture + // cleanup leftovers in #qunit-fixture const qunitFixture = document.getElementById("qunit-fixture"); if (qunitFixture.children.length) { - // console.error('#qunit-fixture still contains elements:' + - // '\n#qunit-fixture HTML:\n' + qunitFixture.outerHTML); - // QUnit.pushFailure(`#qunit-fixture still contains elements`); toRemove.push(...qunitFixture.children); } // remove unwanted elements if not in debug diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index 34058a7955f..318c48103cf 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -242,7 +242,7 @@ export class MockServer { // TODO // const pyevalContext = window.py.dict.fromJSON(context || {}); // var v = pyUtils.py_eval(mod, {context: pyevalContext}) ? true : false; - console.warn("MockServer: naive parse of modifier value"); + console.info("MockServer: naive parse of modifier value in", QUnit.config.current.testName); const v = JSON.parse(mod); if (inTreeView && !inListHeader && attr === "invisible") { modifiers.column_invisible = v; @@ -498,7 +498,7 @@ export class MockServer { if (!action) { // when the action doesn't exist, the real server doesn't crash, it // simply returns false - console.warn("No action found for ID " + kwargs.action_id); + console.warn(`No action found for ID ${kwargs.action_id} during test ${QUnit.config.current.testName}`); } return action || false; } @@ -808,7 +808,7 @@ export class MockServer { res[groupByField] = val; } if (field.type === "date" && val) { - console.warn("Mock Server: read group not fully implemented (moment stuff)"); + console.info("Mock Server: read group not fully implemented (moment stuff) in", QUnit.config.current.testName); // const aggregateFunction = groupByField.split(':')[1]; // let startDate; // let endDate; diff --git a/addons/web/static/tests/helpers/utils.js b/addons/web/static/tests/helpers/utils.js index f01c79b991b..cdf3bf7b88c 100644 --- a/addons/web/static/tests/helpers/utils.js +++ b/addons/web/static/tests/helpers/utils.js @@ -208,3 +208,8 @@ export async function legacyExtraNextTick() { export function mockDownload(cb) { patchWithCleanup(download, { _download: cb }); } + +export const hushConsole = Object.create(null); +for(const propName of Object.keys(window.console)) { + hushConsole[propName] = () => {} +} diff --git a/addons/web/static/tests/legacy/components/datepicker_tests.js b/addons/web/static/tests/legacy/components/datepicker_tests.js index 643bcdb5188..78908bd911f 100644 --- a/addons/web/static/tests/legacy/components/datepicker_tests.js +++ b/addons/web/static/tests/legacy/components/datepicker_tests.js @@ -15,9 +15,10 @@ odoo.define('web.datepicker_tests', function (require) { assert.expect(8); const picker = await createComponent(DatePicker, { - props: { date: moment('01/09/1997') }, + props: { date: moment('1997-01-09') }, }); + assert.containsOnce(picker, 'input.o_input.o_datepicker_input'); assert.containsOnce(picker, 'span.o_datepicker_button'); assert.containsNone(document.body, 'div.bootstrap-datetimepicker-widget'); @@ -46,7 +47,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.expect(5); const picker = await createComponent(DatePicker, { - props: { date: moment('01/09/1997') }, + props: { date: moment('1997-01-09') }, intercepts: { 'datetime-changed': ev => { assert.step('datetime-changed'); @@ -106,7 +107,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.verifySteps(['datetime-changed']); moment.locale(originalLocale); - moment.updateLocale('englishForTest', null); + moment.updateLocale('frenchForTests', null); picker.destroy(); }); @@ -115,7 +116,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.expect(5); const picker = await createComponent(DatePicker, { - props: { date: moment('01/09/1997') }, + props: { date: moment('1997-01-09') }, intercepts: { 'datetime-changed': ev => { assert.step('datetime-changed'); @@ -146,9 +147,9 @@ odoo.define('web.datepicker_tests', function (require) { QUnit.test("Date format is correctly set", async function (assert) { assert.expect(2); - testUtils.patch(time, { getLangDateFormat: () => "YYYY/MM/DD" }); + testUtils.mock.patch(time, { getLangDateFormat: () => "YYYY/MM/DD" }); const picker = await createComponent(DatePicker, { - props: { date: moment('01/09/1997') }, + props: { date: moment('1997-01-09') }, }); const input = picker.el.querySelector('.o_datepicker_input'); @@ -160,7 +161,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.strictEqual(input.value, '1997/01/09'); picker.destroy(); - testUtils.unpatch(time); + testUtils.mock.unpatch(time); }); QUnit.module('DateTimePicker'); @@ -169,7 +170,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.expect(11); const picker = await createComponent(DateTimePicker, { - props: { date: moment('01/09/1997 12:30:01') }, + props: { date: moment('1997-01-09 12:30:01') }, }); assert.containsOnce(picker, 'input.o_input.o_datepicker_input'); @@ -204,7 +205,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.expect(5); const picker = await createComponent(DateTimePicker, { - props: { date: moment('01/09/1997 12:30:01') }, + props: { date: moment('1997-01-09 12:30:01') }, intercepts: { 'datetime-changed': ev => { assert.step('datetime-changed'); @@ -292,7 +293,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.expect(9); const picker = await createComponent(DateTimePicker, { - props: { date: moment('01/09/1997 12:30:01') }, + props: { date: moment('1997-01-09 12:30:01') }, intercepts: { 'datetime-changed': ev => { assert.step('datetime-changed'); @@ -330,9 +331,9 @@ odoo.define('web.datepicker_tests', function (require) { QUnit.test("Date time format is correctly set", async function (assert) { assert.expect(2); - testUtils.patch(time, { getLangDatetimeFormat: () => "hh:mm:ss YYYY/MM/DD" }); + testUtils.mock.patch(time, { getLangDatetimeFormat: () => "hh:mm:ss YYYY/MM/DD" }); const picker = await createComponent(DateTimePicker, { - props: { date: moment('01/09/1997 12:30:01') }, + props: { date: moment('1997-01-09 12:30:01') }, }); const input = picker.el.querySelector('.o_datepicker_input'); @@ -344,7 +345,7 @@ odoo.define('web.datepicker_tests', function (require) { assert.strictEqual(input.value, '12:30:01 1997/01/09'); picker.destroy(); - testUtils.unpatch(time); + testUtils.mock.unpatch(time); }); }); }); diff --git a/addons/web/static/tests/legacy/fields/basic_fields_tests.js b/addons/web/static/tests/legacy/fields/basic_fields_tests.js index 04d94321145..fa7ed263804 100644 --- a/addons/web/static/tests/legacy/fields/basic_fields_tests.js +++ b/addons/web/static/tests/legacy/fields/basic_fields_tests.js @@ -3910,7 +3910,7 @@ QUnit.module('basic_fields', { assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0, "datepicker should be closed initially"); - testUtils.openDatepicker(form.$('.o_datepicker')); + testUtils.dom.openDatepicker(form.$('.o_datepicker')); assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 1, "datepicker should be opened"); @@ -4375,7 +4375,7 @@ QUnit.module('basic_fields', { var dateViewForm = form.$('.o_field_date').text(); await testUtils.dom.click(form.$buttons.find('.o_form_button_edit')); - await testUtils.openDatepicker(form.$('.o_datepicker')); + await testUtils.dom.openDatepicker(form.$('.o_datepicker')); assert.strictEqual(form.$('.o_datepicker_input').val(), dateViewForm, "input date field should be the same as it was in the view form"); @@ -7564,7 +7564,7 @@ QUnit.module('basic_fields', { var top = $progressBarEl.offset().top + 5; var left = $progressBarEl.offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "click"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "click"); } catch (e) { form.destroy(); $view.remove(); @@ -7611,7 +7611,7 @@ QUnit.module('basic_fields', { var top = $progressBarEl.offset().top + 5; var left = $progressBarEl.offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "click"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "click"); } catch (e) { form.destroy(); $view.remove(); diff --git a/addons/web/static/tests/legacy/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/legacy/fields/relational_fields/field_one2many_tests.js index 9f96a0d7afa..83e3b50a699 100644 --- a/addons/web/static/tests/legacy/fields/relational_fields/field_one2many_tests.js +++ b/addons/web/static/tests/legacy/fields/relational_fields/field_one2many_tests.js @@ -1,6 +1,7 @@ odoo.define('web.field_one_to_many_tests', function (require) { "use strict"; +const {delay} = require('web.concurrency'); var AbstractField = require('web.AbstractField'); var AbstractStorageService = require('web.AbstractStorageService'); const ControlPanel = require('web.ControlPanel'); @@ -1659,28 +1660,26 @@ QUnit.module('fields', {}, function () { }); QUnit.test('embedded one2many with handle widget with minimum setValue calls', async function (assert) { - var done = assert.async(); assert.expect(20); - this.data.turtle.records[0].turtle_int = 6; this.data.turtle.records.push({ id: 4, turtle_int: 20, turtle_foo: "a1", }, { - id: 5, - turtle_int: 9, - turtle_foo: "a2", - }, { - id: 6, - turtle_int: 2, - turtle_foo: "a3", - }, { - id: 7, - turtle_int: 11, - turtle_foo: "a4", - }); + id: 5, + turtle_int: 9, + turtle_foo: "a2", + }, { + id: 6, + turtle_int: 2, + turtle_foo: "a3", + }, { + id: 7, + turtle_int: 11, + turtle_foo: "a4", + }); this.data.partner.records[0].turtles = [1, 2, 3, 4, 5, 6, 7]; var form = await createView({ @@ -1688,18 +1687,12 @@ QUnit.module('fields', {}, function () { model: 'partner', data: this.data, arch: '
' + - '' + - '' + - '' + '' + '' + '' + '' + '' + '' + - '' + - '' + - '' + '
', res_id: 1, }); @@ -1715,40 +1708,29 @@ QUnit.module('fields', {}, function () { [5, 1, 'top', ['7', '6', '1', '2', '5']], // move the penultimate to the second line [2, 5, 'bottom', ['1', '2', '5', '6']], // move the third to the penultimate line ]; - async function dragAndDrop() { - var pos = positions.shift(); - + for (const [source, target, position, steps] of positions) { await testUtils.dom.dragAndDrop( - form.$('.ui-sortable-handle').eq(pos[0]), - form.$('tbody tr').eq(pos[1]), - { position: pos[2] } + form.$('.ui-sortable-handle').eq(source), + form.$('tbody tr').eq(target), + {position: position} ); - assert.verifySteps(pos[3], + await delay(10); + + assert.verifySteps(steps, "sequences values should be apply from the begin index to the drop index"); - - if (positions.length) { - - setTimeout(dragAndDrop, 10); - - } else { - - assert.deepEqual(_.pluck(form.model.get(form.handle).data.turtles.data, 'data'), [ - { id: 3, turtle_foo: "kawa", turtle_int: 2 }, - { id: 7, turtle_foo: "a4", turtle_int: 3 }, - { id: 1, turtle_foo: "yop", turtle_int: 4 }, - { id: 2, turtle_foo: "blip", turtle_int: 5 }, - { id: 5, turtle_foo: "a2", turtle_int: 6 }, - { id: 6, turtle_foo: "a3", turtle_int: 7 }, - { id: 4, turtle_foo: "a1", turtle_int: 8 } - ], "sequences must be apply correctly"); - - form.destroy(); - done(); - } } + assert.deepEqual(_.pluck(form.model.get(form.handle).data.turtles.data, 'data'), [ + { id: 3, turtle_foo: "kawa", turtle_int: 2 }, + { id: 7, turtle_foo: "a4", turtle_int: 3 }, + { id: 1, turtle_foo: "yop", turtle_int: 4 }, + { id: 2, turtle_foo: "blip", turtle_int: 5 }, + { id: 5, turtle_foo: "a2", turtle_int: 6 }, + { id: 6, turtle_foo: "a3", turtle_int: 7 }, + { id: 4, turtle_foo: "a1", turtle_int: 8 } + ], "sequences must be apply correctly"); - dragAndDrop(); + form.destroy(); }); QUnit.test('embedded one2many (editable list) with handle widget', async function (assert) { @@ -9720,7 +9702,7 @@ QUnit.module('fields', {}, function () { assert.expect(2); let o2m; - testUtils.patch(FieldOne2Many, { + testUtils.mock.patch(FieldOne2Many, { init() { this._super(...arguments); o2m = this; @@ -9747,7 +9729,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(o2m.recordData.display_name, "val"); form.destroy(); - testUtils.unpatch(FieldOne2Many); + testUtils.mock.unpatch(FieldOne2Many); }); QUnit.test('nested one2many, onchange, no command value', async function (assert) { diff --git a/addons/web/static/tests/legacy/fields/relational_fields_tests.js b/addons/web/static/tests/legacy/fields/relational_fields_tests.js index e60dca578bc..1757d121347 100644 --- a/addons/web/static/tests/legacy/fields/relational_fields_tests.js +++ b/addons/web/static/tests/legacy/fields/relational_fields_tests.js @@ -873,7 +873,7 @@ QUnit.module('relational_fields', { `, config: {device: {isMobile: false}}, }); - testUtils.intercept(form, 'call_service', function (ev) { + testUtils.mock.intercept(form, 'call_service', function (ev) { assert.strictEqual(ev.data.service, 'notification', "should display an 'invalid fields' notification"); }, true); @@ -1482,7 +1482,7 @@ QUnit.module('relational_fields', { assert.containsN(list, '.o_field_many2manytags .badge', 2, "there should be 2 tags"); assert.containsNone(list, '.badge.dropdown-toggle', "the tags should not be dropdowns"); - testUtils.intercept(list, 'switch_view', function (event) { + testUtils.mock.intercept(list, 'switch_view', function (event) { assert.strictEqual(event.data.view_type, "form", "should switch to form view"); }); // click on the tag: should do nothing and open the form view diff --git a/addons/web/static/tests/legacy/helpers/mock_server.js b/addons/web/static/tests/legacy/helpers/mock_server.js index 1a6f2d80b4c..2ce6392b56b 100644 --- a/addons/web/static/tests/legacy/helpers/mock_server.js +++ b/addons/web/static/tests/legacy/helpers/mock_server.js @@ -166,7 +166,15 @@ var MockServer = Class.extend({ var message = result && result.message; var event = result && result.event; var errorString = JSON.stringify(message || false); - console.warn('%c[rpc] response (error) ' + route, 'color: orange; font-weight: bold;', JSON.parse(errorString)); + if (debug) { + console.warn( + '%c[rpc] response (error) %s%s, during test %s', + 'color: orange; font-weight: bold;', + route, + message != null && ` -> ${errorString}`, + JSON.stringify(QUnit.config.current.testName) + ); + } return Promise.reject({message: errorString, event: event || $.Event()}); }); @@ -1152,7 +1160,7 @@ var MockServer = Class.extend({ if (!action) { // when the action doesn't exist, the real server doesn't crash, it // simply returns false - console.warn("No action found for ID " + kwargs.action_id); + console.warn(`No action found for ID ${kwargs.action_id} during test ${QUnit.config.current.testName} (legacy)`); } return action || false; }, diff --git a/addons/web/static/tests/legacy/qweb_tests.js b/addons/web/static/tests/legacy/qweb_tests.js index fda72e2392b..dd2b0c527ec 100644 --- a/addons/web/static/tests/legacy/qweb_tests.js +++ b/addons/web/static/tests/legacy/qweb_tests.js @@ -2,6 +2,7 @@ odoo.define('web.qweb_tests', function (require) { "use strict"; var qwebPath = '/web/static/lib/qweb/'; +const {hushConsole} = require('@web/../tests/helpers/utils'); function trim(s) { return s.replace(/(^\s+|\s+$)/g, ''); @@ -63,7 +64,13 @@ function loadTest(assert, template, context) { return prom; } -QUnit.module('QWeb', {}, function () { +QUnit.module('QWeb', { + before() { + this.oldConsole = window.console; + window.console = hushConsole; + }, + after() {window.console = this.oldConsole;} +}, function () { QUnit.test('Output', function (assert) { loadTest(assert, 'qweb-test-output.xml'); }); diff --git a/addons/web/static/tests/legacy/views/calendar_tests.js b/addons/web/static/tests/legacy/views/calendar_tests.js index 753e271c23e..b1d959775cd 100644 --- a/addons/web/static/tests/legacy/views/calendar_tests.js +++ b/addons/web/static/tests/legacy/views/calendar_tests.js @@ -2972,7 +2972,7 @@ QUnit.module('Views', { assert.strictEqual(calendar.$('.o_field_widget[name="start"]').text(), "12/16/2016 16:00:00"); // Move event 6 as on first day of month view (27th november 2016) - await testUtils.dragAndDrop( + await testUtils.dom.dragAndDrop( calendar.$('.fc-event').eq(5), calendar.$('.fc-day-top').first() ); @@ -3023,8 +3023,8 @@ QUnit.module('Views', { // Create event (on 20 december) var $cell = calendar.$('.fc-day-grid .fc-row:eq(3) .fc-day:eq(2)'); - await testUtils.triggerMouseEvent($cell, "mousedown"); - await testUtils.triggerMouseEvent($cell, "mouseup"); + await testUtils.dom.triggerMouseEvent($cell, "mousedown"); + await testUtils.dom.triggerMouseEvent($cell, "mouseup"); await testUtils.nextTick(); var $input = $('.modal-body input:first'); await testUtils.fields.editInput($input, "An event"); @@ -3036,7 +3036,7 @@ QUnit.module('Views', { assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_field_date').text(), '12/20/2016', "should have correct start date"); // Move event to another day (on 27 november) - await testUtils.dragAndDrop( + await testUtils.dom.dragAndDrop( calendar.$('.fc-event').first(), calendar.$('.fc-day-top').first() ); @@ -3047,7 +3047,7 @@ QUnit.module('Views', { assert.strictEqual(calendar.$('.o_cw_popover .o_cw_popover_fields_secondary .list-group-item:last .o_field_date').text(), '11/27/2016', "should have correct start date"); // Move event to last day (on 7 january) - await testUtils.dragAndDrop( + await testUtils.dom.dragAndDrop( calendar.$('.fc-event').first(), calendar.$('.fc-day-top').last() ); @@ -3077,8 +3077,8 @@ QUnit.module('Views', { // Create event (on 20 december) var $cell = calendar.$('.fc-day-grid .fc-row:eq(3) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + await testUtils.dom.triggerMouseEvent($cell, "mousedown"); + await testUtils.dom.triggerMouseEvent($cell, "mouseup"); await testUtils.nextTick(); var $input = $('.modal-body input:first'); await testUtils.fields.editInput($input, "An event"); @@ -3086,7 +3086,7 @@ QUnit.module('Views', { await testUtils.nextTick(); // Move event to another day (on 19 december) - await testUtils.dragAndDrop( + await testUtils.dom.dragAndDrop( calendar.$('.fc-event:contains("An event")'), calendar.$('.fc-day-grid .fc-row:eq(3) .fc-day-top:eq(1)') ); @@ -3121,8 +3121,8 @@ QUnit.module('Views', { // Create event (on 20 december) var $cell = calendar.$('.fc-day-grid .fc-row:eq(3) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + await testUtils.dom.triggerMouseEvent($cell, "mousedown"); + await testUtils.dom.triggerMouseEvent($cell, "mouseup"); await testUtils.nextTick(); var $input = $('.modal-body input:first'); await testUtils.fields.editInput($input, "An event"); @@ -3190,8 +3190,8 @@ QUnit.module('Views', { // Create event (on 20 december) var $cell = calendar.$('.fc-day-grid .fc-row:eq(3) .fc-day:eq(2)'); - await testUtils.triggerMouseEvent($cell, "mousedown"); - await testUtils.triggerMouseEvent($cell, "mouseup"); + await testUtils.dom.triggerMouseEvent($cell, "mousedown"); + await testUtils.dom.triggerMouseEvent($cell, "mouseup"); await testUtils.nextTick(); var $input = $('.modal-body input:first'); await testUtils.fields.editInput($input, "An event"); @@ -3199,7 +3199,7 @@ QUnit.module('Views', { await testUtils.nextTick(); // Move event to another day (on 27 november) - await testUtils.dragAndDrop( + await testUtils.dom.dragAndDrop( calendar.$('.fc-event').first(), calendar.$('.fc-day-top').first() ); @@ -3369,6 +3369,7 @@ QUnit.module('Views', { 'The day should be in the given locale specific format'); moment.locale(initialLocale); + moment.defineLocale('zz', null); calendar.destroy(); }); diff --git a/addons/web/static/tests/legacy/views/form_tests.js b/addons/web/static/tests/legacy/views/form_tests.js index fde1d1076b2..e2ee4864c79 100644 --- a/addons/web/static/tests/legacy/views/form_tests.js +++ b/addons/web/static/tests/legacy/views/form_tests.js @@ -9650,17 +9650,17 @@ QUnit.module('Views', { const $productLabel = form.$('.o_form_label:eq(1)'); $productLabel.tooltip('show', false); - $productLabel.trigger($.Event('mouseenter')); + await testUtils.dom.triggerMouseEvent($productLabel, 'mouseenter'); assert.strictEqual($('.tooltip .oe_tooltip_help').text().trim(), "this is a tooltip\n\nValues set here are company-specific."); - $productLabel.trigger($.Event('mouseleave')); + await testUtils.dom.triggerMouseEvent($productLabel, 'mouseleave'); const $fooLabel = form.$('.o_form_label:first'); $fooLabel.tooltip('show', false); - $fooLabel.trigger($.Event('mouseenter')); + await testUtils.dom.triggerMouseEvent($fooLabel, 'mouseenter'); assert.strictEqual($('.tooltip .oe_tooltip_help').text().trim(), "Values set here are company-specific."); - $fooLabel.trigger($.Event('mouseleave')); + await testUtils.dom.triggerMouseEvent($fooLabel, 'mouseleave'); form.destroy(); }); @@ -9689,9 +9689,9 @@ QUnit.module('Views', { const $productLabel = form.$('.o_form_label'); $productLabel.tooltip('show', false); - $productLabel.trigger($.Event('mouseenter')); + await testUtils.dom.triggerMouseEvent($productLabel, 'mouseenter'); assert.strictEqual($('.tooltip .oe_tooltip_help').text().trim(), "this is a tooltip"); - $productLabel.trigger($.Event('mouseleave')); + await testUtils.dom.triggerMouseEvent($productLabel, 'mouseleave'); form.destroy(); }); @@ -9704,7 +9704,7 @@ QUnit.module('Views', { model: 'partner', data: this.data, arch: `
- + `, }); diff --git a/addons/web/static/tests/legacy/views/kanban_tests.js b/addons/web/static/tests/legacy/views/kanban_tests.js index 1e737f0535f..4a7fb13e03e 100644 --- a/addons/web/static/tests/legacy/views/kanban_tests.js +++ b/addons/web/static/tests/legacy/views/kanban_tests.js @@ -2987,7 +2987,7 @@ QUnit.module('Views', { // drag&drop a record in another column var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first'); var $group = kanban.$('.o_kanban_group:nth-child(2)'); - await testUtils.dragAndDrop($record, $group); + await testUtils.dom.dragAndDrop($record, $group); // should not drag&drop record assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length , 2, diff --git a/addons/web/static/tests/legacy/views/search_panel_tests.js b/addons/web/static/tests/legacy/views/search_panel_tests.js index d50ecea676d..9a745ad6760 100644 --- a/addons/web/static/tests/legacy/views/search_panel_tests.js +++ b/addons/web/static/tests/legacy/views/search_panel_tests.js @@ -1144,7 +1144,7 @@ QUnit.module('Views', { "partner,false,search": ` - + `, @@ -2065,7 +2065,7 @@ QUnit.module('Views', { 'partner,false,search': ` - + `, @@ -4135,7 +4135,7 @@ QUnit.module('Views', { 'partner,false,search': ` - + `, diff --git a/addons/web/static/tests/legacy/widgets/model_field_selector_tests.js b/addons/web/static/tests/legacy/widgets/model_field_selector_tests.js index 69bb1eb9314..988fb7a757f 100644 --- a/addons/web/static/tests/legacy/widgets/model_field_selector_tests.js +++ b/addons/web/static/tests/legacy/widgets/model_field_selector_tests.js @@ -182,7 +182,7 @@ QUnit.module('ModelFieldSelector', { readonly: false, debugMode: true, }); - await testUtils.addMockEnvironment(fieldSelector, {data: this.data}); + await testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data}); await fieldSelector.appendTo($target); // Focusing the field selector input should open a field selector popover diff --git a/addons/web/static/tests/qunit.js b/addons/web/static/tests/qunit.js index d66bce60f8a..6203facd223 100644 --- a/addons/web/static/tests/qunit.js +++ b/addons/web/static/tests/qunit.js @@ -363,6 +363,13 @@ }); } }); + const oldError = QUnit.onError; + QUnit.onError = err => { + if (err.message === 'ResizeObserver loop limit exceeded') { + return true; + } + return oldError(err); + } // ----------------------------------------------------------------------------- // Add sort button diff --git a/addons/web/static/tests/webclient/actions/misc_tests.js b/addons/web/static/tests/webclient/actions/misc_tests.js index 3cde098f53d..578854c4a11 100644 --- a/addons/web/static/tests/webclient/actions/misc_tests.js +++ b/addons/web/static/tests/webclient/actions/misc_tests.js @@ -6,7 +6,7 @@ import core from "web.core"; import testUtils from "web.test_utils"; import Widget from "web.Widget"; import { makeTestEnv } from "../../helpers/mock_env"; -import { legacyExtraNextTick, patchWithCleanup } from "../../helpers/utils"; +import {hushConsole, legacyExtraNextTick, patchWithCleanup} from "../../helpers/utils"; import { createWebClient, doAction, @@ -97,6 +97,7 @@ QUnit.module("ActionManager", (hooks) => { QUnit.test("properly handle case when action id does not exist", async (assert) => { assert.expect(2); const webClient = await createWebClient({ serverData }); + patchWithCleanup(window, {console: hushConsole}, {pure: true}); patchWithCleanup(webClient.env.services.notification, { add(message) { assert.strictEqual(message, "No action with id '4448' could be found"); diff --git a/addons/web_tour/static/tests/tour_manager_tests.js b/addons/web_tour/static/tests/tour_manager_tests.js index 26ebaeb398c..b4e994733ad 100644 --- a/addons/web_tour/static/tests/tour_manager_tests.js +++ b/addons/web_tour/static/tests/tour_manager_tests.js @@ -14,16 +14,17 @@ odoo.define('web_tour.tour_manager_tests', async function (require) { /** * Create a widget and a TourManager instance with a list of given Tour objects. - * @see TourManager.register() for more details on the Tours registry system. - * @param {Object} params + * @see `TourManager.register()` for more details on the Tours registry system. + * @param {Object} params aside from the parameters defined below, passed + * to {@see addMockEnvironment}. * @param {string[]} [params.consumed_tours] - * @param {boolean} [params.debug] + * @param {boolean} [params.debug] also passed along * @param {boolean} [params.disabled] * @param {string} params.template inner HTML content of the widget * @param {Object[]} params.tours { {string} name, {Object} option, {Object[]} steps } */ - async function createTourManager({ consumed_tours, debug, disabled, template, tours }) { - const parent = await testUtils.createParent({ debug }); + async function createTourManager({ consumed_tours, disabled, template, tours, ...params }) { + const parent = await testUtils.createParent(params); const tourManager = new TourManager(parent, consumed_tours, disabled); tourManager.running_step_delay = 0; for (const { name, options, steps } of tours) { @@ -34,7 +35,7 @@ odoo.define('web_tour.tour_manager_tests', async function (require) { tourManager.destroy = _destroy; parent.destroy(); }; - await parent.prependTo(testUtils.prepareTarget(debug)); + await parent.prependTo(testUtils.prepareTarget(params.debug)); parent.el.innerHTML = template; await tourManager._register_all(true); // Wait for possible tooltips to be loaded and appended. @@ -75,6 +76,7 @@ odoo.define('web_tour.tour_manager_tests', async function (require) { assert.expect(5); const tourManager = await createTourManager({ + data: { 'web_tour.tour': { fields: {}, consume() {} } }, template: ` diff --git a/odoo/tests/common.py b/odoo/tests/common.py index c0040c37000..28a2e5c8e59 100644 --- a/odoo/tests/common.py +++ b/odoo/tests/common.py @@ -1051,11 +1051,22 @@ class ChromeBrowser(): res['success'] = 'test successful' in message if res.get('method') == 'Runtime.exceptionThrown': - exception_details = res['params']['exceptionDetails'] - descr = exception_details.get('exception', {}).get('description') - self.take_screenshot() - self._save_screencast() - raise ChromeBrowserException(descr or pprint.pformat(exception_details)) + details = res['params']['exceptionDetails'] + message = details['text'] + exception = details.get('exception') + if exception: + message += str(self._from_remoteobject(exception)) + details['type'] = 'trace' # fake this so _format_stack works + stack = ''.join(self._format_stack(details)) + if stack: + message += '\n' + stack + + if raise_log_error: + self.take_screenshot() + self._save_screencast() + raise ChromeBrowserException(message) + else: + self._logger.getChild('browser').error(message) return res @@ -1063,7 +1074,7 @@ class ChromeBrowser(): 'debug': logging.DEBUG, 'log': logging.INFO, 'info': logging.INFO, - 'warning': logging.INFO, # logging.WARNING, + 'warning': logging.WARNING, 'error': logging.ERROR, # TODO: what do with # dir, dirxml, table, trace, clear, startGroup, startGroupCollapsed,