summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/fields
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web/static/tests/fields')
-rw-r--r--addons/web/static/tests/fields/relational_fields/field_many2many_tests.js6
-rw-r--r--addons/web/static/tests/fields/relational_fields/field_many2one_tests.js6
-rw-r--r--addons/web/static/tests/fields/relational_fields/field_one2many_tests.js135
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js17
4 files changed, 147 insertions, 17 deletions
diff --git a/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js
index d7d18dfb86b..ed5fcd7f985 100644
--- a/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js
+++ b/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js
@@ -1383,8 +1383,7 @@ QUnit.module('fields', {}, function () {
await testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button'));
- var m2m_records = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_data_cell:not(.o_many2many_tags_cell)');
- assert.equal(m2m_records.length, 51,
+ assert.strictEqual(form.$('.o_data_row').length, 51,
'We should have added all the records present in the search view to the m2m field'); // the 50 in batch + 'gold'
await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_save'));
@@ -1411,8 +1410,7 @@ QUnit.module('fields', {}, function () {
await testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button'));
- pager_limit = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_pager_limit');
- assert.equal(pager_limit.text(), '51',
+ assert.strictEqual(form.$('.o_data_row').length, 51,
'We should have 51 records in the m2m field');
form.destroy();
diff --git a/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js b/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js
index 50e7ae2e6cb..e94797ff5f6 100644
--- a/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js
+++ b/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js
@@ -3293,13 +3293,16 @@ QUnit.module('fields', {}, function () {
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column when the product_id is set");
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
'', 'keyup');
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form, 'th:not(.o_list_record_remove_header)', 2,
"should be 2 columns in the one2many when product_id is not set");
await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column after the value change");
form.destroy();
@@ -3386,13 +3389,16 @@ QUnit.module('fields', {}, function () {
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column when the product_id is set");
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
'', 'keyup');
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form, 'th:not(.o_list_record_remove_header)', 2,
"should be 2 columns in the one2many when product_id is not set");
await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column after the value change");
form.destroy();
diff --git a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js
index 4d0055eb3b1..75346009aaf 100644
--- a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js
+++ b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js
@@ -3,6 +3,8 @@ odoo.define('web.field_one_to_many_tests', function (require) {
var AbstractField = require('web.AbstractField');
var AbstractStorageService = require('web.AbstractStorageService');
+const ControlPanel = require('web.ControlPanel');
+const fieldRegistry = require('web.field_registry');
var FormView = require('web.FormView');
var KanbanRecord = require('web.KanbanRecord');
var ListRenderer = require('web.ListRenderer');
@@ -2557,7 +2559,7 @@ QUnit.module('fields', {}, function () {
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.dom.click(form.$el);
- assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 5',
+ assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-4 / 5',
"pager should display the correct total");
form.destroy();
});
@@ -2869,7 +2871,7 @@ QUnit.module('fields', {}, function () {
});
QUnit.test('editable one2many list, adding line when only one page', async function (assert) {
- assert.expect(1);
+ assert.expect(5);
this.data.partner.records[0].turtles = [1, 2, 3];
var form = await createView({
@@ -2892,6 +2894,15 @@ QUnit.module('fields', {}, function () {
// the record currently being added should not count in the pager
assert.containsNone(form, '.o_field_widget[name=turtles] .o_pager');
+ // unselect the row
+ await testUtils.dom.click(form.$el);
+ assert.containsNone(form, '.o_selected_row');
+ assert.containsNone(form, '.o_field_widget[name=turtles] .o_pager');
+
+ await testUtils.form.clickSave(form);
+ assert.containsOnce(form, '.o_field_widget[name=turtles] .o_pager');
+ assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text(), "1-3 / 4");
+
form.destroy();
});
@@ -2993,13 +3004,13 @@ QUnit.module('fields', {}, function () {
// see a confirm dialog
await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
- assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 4',
+ assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-4 / 5',
"pager should still display the correct total");
// click on cancel
await testUtils.dom.click($('.modal .modal-footer .btn-secondary'));
- assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 4',
+ assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-4 / 5',
"pager should again display the correct total");
assert.containsOnce(form, '.o_field_one2many input.o_field_invalid',
"there should be an invalid input in the one2many");
@@ -3007,7 +3018,7 @@ QUnit.module('fields', {}, function () {
});
QUnit.test('editable one2many list, adding, discarding, and pager', async function (assert) {
- assert.expect(2);
+ assert.expect(4);
this.data.partner.records[0].turtles = [1];
@@ -3025,15 +3036,15 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- // add a 4 records record (to make the pager appear)
+ // add 4 records (to have more records than the limit)
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- // go on next page
- await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ assert.containsN(form, 'tr.o_data_row', 5);
+ assert.containsNone(form, '.o_field_widget[name=turtles] .o_pager');
// discard
await testUtils.form.clickDiscard(form);
@@ -4541,6 +4552,12 @@ QUnit.module('fields', {}, function () {
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ // use of owlCompatibilityNextTick because we have an x2many field with a boolean field
+ // (written in owl), so when we add a line, we sequentially render the list itself
+ // (including the boolean field), so we have to wait for the next animation frame, and
+ // then we render the control panel (also in owl), so we have to wait again for the
+ // next animation frame
+ await testUtils.owlCompatibilityNextTick();
form.destroy();
});
@@ -4571,6 +4588,12 @@ QUnit.module('fields', {}, function () {
},
});
await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ // use of owlCompatibilityNextTick because we have an x2many field with a boolean field
+ // (written in owl), so when we add a line, we sequentially render the list itself
+ // (including the boolean field), so we have to wait for the next animation frame, and
+ // then we render the control panel (also in owl), so we have to wait again for the
+ // next animation frame
+ await testUtils.owlCompatibilityNextTick();
assert.verifySteps(['onchange', 'onchange']);
form.destroy();
});
@@ -6071,6 +6094,7 @@ QUnit.module('fields', {}, function () {
// add a new row (which is invalid at first)
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.owlCompatibilityNextTick();
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0",
"int_field should still be 0 (no onchange should have been done yet)");
assert.verifySteps(['load_views', 'read', 'onchange']);
@@ -6693,13 +6717,14 @@ QUnit.module('fields', {}, function () {
await testUtils.form.clickEdit(form);
+ // add a new record page 1 (this increases the limit to 4)
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
- await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
- await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); // page 2: 4 records
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); // page 3: 2 records
- assert.containsN(form, 'tr.o_data_row', 3,
- "should have 3 data rows on the current page");
+ assert.containsN(form, 'tr.o_data_row', 2,
+ "should have 2 data rows on the current page");
form.destroy();
});
@@ -6885,7 +6910,11 @@ QUnit.module('fields', {}, function () {
});
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
-
+ // use of owlCompatibilityNextTick because we have a boolean field (owl) inside the
+ // x2many, so an update of the x2many requires to wait for 2 animation frames: one
+ // for the list to be re-rendered (with the boolean field) and one for the control
+ // panel.
+ await testUtils.owlCompatibilityNextTick();
await testUtils.dom.click(form.$('.o_field_widget[name=bar] input'));
assert.notOk(form.$('.o_field_widget[name=bar] input').prop('checked'),
"the checkbox should be unticked");
@@ -8430,13 +8459,16 @@ QUnit.module('fields', {}, function () {
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column when the product_id is set");
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
'', 'keyup');
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form, 'th:not(.o_list_record_remove_header)', 2,
"should be 2 columns in the one2many when product_id is not set");
await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column after the value change");
form.destroy();
@@ -8611,13 +8643,16 @@ QUnit.module('fields', {}, function () {
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column when the product_id is set");
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
'', 'keyup');
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form, 'th:not(.o_list_record_remove_header)', 2,
"should be 2 columns in the one2many when product_id is not set");
await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column after the value change");
form.destroy();
@@ -9110,6 +9145,12 @@ QUnit.module('fields', {}, function () {
// resolve the name_create to trigger the onchange, and the reset of p
prom.resolve();
await testUtils.nextTick();
+ // use of owlCompatibilityNextTick because we have two sequential updates of the
+ // fieldX2Many: one because of the onchange, and one because of the click on add a line.
+ // As an update requires an update of the ControlPanel, which is an Owl Component, and
+ // waits for it, we need to wait for two animation frames before seeing the new line in
+ // the DOM
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, '.o_data_row');
assert.hasClass(form.$('.o_data_row'), 'o_selected_row');
@@ -9331,6 +9372,74 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
+
+ QUnit.test('mounted is called only once for x2many control panel', async function (assert) {
+ // This test could be removed as soon as the field widgets will be converted in owl.
+ // It comes with a fix for a bug that occurred because in some circonstances, 'mounted'
+ // is called twice for the x2many control panel.
+ // Specifically, this occurs when there is 'pad' widget in the form view, because this
+ // widget does a 'setValue' in its 'start', which thus resets the field x2many.
+ assert.expect(5);
+
+ const PadLikeWidget = fieldRegistry.get('char').extend({
+ start() {
+ this._setValue("some value");
+ }
+ });
+ fieldRegistry.add('pad_like', PadLikeWidget);
+
+ let resolveCP;
+ const prom = new Promise(r => {
+ resolveCP = r;
+ });
+ ControlPanel.patch('cp_patch_mock', T =>
+ class extends T {
+ constructor() {
+ super(...arguments);
+ owl.hooks.onMounted(() => {
+ assert.step('mounted');
+ });
+ owl.hooks.onWillUnmount(() => {
+ assert.step('willUnmount');
+ });
+ }
+ async update() {
+ // the issue is a race condition, so we manually delay the update to turn it deterministic
+ await prom;
+ super.update(...arguments);
+ }
+ }
+ );
+
+ const form = await createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: `
+ <form>
+ <field name="foo" widget="pad_like"/>
+ <field name="p">
+ <tree><field name="display_name"/></tree>
+ </field>
+ </form>`,
+ viewOptions: {
+ withControlPanel: false, // s.t. there is only one CP: the one of the x2many
+ },
+ });
+
+ assert.verifySteps(['mounted']);
+
+ resolveCP();
+ await testUtils.nextTick();
+
+ assert.verifySteps([]);
+
+ ControlPanel.unpatch('cp_patch_mock');
+ delete fieldRegistry.map.pad_like;
+ form.destroy();
+
+ assert.verifySteps(["willUnmount"]);
+ });
});
});
});
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index 6ef0e402562..f93e7c35ace 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -474,9 +474,11 @@ QUnit.module('relational_fields', {
await testUtils.form.clickEdit(form);
// add a line (virtual record)
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.owlCompatibilityNextTick();
await testUtils.fields.editInput(form.$('.o_input'), 'pi');
// delete the line above it
await testUtils.dom.click(form.$('.o_list_record_remove').first());
+ await testUtils.owlCompatibilityNextTick();
// the next line should be displayed below the newly added one
assert.strictEqual(form.$('.o_data_row').length, 2, "should have 2 records");
assert.strictEqual(form.$('.o_data_row .o_data_cell:first-child').text(), 'pikawa',
@@ -2535,6 +2537,7 @@ QUnit.module('relational_fields', {
});
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.owlCompatibilityNextTick();
await testUtils.fields.many2one.searchAndClickItem('product_id',
{selector: '.modal', search: 'new record'});
@@ -3070,13 +3073,16 @@ QUnit.module('relational_fields', {
await testUtils.form.clickEdit(form);
await testUtils.fields.many2one.clickOpenDropdown("product_id");
await testUtils.fields.many2one.clickHighlightedItem("product_id");
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column when the product_id is set");
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
'', 'keyup');
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form, 'th:not(.o_list_record_remove_header)', 2,
"should be 2 columns in the one2many when product_id is not set");
await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column after the value change");
form.destroy();
@@ -3164,13 +3170,16 @@ QUnit.module('relational_fields', {
await testUtils.form.clickEdit(form);
await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
await testUtils.fields.many2one.clickHighlightedItem("product_id");
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column when the product_id is set");
await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
'', 'keyup');
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form, 'th:not(.o_list_record_remove_header)', 2,
"should be 2 columns in the one2many when product_id is not set");
await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.owlCompatibilityNextTick();
assert.containsOnce(form, 'th:not(.o_list_record_remove_header)',
"should be 1 column after the value change");
form.destroy();
@@ -3230,6 +3239,13 @@ QUnit.module('relational_fields', {
assert.containsN(form.$('.o_field_one2many'), 'div.o_optional_columns div.dropdown-item:visible', 2,
"dropdown is still open");
await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ // use of owlCompatibilityNextTick because the x2many field is reset, meaning that
+ // 1) its list renderer is updated (updateState is called): this is async and as it
+ // contains a FieldBoolean, which is written in Owl, it completes in the nextAnimationFrame
+ // 2) when this is done, the control panel is updated: as it is written in owl, this is
+ // done in the nextAnimationFrame
+ // -> we need to wait for 2 nextAnimationFrame to ensure that everything is fine
+ await testUtils.owlCompatibilityNextTick();
assert.containsN(form.$('.o_field_one2many'), 'div.o_optional_columns div.dropdown-item:visible', 0,
"dropdown is closed");
var $selectedRow = form.$('.o_field_one2many tr.o_selected_row');
@@ -3329,6 +3345,7 @@ QUnit.module('relational_fields', {
which: $.ui.keyCode.TAB,
keyCode: $.ui.keyCode.TAB,
}));
+ await testUtils.owlCompatibilityNextTick();
await testUtils.dom.click(document.activeElement);
assert.strictEqual(assert.strictEqual(form.$el.find('input[name="turtle_foo"]')[0],
document.activeElement,