[FIX] *: JS runner and large number of JS warnings

Currently the JS logs are full of warnings and it doesn't really matter because they don't block CI.

This PR:

* flips JS warnings to trigger Python warnings
* improves qunit's logging (hopefully) so test failures are more readable and actionable
* fixes / removes / downgrades JS warnings occurring during runbot runs
* also other updates probably

closes odoo/odoo#71845

Related: odoo/enterprise#18949
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
This commit is contained in:
Odoo's Mergebot
2021-06-29 08:06:04 +02:00
committed by GitHub
24 changed files with 162 additions and 137 deletions
+2 -2
View File
@@ -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) {
+4 -4
View File
@@ -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();
});
@@ -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,
+4 -2
View File
@@ -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.`);
@@ -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);
},
@@ -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) => {
+3 -9
View File
@@ -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
@@ -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;
+5
View File
@@ -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] = () => {}
}
@@ -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);
});
});
});
@@ -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();
@@ -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: '<form string="Partners">' +
'<sheet>' +
'<notebook>' +
'<page string="P page">' +
'<field name="turtles">' +
'<tree default_order="turtle_int">' +
'<field name="turtle_int" widget="handle"/>' +
'<field name="turtle_foo"/>' +
'</tree>' +
'</field>' +
'</page>' +
'</notebook>' +
'</sheet>' +
'</form>',
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) {
@@ -873,7 +873,7 @@ QUnit.module('relational_fields', {
</form>`,
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
@@ -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;
},
+8 -1
View File
@@ -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');
});
@@ -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();
});
@@ -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: `<form>
<widget name="pie_chart" title="qux by product" attrs="{'measure\': 'qux', 'groupby': 'product_id'}"/>
<widget name="pie_chart" title="qux by product" attrs="{'measure': 'qux', 'groupby': 'product_id'}"/>
</form>`,
});
@@ -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,
@@ -1144,7 +1144,7 @@ QUnit.module('Views', {
"partner,false,search": `
<search>
<searchpanel>
<field name="category_id" enable_counters="1"/>
<field name="category_id"/>
<field name="company_id" select="multi" domain="[['category_id', '=', category_id]]" enable_counters="1"/>
</searchpanel>
</search>`,
@@ -2065,7 +2065,7 @@ QUnit.module('Views', {
'partner,false,search': `
<search>
<searchpanel>
<field name="category_id" enable_counters="1"/>
<field name="category_id"/>
<field name="company_id" select="multi" domain="[['category_id', '=', category_id]]" enable_counters="1"/>
</searchpanel>
</search>`,
@@ -4135,7 +4135,7 @@ QUnit.module('Views', {
'partner,false,search': `
<search>
<searchpanel>
<field name="category_id" enable_counters="1"/>
<field name="category_id"/>
<field name="company_id" select="multi" domain="[['category_id', '=', category_id]]"/>
</searchpanel>
</search>`,
@@ -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
+7
View File
@@ -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
@@ -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");
@@ -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: `
<button class="btn anchor1">Anchor</button>
<button class="btn anchor2">Anchor</button>
+17 -6
View File
@@ -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,