diff options
| author | Vincent Schippefilt <vsc@odoo.com> | 2019-03-06 14:02:32 +0100 |
|---|---|---|
| committer | Aaron Bohy <aab@odoo.com> | 2019-03-06 20:07:17 +0100 |
| commit | ab56e637b7f97ddcdbcc9baea99ae097e342409c (patch) | |
| tree | 4cb47da9f7ef89b19d18429220a7507470ec12a9 /addons/web/static/tests/fields/relational_fields/field_many2one_tests.js | |
| parent | eeed894fd50e477135e1ac9a82f6e98ce063ab90 (diff) | |
[REF] web: adapt code after jQuery update
Part of task 1896658
Co-authored-by: Aaron Bohy <aab@odoo.com>
Co-authored-by: Christophe Matthieu <chm@odoo.com>
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Co-authored-by: David Monjoie <dmo@odoo.com>
Co-authored-by: Martin Geubelle <mge@odoo.com>
Co-authored-by: svs-odoo <svs@odoo.com>
Co-authored-by: Vincent Schippefilt <vsc@odoo.com>
Diffstat (limited to 'addons/web/static/tests/fields/relational_fields/field_many2one_tests.js')
| -rw-r--r-- | addons/web/static/tests/fields/relational_fields/field_many2one_tests.js | 1080 |
1 files changed, 511 insertions, 569 deletions
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 04b58b017ba..4f2a3d03bed 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 @@ -150,13 +150,13 @@ QUnit.module('fields', {}, function () { }] }, }; - } + }, }, function () { QUnit.module('FieldMany2One'); - QUnit.test('many2ones in form views', function (assert) { + QUnit.test('many2ones in form views', async function (assert) { assert.expect(5); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -174,7 +174,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { if (args.method === 'get_formview_action') { assert.deepEqual(args.args[0], [4], "should call get_formview_action with correct id"); - return $.when({ + return Promise.resolve({ res_id: 17, type: 'ir.actions.act_window', target: 'current', @@ -183,7 +183,7 @@ QUnit.module('fields', {}, function () { } if (args.method === 'get_formview_id') { assert.deepEqual(args.args[0], [4], "should call get_formview_id with correct id"); - return $.when(false); + return Promise.resolve(false); } return this._super(route, args); }, @@ -196,23 +196,22 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('a.o_form_uri:contains(aaa)').length, 1, "should contain a link"); - testUtils.dom.click(form.$('a.o_form_uri')); + await testUtils.dom.click(form.$('a.o_form_uri')); - testUtils.form.clickEdit(form); - - testUtils.dom.click(form.$('.o_external_button')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_external_button')); assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: custom label', "dialog title should display the custom string label"); - // TODO: test that we can edit the record in the dialog, and that the value is correctly - // updated on close + // TODO: test that we can edit the record in the dialog, and that + // the value is correctly updated on close form.destroy(); }); - QUnit.test('editing a many2one, but not changing anything', function (assert) { + QUnit.test('editing a many2one, but not changing anything', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -228,7 +227,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { if (args.method === 'get_formview_id') { assert.deepEqual(args.args[0], [4], "should call get_formview_id with correct id"); - return $.when(false); + return Promise.resolve(false); } return this._super(route, args); }, @@ -237,16 +236,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // click on the external button (should do an RPC) - testUtils.dom.click(form.$('.o_external_button')); + await testUtils.dom.click(form.$('.o_external_button')); // save and close modal - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); // save form - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); // click next on pager - testUtils.dom.click(form.pager.$('.o_pager_next')); + await testUtils.dom.click(form.pager.$('.o_pager_next')); // this checks that the view did not ask for confirmation that the // record is dirty @@ -255,13 +254,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('context in many2one and default get', function (assert) { + QUnit.test('context in many2one and default get', async function (assert) { assert.expect(1); this.data.partner.fields.int_field.default = 14; this.data.partner.fields.trululu.default = 2; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -280,9 +279,9 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editing a many2one (with form view opened with external button)', function (assert) { + QUnit.test('editing a many2one (with form view opened with external button)', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -297,7 +296,7 @@ QUnit.module('fields', {}, function () { res_id: 1, mockRPC: function (route, args) { if (args.method === 'get_formview_id') { - return $.when(false); + return Promise.resolve(false); } return this._super(route, args); }, @@ -306,19 +305,19 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // click on the external button (should do an RPC) - testUtils.dom.click(form.$('.o_external_button')); + await testUtils.dom.click(form.$('.o_external_button')); - testUtils.fields.editInput($('.modal input[name="foo"]'), 'brandon'); + await testUtils.fields.editInput($('.modal input[name="foo"]'), 'brandon'); // save and close modal - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); // save form - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); // click next on pager - testUtils.dom.click(form.pager.$('.o_pager_next')); + await testUtils.dom.click(form.pager.$('.o_pager_next')); // this checks that the view did not ask for confirmation that the // record is dirty @@ -327,9 +326,9 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2ones in form views with show_adress', function (assert) { + QUnit.test('many2ones in form views with show_adress', async function (assert) { assert.expect(4); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -359,7 +358,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('a.o_form_uri').html(), 'aaa<br>Street<br>City ZIP', "input should have a multi-line content in readonly due to show_address"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsOnce(form, 'button.o_external_button:visible', "should have an open record button"); @@ -374,12 +373,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('show_address works in a view embedded in a view of another type', function (assert) { + QUnit.test('show_address works in a view embedded in a view of another type', async function (assert) { assert.expect(1); this.data.turtle.records[1].turtle_trululu = 2; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -410,19 +409,19 @@ QUnit.module('fields', {}, function () { }, }); // click the turtle field, opens a modal with the turtle form view - testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell')); + await testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell')); assert.strictEqual($('[name="turtle_trululu"]').text(), "second recordrue morgueparis 75013", "The partner's address should be displayed"); form.destroy(); }); - QUnit.test('many2one data is reloaded if there is a context to take into account', function (assert) { + QUnit.test('many2one data is reloaded if there is a context to take into account', async function (assert) { assert.expect(1); this.data.turtle.records[1].turtle_trululu = 2; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -454,14 +453,14 @@ QUnit.module('fields', {}, function () { }, }); // click the turtle field, opens a modal with the turtle form view - testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal [name=turtle_trululu]').text(), "second recordrue morgueparis 75013", "The partner's address should be displayed"); form.destroy(); }); - QUnit.test('many2ones in form views with search more', function (assert) { + QUnit.test('many2ones in form views with search more', async function (assert) { assert.expect(3); this.data.partner.records.push({ id: 5, @@ -483,7 +482,7 @@ QUnit.module('fields', {}, function () { display_name: "Partner 9", }); this.data.partner.fields.datetime.searchable = true; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -501,29 +500,29 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.fields.many2one.clickOpenDropdown('trululu'); - testUtils.fields.many2one.clickItem('trululu', 'Search'); + await testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickItem('trululu', 'Search'); assert.strictEqual($('tr.o_data_row').length, 9, "should display 9 records"); - testUtils.dom.click($('button:contains(Filters)')); - testUtils.dom.click($('.o_add_custom_filter:visible')); + await testUtils.dom.click($('button:contains(Filters)')); + await testUtils.dom.click($('.o_add_custom_filter:visible')); assert.strictEqual($('.o_filter_condition select.o_searchview_extended_prop_field').val(), 'datetime', "datetime field should be selected"); - testUtils.dom.click($('.o_apply_filter')); + await testUtils.dom.click($('.o_apply_filter')); assert.strictEqual($('tr.o_data_row').length, 0, "should display 0 records"); form.destroy(); }); - QUnit.test('onchanges on many2ones trigger when editing record in form view', function (assert) { + QUnit.test('onchanges on many2ones trigger when editing record in form view', async function (assert) { assert.expect(10); this.data.partner.onchanges.user_id = function () { }; this.data.user.fields.other_field = { string: "Other Field", type: "char" }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -541,7 +540,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { assert.step(args.method); if (args.method === 'get_formview_id') { - return $.when(false); + return Promise.resolve(false); } if (args.method === 'onchange') { assert.strictEqual(args.args[1].user_id, 17, @@ -552,25 +551,25 @@ QUnit.module('fields', {}, function () { }); // open the many2one in form view and change something - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_external_button')); - testUtils.fields.editInput($('.modal-body input[name="other_field"]'), 'wood'); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_external_button')); + await testUtils.fields.editInput($('.modal-body input[name="other_field"]'), 'wood'); // save the modal and make sure an onchange is triggered - testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); + await testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']); // save the main record, and check that no extra rpcs are done (record // is not dirty, only a related record was modified) - testUtils.form.clickSave(form); - assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']); + await testUtils.form.clickSave(form); + assert.verifySteps([]); form.destroy(); }); - QUnit.test('many2one fields with option "no_open"', function (assert) { + QUnit.test('many2one fields with option "no_open"', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -588,13 +587,13 @@ QUnit.module('fields', {}, function () { "should be displayed inside a span (sanity check)"); assert.containsNone(form, 'span.o_form_uri', "should not have an anchor"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsNone(form, '.o_field_widget[name=trululu] .o_external_button', "should not have the button to open the record"); form.destroy(); }); - QUnit.test('many2one in edit mode', function (assert) { + QUnit.test('many2one in edit mode', async function (assert) { assert.expect(16); // create 10 partners to have the 'Search More' option in the autocomplete dropdown @@ -603,7 +602,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records.push({ id: id, display_name: "Partner " + id }); } - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -635,11 +634,11 @@ QUnit.module('fields', {}, function () { event.data.callback({ user_context: {} }); }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickOpenDropdown('trululu'); assert.ok($dropdown.is(':visible'), 'clicking on the m2o input should open the dropdown if it is not open yet'); assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 7, @@ -647,51 +646,50 @@ QUnit.module('fields', {}, function () { assert.strictEqual($dropdown.find('li.o_m2o_dropdown_option').length, 2, 'autocomplete should contain "Search More" and Create and Edit..."'); - testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickOpenDropdown('trululu'); assert.ok(!$dropdown.is(':visible'), 'clicking on the m2o input should close the dropdown if it is open'); // change the value of the m2o with a suggestion of the dropdown - testUtils.fields.many2one.clickOpenDropdown('trululu'); - testUtils.fields.many2one.clickHighlightedItem('trululu'); + await testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickHighlightedItem('trululu'); assert.ok(!$dropdown.is(':visible'), 'clicking on a value should close the dropdown'); assert.strictEqual(form.$('.o_field_many2one input').val(), 'first record', 'value of the m2o should have been correctly updated'); // change the value of the m2o with a record in the 'Search More' modal - testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickOpenDropdown('trululu'); // click on 'Search More' (mouseenter required by ui-autocomplete) - testUtils.fields.many2one.clickItem('trululu', 'Search'); + await testUtils.fields.many2one.clickItem('trululu', 'Search'); assert.ok($('.modal .o_list_view').length, "should have opened a list view in a modal"); assert.ok(!$('.modal .o_list_view .o_list_record_selector').length, "there should be no record selector in the list view"); assert.ok(!$('.modal .modal-footer .o_select_button').length, "there should be no 'Select' button in the footer"); assert.ok($('.modal tbody tr').length > 10, "list should contain more than 10 records"); - // filter the list using the searchview - $('.modal .o_searchview_input').trigger({ type: 'keypress', which: 80 }); // P - $('.modal .o_searchview_input').trigger({ type: 'keydown', which: 13 }); // enter + await testUtils.fields.triggerKey('press', $('.modal .o_searchview_input'), 'P'), + await testUtils.fields.triggerKeydown($('.modal .o_searchview_input'), 'enter'); assert.strictEqual($('.modal tbody tr').length, 10, "list should be restricted to records containing a P (10 records)"); // choose a record - testUtils.dom.click($('.modal tbody tr:contains(Partner 20)')); + await testUtils.dom.click($('.modal tbody tr:contains(Partner 20)')); assert.ok(!$('.modal').length, "should have closed the modal"); assert.ok(!$dropdown.is(':visible'), 'should have closed the dropdown'); assert.strictEqual(form.$('.o_field_many2one input').val(), 'Partner 20', 'value of the m2o should have been correctly updated'); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('a.o_form_uri').text(), 'Partner 20', "should display correct value after save"); form.destroy(); }); - QUnit.test('many2one in non edit mode', function (assert) { + QUnit.test('many2one in non edit mode', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -707,9 +705,9 @@ QUnit.module('fields', {}, function () { "href should contain id and model"); // Remove value from many2one and then save, there should not have href with id and model on m2o anchor - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); form.$('.o_field_many2one input').val('').trigger('keyup').trigger('focusout'); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.hasAttrValue(form.$('a.o_form_uri'), 'href', "#", "href should have #"); @@ -717,14 +715,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2one searches with correct value', function (assert) { - var done = assert.async(); + QUnit.test('many2one searches with correct value', async function (assert) { assert.expect(6); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -748,31 +745,27 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_field_many2one input').val(), 'aaa', "should be initially set to 'aaa'"); - testUtils.dom.click(form.$('.o_field_many2one input')); + await testUtils.dom.click(form.$('.o_field_many2one input')); // unset the many2one -> should search again with '' form.$('.o_field_many2one input').val('').trigger('keydown'); - concurrency.delay(0).then(function () { - // write 'p' -> should search with 'p' - form.$('.o_field_many2one input').val('p').trigger('keydown').trigger('keyup'); + await testUtils.nextTick(); + form.$('.o_field_many2one input').val('p').trigger('keydown').trigger('keyup'); + await testUtils.nextTick(); - return concurrency.delay(0); - }).then(function () { - // close and re-open the dropdown -> should search with 'p' again - testUtils.dom.click(form.$('.o_field_many2one input')); - testUtils.dom.click(form.$('.o_field_many2one input')); + // close and re-open the dropdown -> should search with 'p' again + await testUtils.dom.click(form.$('.o_field_many2one input')); + await testUtils.dom.click(form.$('.o_field_many2one input')); - assert.verifySteps(['search: ', 'search: ', 'search: p', 'search: p']); + assert.verifySteps(['search: ', 'search: ', 'search: p', 'search: p']); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; + form.destroy(); }); - QUnit.test('many2one field with option always_reload', function (assert) { + QUnit.test('many2one field with option always_reload', async function (assert) { assert.expect(4); var count = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -783,7 +776,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { if (args.method === 'name_get') { count++; - return $.when([[1, "first record\nand some address"]]); + return Promise.resolve([[1, "first record\nand some address"]]); } return this._super(route, args); }, @@ -793,22 +786,22 @@ QUnit.module('fields', {}, function () { assert.ok(form.$('a:contains(and some address)').length, "should display additional result"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name=trululu] input').val(), "first record", "actual field value should be displayed to be edited"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.ok(form.$('a:contains(and some address)').length, "should still display additional result"); form.destroy(); }); - QUnit.test('many2one field and list navigation', function (assert) { + QUnit.test('many2one field and list navigation', async function (assert) { assert.expect(3); - var list = createView({ + var list = await createView({ View: ListView, model: 'partner', data: this.data, @@ -816,14 +809,11 @@ QUnit.module('fields', {}, function () { }); // edit first input, to trigger autocomplete - testUtils.dom.click(list.$('.o_data_row .o_data_cell').first()); - testUtils.fields.editInput(list.$('.o_data_cell input'), ''); + await testUtils.dom.click(list.$('.o_data_row .o_data_cell').first()); + await testUtils.fields.editInput(list.$('.o_data_cell input'), ''); // press keydown, to select first choice - list.$('.o_data_cell input').focus().trigger($.Event('keydown', { - which: $.ui.keyCode.DOWN, - keyCode: $.ui.keyCode.DOWN, - })); + await testUtils.fields.triggerKeydown(list.$('.o_data_cell input').focus(), 'down'); // we now check that the dropdown is open (and that the focus did not go // to the next line) @@ -839,7 +829,6 @@ QUnit.module('fields', {}, function () { QUnit.test('standalone many2one field', async function (assert) { assert.expect(4); - var done = assert.async(); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; @@ -851,54 +840,53 @@ QUnit.module('fields', {}, function () { Model: BasicModel, data: this.data, }); - + var record; model.makeRecord('coucou', [{ name: 'partner_id', relation: 'partner', type: 'many2one', value: [1, 'first partner'], }]).then(function (recordID) { - var record = model.get(recordID); - // create a new widget that uses the StandaloneFieldManagerMixin - var StandaloneWidget = Widget.extend(StandaloneFieldManagerMixin, { - init: function (parent) { - this._super.apply(this, arguments); - StandaloneFieldManagerMixin.init.call(this, parent); - }, - }); - var parent = new StandaloneWidget(model); - testUtils.mock.addMockEnvironment(parent, { - data: self.data, - mockRPC: function (route, args) { - assert.step(args.method); - return this._super.apply(this, arguments); - }, - }); + record = model.get(recordID); + }); + await testUtils.nextTick(); + // create a new widget that uses the StandaloneFieldManagerMixin + var StandaloneWidget = Widget.extend(StandaloneFieldManagerMixin, { + init: function (parent) { + this._super.apply(this, arguments); + StandaloneFieldManagerMixin.init.call(this, parent); + }, + }); + var parent = new StandaloneWidget(model); + testUtils.mock.addMockEnvironment(parent, { + data: self.data, + mockRPC: function (route, args) { + assert.step(args.method); + return this._super.apply(this, arguments); + }, + }); - var relField = new relationalFields.FieldMany2One(parent, 'partner_id', record, { - mode: 'edit', - noOpen: true, - }); + var relField = new relationalFields.FieldMany2One(parent, 'partner_id', record, { + mode: 'edit', + noOpen: true, + }); - relField.appendTo(fixture); - testUtils.fields.editInput($('input.o_input'), 'xyzzrot'); + relField.appendTo(fixture); + await testUtils.nextTick(); + await testUtils.fields.editInput($('input.o_input'), 'xyzzrot'); - concurrency.delay(0).then(function () { - testUtils.fields.many2one.clickItem('partner_id', 'Create'); + await testUtils.fields.many2one.clickItem('partner_id', 'Create'); - assert.containsNone(relField, '.o_external_button', - "should not have the button to open the record"); - assert.verifySteps(['name_search', 'name_create']); + assert.containsNone(relField, '.o_external_button', + "should not have the button to open the record"); + assert.verifySteps(['name_search', 'name_create']); - parent.destroy(); - model.destroy(); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - done(); - }); - }); + parent.destroy(); + model.destroy(); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; }); - // QUnit.test('onchange on a many2one to a different model', function (assert) { + // QUnit.test('onchange on a many2one to a different model', async function (assert) { // This test is commented because the mock server does not give the correct response. // It should return a couple [id, display_name], but I don't know the logic used // by the server, so it's hard to emulate it correctly @@ -911,7 +899,7 @@ QUnit.module('fields', {}, function () { // }, // }; - // var form = createView({ + // var form = await createView({ // View: FormView, // model: 'partner', // data: this.data, @@ -921,7 +909,7 @@ QUnit.module('fields', {}, function () { // '</form>', // res_id: 1, // }); - // testUtils.form.clickEdit(form); + // await testUtils.form.clickEdit(form); // assert.strictEqual(form.$('input').eq(1).val(), 'xpad', "initial product_id val should be xpad"); // testUtils.fields.editInput(form.$('input').eq(0), "let us trigger an onchange"); @@ -932,9 +920,9 @@ QUnit.module('fields', {}, function () { QUnit.test('form: quick create then save directly', async function (assert) { assert.expect(5); - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); var newRecordID; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -945,7 +933,7 @@ QUnit.module('fields', {}, function () { var result = this._super.apply(this, arguments); if (args.method === 'name_create') { assert.step('name_create'); - return def.then(_.constant(result)).then(function (nameGet) { + return prom.then(_.constant(result)).then(function (nameGet) { newRecordID = nameGet[0]; return nameGet; }); @@ -959,23 +947,24 @@ QUnit.module('fields', {}, function () { }, }); await testUtils.fields.many2one.searchAndClickItem('trululu', {search: 'b'}); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.verifySteps(['name_create'], "should wait for the name_create before creating the record"); - def.resolve(); + await prom.resolve(); + await testUtils.nextTick(); - assert.verifySteps(['name_create', 'create']); + assert.verifySteps(['create']); form.destroy(); }); QUnit.test('list: quick create then save directly', async function (assert) { assert.expect(8); - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); var newRecordID; - var list = createView({ + var list = await createView({ View: ListView, model: 'partner', data: this.data, @@ -986,7 +975,7 @@ QUnit.module('fields', {}, function () { var result = this._super.apply(this, arguments); if (args.method === 'name_create') { assert.step('name_create'); - return def.then(_.constant(result)).then(function (nameGet) { + return prom.then(_.constant(result)).then(function (nameGet) { newRecordID = nameGet[0]; return nameGet; }); @@ -1000,7 +989,7 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(list.$buttons.find('.o_list_button_add')); + await testUtils.dom.click(list.$buttons.find('.o_list_button_add')); await testUtils.fields.many2one.searchAndClickItem('trululu', {search:'b'}); list.$buttons.find('.o_list_button_add').show(); @@ -1011,9 +1000,10 @@ QUnit.module('fields', {}, function () { assert.containsN(list, '.o_data_row', 4, "should wait for the name_create before adding the new row"); - def.resolve(); + await prom.resolve(); + await testUtils.nextTick(); - assert.verifySteps(['name_create', 'create']); + assert.verifySteps(['create']); assert.strictEqual(list.$('.o_data_row:nth(1) .o_data_cell').text(), 'b', "created row should have the correct m2o value"); assert.containsN(list, '.o_data_row', 5, "should have added the fifth row"); @@ -1024,9 +1014,9 @@ QUnit.module('fields', {}, function () { QUnit.test('list in form: quick create then save directly', async function (assert) { assert.expect(6); - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); var newRecordID; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1043,7 +1033,7 @@ QUnit.module('fields', {}, function () { var result = this._super.apply(this, arguments); if (args.method === 'name_create') { assert.step('name_create'); - return def.then(_.constant(result)).then(function (nameGet) { + return prom.then(_.constant(result)).then(function (nameGet) { newRecordID = nameGet[0]; return nameGet; }); @@ -1057,28 +1047,28 @@ QUnit.module('fields', {}, function () { }, }); - 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.fields.many2one.searchAndClickItem('trululu', {search: 'b'}); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.verifySteps(['name_create'], "should wait for the name_create before creating the record"); - def.resolve(); + await prom.resolve(); + await testUtils.nextTick(); - assert.verifySteps(['name_create', 'create']); + assert.verifySteps(['create']); assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b', "first row should have the correct m2o value"); form.destroy(); }); - QUnit.test('list in form: quick create then add a new line directly', function (assert) { + QUnit.test('list in form: quick create then add a new line directly', async function (assert) { // required many2one inside a one2many list: directly after quick creating // a new many2one value (before the name_create returns), click on add an item: // at this moment, the many2one has still no value, and as it is required, // the row is discarded if a saveLine is requested. However, it should // wait for the name_create to return before trying to save the line. - var done = assert.async(); assert.expect(8); this.data.partner.onchanges = { @@ -1088,9 +1078,9 @@ QUnit.module('fields', {}, function () { var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); var newRecordID; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1106,7 +1096,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { var result = this._super.apply(this, arguments); if (args.method === 'name_create') { - return def.then(_.constant(result)).then(function (nameGet) { + return prom.then(_.constant(result)).then(function (nameGet) { newRecordID = nameGet[0]; return nameGet; }); @@ -1118,43 +1108,42 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - form.$('.o_field_many2one input').val('b').trigger('keydown'); - concurrency.delay(0).then(function () { - testUtils.fields.many2one.clickHighlightedItem('trululu'); - 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.fields.editAndTrigger(form.$('.o_field_many2one input'), + 'b', 'keydown'); + await testUtils.fields.many2one.clickHighlightedItem('trululu'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.containsOnce(form, '.o_data_row', - "there should still be only one row"); - assert.hasClass(form.$('.o_data_row'),'o_selected_row', - "the row should still be in edition"); + assert.containsOnce(form, '.o_data_row', + "there should still be only one row"); + assert.hasClass(form.$('.o_data_row'),'o_selected_row', + "the row should still be in edition"); - def.resolve(); + await prom.resolve(); + await testUtils.nextTick(); - assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b', - "first row should have the correct m2o value"); - assert.containsN(form, '.o_data_row', 2, - "there should now be 2 rows"); - assert.hasClass(form.$('.o_data_row:nth(1)'),'o_selected_row', - "the second row should be in edition"); + assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b', + "first row should have the correct m2o value"); + assert.containsN(form, '.o_data_row', 2, + "there should now be 2 rows"); + assert.hasClass(form.$('.o_data_row:nth(1)'),'o_selected_row', + "the second row should be in edition"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); - assert.containsOnce(form, '.o_data_row', - "there should be 1 row saved (the second one was empty and invalid)"); - assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'b', - "should have the correct m2o value"); + assert.containsOnce(form, '.o_data_row', + "there should be 1 row saved (the second one was empty and invalid)"); + assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'b', + "should have the correct m2o value"); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; + form.destroy(); }); - QUnit.test('list in form: create with one2many with many2one', function (assert) { + QUnit.test('list in form: create with one2many with many2one', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1170,7 +1159,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ p: [[0, 0, { display_name: 'new record' }]] }); + return Promise.resolve({ p: [[0, 0, { display_name: 'new record' }]] }); } else if (args.method === 'name_get') { // This should not be called at all and thus is not accounted for // in the assert.expect. If this is called, you broke this test. @@ -1187,13 +1176,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('list in form: create with one2many with many2one (version 2)', function (assert) { + QUnit.test('list in form: create with one2many with many2one (version 2)', async function (assert) { // This test simulates the exact same scenario as the previous one, // except that the value for the many2one is explicitely set to false, // which is stupid, but this happens, so we have to handle it assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1209,7 +1198,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ p: [[0, 0, { display_name: 'new record', trululu: false }]] }); + return Promise.resolve({ p: [[0, 0, { display_name: 'new record', trululu: false }]] }); } else if (args.method === 'name_get') { // This should not be called at all and thus is not accounted for // in the assert.expect. If this is called, you broke this test. @@ -1226,14 +1215,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('item not dropped on discard with empty required field (default_get)', function (assert) { + QUnit.test('item not dropped on discard with empty required field (default_get)', async function (assert) { // This test simulates discarding a record that has been created with // one of its required field that is empty. When we discard the changes // on this empty field, it should not assume that this record should be // abandonned, since it has been added (even though it is a new record). assert.expect(8); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1249,7 +1238,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ p: [[0, 0, { display_name: 'new record', trululu: false }]] }); + return Promise.resolve({ p: [[0, 0, { display_name: 'new record', trululu: false }]] }); } return this._super.apply(this, arguments); }, @@ -1284,12 +1273,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('list in form: name_get with unique ids (default_get)', function (assert) { + QUnit.test('list in form: name_get with unique ids (default_get)', async function (assert) { assert.expect(2); this.data.partner.records[0].display_name = "MyTrululu"; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1304,7 +1293,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ + return Promise.resolve({ p: [ [0, 0, { trululu: 1 }], [0, 0, { trululu: 1 }] @@ -1325,10 +1314,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('list in form: show name of many2one fields in multi-page (default_get)', function (assert) { + QUnit.test('list in form: show name of many2one fields in multi-page (default_get)', async function (assert) { assert.expect(4); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1344,7 +1333,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ + return Promise.resolve({ p: [ [0, 0, { display_name: 'record1', trululu: 1 }], [0, 0, { display_name: 'record2', trululu: 2 }] @@ -1360,7 +1349,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('td.o_data_cell').first().next().text(), "first record", "should show display_name of trululu of 1st record"); - testUtils.dom.click(form.$('button.o_pager_next')); + await testUtils.dom.click(form.$('button.o_pager_next')); assert.strictEqual(form.$('td.o_data_cell').first().text(), "record2", "should show display_name of 2nd record"); @@ -1370,7 +1359,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('list in form: item not dropped on discard with empty required field (onchange in default_get)', function (assert) { + QUnit.test('list in form: item not dropped on discard with empty required field (onchange in default_get)', async function (assert) { // variant of the test "list in form: discard newly added element with // empty required field (default_get)", in which the `default_get` // performs an `onchange` at the same time. This `onchange` may create @@ -1389,7 +1378,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1404,7 +1393,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ + return Promise.resolve({ product_id: 37, }); } @@ -1440,7 +1429,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('list in form: item not dropped on discard with empty required field (onchange on list after default_get)', function (assert) { + QUnit.test('list in form: item not dropped on discard with empty required field (onchange on list after default_get)', async function (assert) { // discarding a record from an `onchange` in a `default_get` should not // abandon the record. This should not be the case for following // `onchange`, except if an onchange make some changes on the list: @@ -1459,7 +1448,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1479,8 +1468,8 @@ QUnit.module('fields', {}, function () { "should have no row in the editable list"); // select product_id to force on_change in editable list - testUtils.dom.click(form.$('.o_field_widget[name="product_id"] .o_input')); - testUtils.dom.click($('.ui-menu-item').first()); + await testUtils.dom.click(form.$('.o_field_widget[name="product_id"] .o_input')); + await testUtils.dom.click($('.ui-menu-item').first()); // check that there is a record in the editable list with empty string as required field assert.containsOnce(form, '.o_data_row', @@ -1494,9 +1483,9 @@ QUnit.module('fields', {}, function () { "should have empty string in the required field on this record"); // click on empty required field in editable list record - testUtils.dom.click(requiredField); + await testUtils.dom.click(requiredField); // click off so that the required field still stay empty - testUtils.dom.click($('body')); + await testUtils.dom.click($('body')); // record should not be dropped assert.containsOnce(form, '.o_data_row', @@ -1510,13 +1499,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('item dropped on discard with empty required field with "Add an item" (invalid on "ADD")', function (assert) { + QUnit.test('item dropped on discard with empty required field with "Add an item" (invalid on "ADD")', async function (assert) { // when a record in a list is added with "Add an item", it should // always be dropped on discard if some required field are empty // at the record creation. assert.expect(6); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1531,7 +1520,7 @@ QUnit.module('fields', {}, function () { }); // Click on "Add an item" - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); var charField = form.$('.o_field_widget.o_field_char[name="display_name"]'); var requiredField = form.$('.o_field_widget.o_required_modifier[name="trululu"]'); charField.val("some text"); @@ -1547,9 +1536,9 @@ QUnit.module('fields', {}, function () { "should have empty string in the required field on this record"); // click on empty required field in editable list record - testUtils.dom.click(requiredField); + await testUtils.dom.click(requiredField); // click off so that the required field still stay empty - testUtils.dom.click($('body')); + await testUtils.dom.click($('body')); // record should be dropped assert.containsNone(form, '.o_data_row', @@ -1558,7 +1547,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('item not dropped on discard with empty required field with "Add an item" (invalid on "UPDATE")', function (assert) { + QUnit.test('item not dropped on discard with empty required field with "Add an item" (invalid on "UPDATE")', async function (assert) { // when a record in a list is added with "Add an item", it should // be temporarily added to the list when it is valid (e.g. required // fields are non-empty). If the record is updated so that the required @@ -1569,7 +1558,7 @@ QUnit.module('fields', {}, function () { var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1587,7 +1576,7 @@ QUnit.module('fields', {}, function () { "should initially not have any record in the list"); // Click on "Add an item" - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsOnce(form, '.o_data_row', "should have a temporary record in the list"); @@ -1598,9 +1587,9 @@ QUnit.module('fields', {}, function () { "should have empty string in the required field on this record"); // add something to required field and leave edit mode of the record - testUtils.dom.click($inputEditMode); - testUtils.dom.click($('li.ui-menu-item').first()); - testUtils.dom.click($('body')); + await testUtils.dom.click($inputEditMode); + await testUtils.dom.click($('li.ui-menu-item').first()); + await testUtils.dom.click($('body')); var $inputReadonlyMode = form.$('.o_data_cell.o_required_modifier'); assert.containsOnce(form, '.o_data_row', @@ -1609,7 +1598,7 @@ QUnit.module('fields', {}, function () { "should have put some content in the required field on this record"); // remove the required field and leave edit mode of the record - testUtils.dom.click($('.o_data_row')); + await testUtils.dom.click($('.o_data_row')); assert.containsOnce(form, '.o_data_row', "should not have dropped record in the list on discard (invalid on UPDATE)"); assert.strictEqual($inputReadonlyMode.text(), "first record", @@ -1619,7 +1608,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('list in form: default_get with x2many create', function (assert) { + QUnit.test('list in form: default_get with x2many create', async function (assert) { assert.expect(5); var displayName = 'brandon is the new timmy'; @@ -1634,7 +1623,7 @@ QUnit.module('fields', {}, function () { obj.int_field = obj.timmy.length; }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1650,7 +1639,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ timmy: [[0, 0, { display_name: 'brandon is the new timmy', name: 'brandon' }]] }); + return Promise.resolve({ timmy: [[0, 0, { display_name: 'brandon is the new timmy', name: 'brandon' }]] }); } if (args.method === 'create') { assert.deepEqual(args.args[0], { @@ -1672,14 +1661,14 @@ QUnit.module('fields', {}, function () { // edit the subrecord and save displayName = 'new value'; - testUtils.dom.click(form.$('.o_data_cell')); - testUtils.fields.editInput(form.$('.o_data_cell input'), displayName); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_data_cell')); + await testUtils.fields.editInput(form.$('.o_data_cell input'), displayName); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('list in form: default_get with x2many create and onchange', function (assert) { + QUnit.test('list in form: default_get with x2many create and onchange', async function (assert) { assert.expect(2); this.data.partner.onchanges.turtles = function (obj) { @@ -1694,7 +1683,7 @@ QUnit.module('fields', {}, function () { "should have properly created the x2many command list"); }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1710,7 +1699,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'default_get') { - return $.when({ turtles: [[6, 0, [2, 3]]] }); + return Promise.resolve({ turtles: [[6, 0, [2, 3]]] }); } if (args.method === 'create') { // it would be even better if we did not send the current @@ -1727,16 +1716,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('list in form: call button in sub view', function (assert) { + QUnit.test('list in form: call button in sub view', async function (assert) { assert.expect(6); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1752,7 +1741,7 @@ QUnit.module('fields', {}, function () { res_id: 1, mockRPC: function (route, args) { if (route === '/web/dataset/call_kw/product/get_formview_id') { - return $.when(false); + return Promise.resolve(false); } return this._super.apply(this, arguments); }, @@ -1777,16 +1766,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('td.o_data_cell:first')); - testUtils.dom.click(form.$('.o_external_button')); - testUtils.dom.click($('button:contains("Just do it !")')); - testUtils.dom.click($('button:contains("Just don\'t do it !")')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('td.o_data_cell:first')); + await testUtils.dom.click(form.$('.o_external_button')); + await testUtils.dom.click($('button:contains("Just do it !")')); + await testUtils.dom.click($('button:contains("Just don\'t do it !")')); form.destroy(); }); - QUnit.test('X2Many sequence list in modal', function (assert) { + QUnit.test('X2Many sequence list in modal', async function (assert) { assert.expect(5); this.data.partner.fields.sequence = { string: 'Sequence', type: 'integer' }; @@ -1810,7 +1799,7 @@ QUnit.module('fields', {}, function () { this.data.partner_type.fields.partner_ids = { string: "Partner", type: "one2many", relation: 'partner' }; this.data.partner_type.records[0].partner_ids = [1, 2]; - testUtils.createAsyncView({ + var form = await createView({ View: FormView, model: 'product', data: this.data, @@ -1832,52 +1821,52 @@ QUnit.module('fields', {}, function () { res_id: 37, mockRPC: function (route, args) { if (route === '/web/dataset/call_kw/product/read') { - return $.when([{ id: 37, name: 'xphone', display_name: 'leonardo', turtle_ids: [1] }]); + return Promise.resolve([{ id: 37, name: 'xphone', display_name: 'leonardo', turtle_ids: [1] }]); } if (route === '/web/dataset/call_kw/turtle/read') { - return $.when([{ id: 1, type_id: [12, 'gold'] }]); + return Promise.resolve([{ id: 1, type_id: [12, 'gold'] }]); } if (route === '/web/dataset/call_kw/partner_type/get_formview_id') { - return $.when(false); + return Promise.resolve(false); } if (route === '/web/dataset/call_kw/partner_type/read') { - return $.when([{ id: 12, partner_ids: [1, 2], display_name: 'gold' }]); + return Promise.resolve([{ id: 12, partner_ids: [1, 2], display_name: 'gold' }]); } if (route === '/web/dataset/call_kw/partner_type/write') { assert.step('partner_type write'); } return this._super.apply(this, arguments); }, - }).then(function (form) { - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_data_cell')); - testUtils.dom.click(form.$('.o_external_button')); + }); - var $modal = $('.modal'); - assert.equal($modal.length, 1, - 'There should be 1 modal opened'); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_data_cell')); + await testUtils.dom.click(form.$('.o_external_button')); - var $handles = $modal.find('.ui-sortable-handle'); - assert.equal($handles.length, 2, - 'There should be 2 sequence handlers'); + var $modal = $('.modal'); + assert.equal($modal.length, 1, + 'There should be 1 modal opened'); - testUtils.dom.dragAndDrop($handles.eq(1), $modal.find('tbody tr').first(), - { position: 'top' }); + var $handles = $modal.find('.ui-sortable-handle'); + assert.equal($handles.length, 2, + 'There should be 2 sequence handlers'); - // Saving the modal and then the original model - testUtils.dom.click($modal.find('.modal-footer .btn-primary')); - testUtils.form.clickSave(form); + await testUtils.dom.dragAndDrop($handles.eq(1), + $modal.find('tbody tr').first(), { position: 'top' }); - assert.verifySteps(['onchange sequence', 'partner_type write']); + // Saving the modal and then the original model + await testUtils.dom.click($modal.find('.modal-footer .btn-primary')); + await testUtils.form.clickSave(form); - form.destroy(); - }); + assert.verifySteps(['onchange sequence', 'partner_type write']); + + form.destroy(); }); - QUnit.test('autocompletion in a many2one, in form view with a domain', function (assert) { + QUnit.test('autocompletion in a many2one, in form view with a domain', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1895,16 +1884,16 @@ QUnit.module('fields', {}, function () { return this._super(route, args); } }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); testUtils.dom.click(form.$('.o_field_widget[name=product_id] input')); form.destroy(); }); - QUnit.test('autocompletion in a many2one, in form view with a date field', function (assert) { + QUnit.test('autocompletion in a many2one, in form view with a date field', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1921,13 +1910,13 @@ QUnit.module('fields', {}, function () { return this._super(route, args); }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); form.destroy(); }); - QUnit.test('creating record with many2one with option always_reload', function (assert) { + QUnit.test('creating record with many2one with option always_reload', async function (assert) { assert.expect(2); this.data.partner.fields.trululu.default = 1; @@ -1939,7 +1928,7 @@ QUnit.module('fields', {}, function () { var count = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1949,7 +1938,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { count++; if (args.method === 'name_get' && args.args[0][0] === 2) { - return $.when([[2, "hello world\nso much noise"]]); + return Promise.resolve([[2, "hello world\nso much noise"]]); } return this._super(route, args); }, @@ -1961,10 +1950,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('selecting a many2one, then discarding', function (assert) { + QUnit.test('selecting a many2one, then discarding', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1974,23 +1963,23 @@ QUnit.module('fields', {}, function () { res_id: 1, }); assert.strictEqual(form.$('a[name=product_id]').text(), '', 'the tag a should be empty'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickItem('product_id','xphone'); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickItem('product_id','xphone'); assert.strictEqual(form.$('.o_field_widget[name=product_id] input').val(), "xphone", "should have selected xphone"); - testUtils.form.clickDiscard(form); + await testUtils.form.clickDiscard(form); assert.strictEqual(form.$('a[name=product_id]').text(), '', 'the tag a should be empty'); form.destroy(); }); - QUnit.test('domain and context are correctly used when doing a name_search in a m2o', function (assert) { + QUnit.test('domain and context are correctly used when doing a name_search in a m2o', async function (assert) { assert.expect(4); this.data.partner.records[0].timmy = [12]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2016,20 +2005,20 @@ QUnit.module('fields', {}, function () { { hey: "ho", hello: "world", test: "yop" }, 'the field attr context should have been used for the ' + 'RPC (evaluated and merged with the session one)'); - return $.when([]); + return Promise.resolve([]); } if (args.method === 'name_search' && args.model === 'partner') { assert.deepEqual(args.kwargs.args, [['id', 'in', [12]]], 'the field attr domain should have been used for the RPC (and evaluated)'); assert.deepEqual(args.kwargs.context, { hey: 'ho', timmy: [[6, false, [12]]] }, 'the field attr context should have been used for the RPC (and evaluated)'); - return $.when([]); + return Promise.resolve([]); } return this._super.apply(this, arguments); }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); testUtils.dom.click(form.$('.o_field_widget[name=product_id] input')); testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); @@ -2037,10 +2026,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('quick create on a many2one', function (assert) { + QUnit.test('quick create on a many2one', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2059,17 +2048,17 @@ QUnit.module('fields', {}, function () { }); form.$('.o_field_many2one input').focus(); - form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout'); - - testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), + 'new partner', ['keyup', 'focusout']); + await testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); form.destroy(); }); - QUnit.test('slow create on a many2one', function (assert) { - assert.expect(7); + QUnit.test('slow create on a many2one', async function (assert) { + assert.expect(11); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2089,41 +2078,55 @@ QUnit.module('fields', {}, function () { // cancel the many2one creation with Cancel button form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); + await testUtils.nextTick(); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); + + await testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); + assert.strictEqual($('.modal').length, 0, "the modal should be closed"); assert.strictEqual(form.$('.o_field_many2one input').val(), "", 'the many2one should not set a value as its creation has been cancelled (with Cancel button)'); // cancel the many2one creation with Close button - form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); - testUtils.dom.click($('.modal .modal-header button')); + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), + 'new product', ['keyup', 'blur']); + assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); + await testUtils.dom.click($('.modal .modal-header button')); assert.strictEqual(form.$('.o_field_many2one input').val(), "", 'the many2one should not set a value as its creation has been cancelled (with Close button)'); + assert.strictEqual($('.modal').length, 0, "the modal should be closed"); // select a new value then cancel the creation of the new one --> restore the previous - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickItem('product_id','o'); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickItem('product_id','o'); assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone", "should have selected xphone"); + form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); + await testUtils.nextTick(); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); + + await testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone", 'should have restored the many2one with its previous selected value (xphone)'); // confirm the many2one creation - form.$('.o_field_many2one input').focus(); - form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('blur'); - testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); + form.$('.o_field_many2one input').focus().val('new partner').trigger('keyup').trigger('blur'); + await testUtils.nextTick(); + assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); + + await testUtils.dom.click($('.modal .modal-footer .btn-primary:contains(Create and edit)')); + await testUtils.nextTick(); assert.strictEqual($('.modal .o_form_view').length, 1, 'a new modal should be opened and contain a form view'); + await testUtils.dom.click($('.modal .o_form_button_cancel')); + form.destroy(); }); - QUnit.test('no_create option on a many2one', function (assert) { + QUnit.test('no_create option on a many2one', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2134,14 +2137,14 @@ QUnit.module('fields', {}, function () { '</form>', }); - form.$('.o_field_many2one input').focus(); - form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout'); - + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), + 'new partner', ['keyup', 'focusout']); + await testUtils.nextTick(); assert.strictEqual($('.modal').length, 0, "should not display the create modal"); form.destroy(); }); - QUnit.test('can_create and can_write option on a many2one', function (assert) { + QUnit.test('can_create and can_write option on a many2one', async function (assert) { assert.expect(5); this.data.product.options = { @@ -2149,7 +2152,7 @@ QUnit.module('fields', {}, function () { can_write: "false", }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2163,117 +2166,98 @@ QUnit.module('fields', {}, function () { }, mockRPC: function (route) { if (route === '/web/dataset/call_kw/product/get_formview_id') { - return $.when(false); + return Promise.resolve(false); } return this._super.apply(this, arguments); }, }); - testUtils.dom.click(form.$('.o_field_many2one input')); + await testUtils.dom.click(form.$('.o_field_many2one input')); assert.strictEqual($('.ui-autocomplete .o_m2o_dropdown_option:contains(Create)').length, 0, "there shouldn't be any option to search and create"); - testUtils.dom.click($('.ui-autocomplete li:contains(xpad)').mouseenter()); + await testUtils.dom.click($('.ui-autocomplete li:contains(xpad)').mouseenter()); assert.strictEqual(form.$('.o_field_many2one input').val(), "xpad", "the correct record should be selected"); assert.containsOnce(form, '.o_field_many2one .o_external_button', "there should be an external button displayed"); - testUtils.dom.click(form.$('.o_field_many2one .o_external_button')); + await testUtils.dom.click(form.$('.o_field_many2one .o_external_button')); assert.strictEqual($('.modal .o_form_view.o_form_readonly').length, 1, "there should be a readonly form view opened"); - testUtils.dom.click($('.modal .o_form_button_cancel')); - - form.$('.o_field_many2one input').val('new product').trigger('keyup').trigger('focusout'); + await testUtils.dom.click($('.modal .o_form_button_cancel')); + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), + 'new product', ['keyup', 'focusout']); assert.strictEqual($('.modal').length, 0, "should not display the create modal"); form.destroy(); }); - QUnit.test('pressing enter in a m2o in an editable list', function (assert) { + QUnit.test('pressing enter in a m2o in an editable list', async function (assert) { assert.expect(9); - var done = assert.async(); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var list = createView({ + var list = await createView({ View: ListView, model: 'partner', data: this.data, arch: '<tree editable="bottom"><field name="product_id"/></tree>', }); - testUtils.dom.click(list.$('td.o_data_cell:first')); + await testUtils.dom.click(list.$('td.o_data_cell:first')); assert.containsOnce(list, '.o_selected_row', "should have a row in edit mode"); // we now write 'a' and press enter to check that the selection is // working, and prevent the navigation - testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); - concurrency.delay(0).then(function () { - var $input = list.$('td.o_data_cell input:first'); - var $dropdown = $input.autocomplete('widget'); - assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible"); - - // we now trigger ENTER to select first choice - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - assert.strictEqual($input[0], document.activeElement, - "input should still be focused"); - - // we now trigger again ENTER to make sure we can move to next line - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - - assert.notOk(document.contains($input[0]), - "input should no longer be in dom"); - assert.hasClass(list.$('tr.o_data_row:eq(1)'),'o_selected_row', - "second row should now be selected"); - - // we now write again 'a' in the cell to select xpad. We will now - // test with the tab key - testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); - return concurrency.delay(0); - }).then(function () { - var $input = list.$('td.o_data_cell input:first'); - var $dropdown = $input.autocomplete('widget'); - assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible"); - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.TAB, - keyCode: $.ui.keyCode.TAB, - })); - assert.strictEqual($input[0], document.activeElement, - "input should still be focused"); - - // we now trigger again ENTER to make sure we can move to next line - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.TAB, - keyCode: $.ui.keyCode.TAB, - })); - - assert.notOk(document.contains($input[0]), - "input should no longer be in dom"); - assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row', - "third row should now be selected"); - list.destroy(); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - done(); - }); + await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); + var $input = list.$('td.o_data_cell input:first'); + var $dropdown = $input.autocomplete('widget'); + assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible"); + + // we now trigger ENTER to select first choice + await testUtils.fields.triggerKeydown($input, 'enter'); + assert.strictEqual($input[0], document.activeElement, + "input should still be focused"); + + // we now trigger again ENTER to make sure we can move to next line + await testUtils.fields.triggerKeydown($input, 'enter'); + + assert.notOk(document.contains($input[0]), + "input should no longer be in dom"); + assert.hasClass(list.$('tr.o_data_row:eq(1)'),'o_selected_row', + "second row should now be selected"); + + // we now write again 'a' in the cell to select xpad. We will now + // test with the tab key + await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); + var $input = list.$('td.o_data_cell input:first'); + var $dropdown = $input.autocomplete('widget'); + assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible"); + await testUtils.fields.triggerKeydown($input, 'tab'); + assert.strictEqual($input[0], document.activeElement, + "input should still be focused"); + + // we now trigger again ENTER to make sure we can move to next line + await testUtils.fields.triggerKeydown($input, 'tab'); + + assert.notOk(document.contains($input[0]), + "input should no longer be in dom"); + assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row', + "third row should now be selected"); + list.destroy(); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; }); - QUnit.test('pressing ENTER on a \'no_quick_create\' many2one should open a M2ODialog', function (assert) { - var done = assert.async(); + QUnit.test('pressing ENTER on a \'no_quick_create\' many2one should open a M2ODialog', async function (assert) { assert.expect(2); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2287,47 +2271,33 @@ QUnit.module('fields', {}, function () { }); var $input = form.$('.o_field_many2one input'); - testUtils.fields.editInput($input, "Something that does not exist"); + await testUtils.fields.editInput($input, "Something that does not exist"); $('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter'); - concurrency.delay(0).then(function () { - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - $input.trigger($.Event('keypress', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - $input.trigger($.Event('keyup', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - concurrency.delay(0).then(function () { - $input.blur(); - assert.strictEqual($('.modal').length, 1, - "should have one modal in body"); - // Check that discarding clears $input - testUtils.dom.click($('.modal .o_form_button_cancel')); - assert.strictEqual($input.val(), '', - "the field should be empty"); - form.destroy(); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - done(); - }); - }); + await testUtils.nextTick(); + await testUtils.fields.triggerKey('down', $input, 'enter') + await testUtils.fields.triggerKey('press', $input, 'enter') + await testUtils.fields.triggerKey('up', $input, 'enter') + $input.blur(); + assert.strictEqual($('.modal').length, 1, + "should have one modal in body"); + // Check that discarding clears $input + await testUtils.dom.click($('.modal .o_form_button_cancel')); + assert.strictEqual($input.val(), '', + "the field should be empty"); + form.destroy(); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; }); - QUnit.test('select a value by pressing TAB on a many2one with onchange', function (assert) { - var done = assert.async(); + QUnit.test('select a value by pressing TAB on a many2one with onchange', async function (assert) { assert.expect(3); this.data.partner.onchanges.trululu = function () { }; var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2338,7 +2308,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { var result = this._super.apply(this, arguments); if (args.method === 'onchange') { - return $.when(def).then(_.constant(result)); + return prom.then(_.constant(result)); } return result; }, @@ -2349,39 +2319,32 @@ QUnit.module('fields', {}, function () { }); var $input = form.$('.o_field_many2one input'); - testUtils.fields.editInput($input, "first"); - concurrency.delay(0).then(function () { - var evOptions = { - which: $.ui.keyCode.TAB, - keyCode: $.ui.keyCode.TAB, - }; - $input.trigger($.Event('keydown', evOptions)); - $input.trigger($.Event('keypress', evOptions)); - $input.trigger($.Event('keyup', evOptions)); - - // simulate a focusout (e.g. because the user clicks outside) - // before the onchange returns - form.$('.o_field_char').focus(); - - assert.strictEqual($('.modal').length, 0, - "there shouldn't be any modal in body"); - - // unlock the onchange - def.resolve(); - - assert.strictEqual($input.val(), 'first record', - "first record should have been selected"); - assert.strictEqual($('.modal').length, 0, - "there shouldn't be any modal in body"); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + await testUtils.fields.editInput($input, "first"); + await testUtils.fields.triggerKey('down', $input, 'tab'); + await testUtils.fields.triggerKey('press', $input, 'tab'); + await testUtils.fields.triggerKey('up', $input, 'tab'); + + // simulate a focusout (e.g. because the user clicks outside) + // before the onchange returns + form.$('.o_field_char').focus(); + + assert.strictEqual($('.modal').length, 0, + "there shouldn't be any modal in body"); + + // unlock the onchange + prom.resolve(); + await testUtils.nextTick(); + + assert.strictEqual($input.val(), 'first record', + "first record should have been selected"); + assert.strictEqual($('.modal').length, 0, + "there shouldn't be any modal in body"); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; + form.destroy(); }); - QUnit.test('many2one in editable list + onchange, with enter [REQUIRE FOCUS]', function (assert) { + QUnit.test('many2one in editable list + onchange, with enter [REQUIRE FOCUS]', async function (assert) { assert.expect(6); - var done = assert.async(); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; @@ -2389,9 +2352,9 @@ QUnit.module('fields', {}, function () { obj.int_field = obj.product_id || 0; }; - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); - var list = createView({ + var list = await createView({ View: ListView, model: 'partner', data: this.data, @@ -2402,42 +2365,30 @@ QUnit.module('fields', {}, function () { } var result = this._super.apply(this, arguments); if (args.method === 'onchange') { - return def.then(_.constant(result)); + return prom.then(_.constant(result)); } return result; }, }); - testUtils.dom.click(list.$('td.o_data_cell:first')); - testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); - concurrency.delay(0).then(function () { - var $input = list.$('td.o_data_cell input:first'); - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - $input.trigger($.Event('keyup', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - def.resolve(); - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM"); - assert.verifySteps(['name_search', 'onchange', 'write', 'read']); - list.destroy(); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - done(); - }); + await testUtils.dom.click(list.$('td.o_data_cell:first')); + await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); + var $input = list.$('td.o_data_cell input:first'); + await testUtils.fields.triggerKeydown($input, 'enter'); + await testUtils.fields.triggerKey('up', $input, 'enter'); + prom.resolve(); + await testUtils.nextTick(); + await testUtils.fields.triggerKeydown($input, 'enter'); + assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM"); + assert.verifySteps(['name_search', 'onchange', 'write', 'read']); + list.destroy(); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; }); - QUnit.test('many2one in editable list + onchange, with enter, part 2 [REQUIRE FOCUS]', function (assert) { + QUnit.test('many2one in editable list + onchange, with enter, part 2 [REQUIRE FOCUS]', async function (assert) { // this is the same test as the previous one, but the onchange is just // resolved slightly later assert.expect(6); - var done = assert.async(); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; @@ -2445,9 +2396,9 @@ QUnit.module('fields', {}, function () { obj.int_field = obj.product_id || 0; }; - var def = $.Deferred(); + var prom = testUtils.makeTestPromise(); - var list = createView({ + var list = await createView({ View: ListView, model: 'partner', data: this.data, @@ -2458,38 +2409,27 @@ QUnit.module('fields', {}, function () { } var result = this._super.apply(this, arguments); if (args.method === 'onchange') { - return def.then(_.constant(result)); + return prom.then(_.constant(result)); } return result; }, }); - testUtils.dom.click(list.$('td.o_data_cell:first')); - testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); - concurrency.delay(0).then(function () { - var $input = list.$('td.o_data_cell input:first'); - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - $input.trigger($.Event('keyup', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - $input.trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - def.resolve(); - assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM"); - assert.verifySteps(['name_search', 'onchange', 'write', 'read']); - list.destroy(); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - done(); - }); + await testUtils.dom.click(list.$('td.o_data_cell:first')); + await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a'); + var $input = list.$('td.o_data_cell input:first'); + await testUtils.fields.triggerKeydown($input, 'enter'); + await testUtils.fields.triggerKey('up', $input, 'enter'); + await testUtils.fields.triggerKeydown($input, 'enter'); + prom.resolve(); + await testUtils.nextTick(); + assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM"); + assert.verifySteps(['name_search', 'onchange', 'write', 'read']); + list.destroy(); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; }); - QUnit.test('many2one: domain updated by an onchange', function (assert) { + QUnit.test('many2one: domain updated by an onchange', async function (assert) { assert.expect(2); this.data.partner.onchanges = { @@ -2497,7 +2437,7 @@ QUnit.module('fields', {}, function () { }; var domain = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2509,7 +2449,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { if (args.method === 'onchange') { domain = [['id', 'in', [10]]]; - return $.when({ + return Promise.resolve({ domain: { trululu: domain, unexisting_field: domain, @@ -2528,18 +2468,18 @@ QUnit.module('fields', {}, function () { }); // trigger a name_search (domain should be []) - testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); + await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); // close the dropdown - testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); + await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); // trigger an onchange that will update the domain - testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); + await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); // trigger a name_search (domain should be [['id', 'in', [10]]]) - testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); + await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); form.destroy(); }); - QUnit.test('many2one in one2many: domain updated by an onchange', function (assert) { + QUnit.test('many2one in one2many: domain updated by an onchange', async function (assert) { assert.expect(3); this.data.partner.onchanges = { @@ -2547,7 +2487,7 @@ QUnit.module('fields', {}, function () { }; var domain = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2561,7 +2501,7 @@ QUnit.module('fields', {}, function () { res_id: 1, mockRPC: function (route, args) { if (args.method === 'onchange') { - return $.when({ + return Promise.resolve({ domain: { trululu: domain, }, @@ -2580,18 +2520,18 @@ QUnit.module('fields', {}, function () { // add a first row with a specific domain for the m2o domain = [['id', 'in', [10]]]; // domain for subrecord 1 - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); // add a second row with another domain for the m2o domain = [['id', 'in', [5]]]; // domain for subrecord 2 - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); // check again the first row to ensure that the domain hasn't change domain = [['id', 'in', [10]]]; // domain for subrecord 1 should have been kept - testUtils.dom.click(form.$('.o_data_row:first .o_data_cell')); - testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); + await testUtils.dom.click(form.$('.o_data_row:first .o_data_cell')); + await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); form.destroy(); }); @@ -2606,7 +2546,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records.push({id: 100 + i, display_name: 'test_' + i}); } - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2652,7 +2592,7 @@ QUnit.module('fields', {}, function () { } var expectedDomain; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2682,7 +2622,7 @@ QUnit.module('fields', {}, function () { // remove the filter on ids expectedDomain = []; - testUtils.dom.click($('.modal .o_cp_searchview .o_facet_remove')); + await testUtils.dom.click($('.modal .o_cp_searchview .o_facet_remove')); assert.verifySteps([ 'default_get', @@ -2697,12 +2637,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('updating a many2one from a many2many', function (assert) { + QUnit.test('updating a many2one from a many2many', async function (assert) { assert.expect(4); this.data.turtle.records[1].turtle_trululu = 1; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2723,22 +2663,22 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { if (args.method === 'get_formview_id') { assert.deepEqual(args.args[0], [1], "should call get_formview_id with correct id"); - return $.when(false); + return Promise.resolve(false); } return this._super(route, args); }, }); // Opening the modal - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_data_row td:contains(first record)')); - testUtils.dom.click(form.$('.o_external_button')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_data_row td:contains(first record)')); + await testUtils.dom.click(form.$('.o_external_button')); assert.strictEqual($('.modal').length, 1, "should have one modal in body"); // Changing the 'trululu' value - testUtils.fields.editInput($('.modal input[name="display_name"]'), 'test'); - testUtils.dom.click($('.modal button.btn-primary')); + await testUtils.fields.editInput($('.modal input[name="display_name"]'), 'test'); + await testUtils.dom.click($('.modal button.btn-primary')); // Test whether the value has changed assert.strictEqual($('.modal').length, 0, @@ -2749,13 +2689,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('x2many list sorted by many2one', function (assert) { + QUnit.test('x2many list sorted by many2one', async function (assert) { assert.expect(3); this.data.partner.records[0].p = [1, 2, 4]; this.data.partner.fields.trululu.sortable = true; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2773,12 +2713,12 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '124', "should have correct order initially"); - testUtils.dom.click(form.$('.o_list_view thead th:nth(1)')); + await testUtils.dom.click(form.$('.o_list_view thead th:nth(1)')); assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '412', "should have correct order (ASC)"); - testUtils.dom.click(form.$('.o_list_view thead th:nth(1)')); + await testUtils.dom.click(form.$('.o_list_view thead th:nth(1)')); assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '214', "should have correct order (DESC)"); @@ -2786,10 +2726,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with extra field from server not in form', function (assert) { + QUnit.test('one2many with extra field from server not in form', async function (assert) { assert.expect(6); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2814,20 +2754,20 @@ QUnit.module('fields', {}, function () { } }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a record in the list - testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); var modal = $('.modal-lg'); var nameInput = modal.find('input.o_input[name=display_name]'); - testUtils.fields.editInput(nameInput, 'michelangelo'); + await testUtils.fields.editInput(nameInput, 'michelangelo'); // Save the record in the modal (though it is still virtual) - testUtils.dom.click(modal.find('.btn-primary').first()); + await testUtils.dom.click(modal.find('.btn-primary').first()); assert.equal(x2mList.find('.o_data_row').length, 1, 'There should be 1 records in the x2m list'); @@ -2840,7 +2780,7 @@ QUnit.module('fields', {}, function () { 'The display name field should have the right value'); // Save the whole thing - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); x2mList = form.$('.o_field_x2many_list[name=p]'); @@ -2858,10 +2798,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with extra field from server not in (inline) form', function (assert) { + QUnit.test('one2many with extra field from server not in (inline) form', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2885,15 +2825,15 @@ QUnit.module('fields', {}, function () { var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a record in the list - testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); var modal = $('.modal-lg'); var nameInput = modal.find('input.o_input[name=display_name]'); - testUtils.fields.editInput(nameInput, 'michelangelo'); + await testUtils.fields.editInput(nameInput, 'michelangelo'); // Save the record in the modal (though it is still virtual) - testUtils.dom.click(modal.find('.btn-primary').first()); + await testUtils.dom.click(modal.find('.btn-primary').first()); assert.equal(x2mList.find('.o_data_row').length, 1, 'There should be 1 records in the x2m list'); @@ -2901,10 +2841,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with extra X2many field from server not in inline form', function (assert) { + QUnit.test('one2many with extra X2many field from server not in inline form', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2928,13 +2868,13 @@ QUnit.module('fields', {}, function () { var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a first record in the list - testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); // Save & New - testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(1)); + await testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(1)); // Save & Close - testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(0)); + await testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(0)); assert.equal(x2mList.find('.o_data_row').length, 2, 'There should be 2 records in the x2m list'); @@ -2942,11 +2882,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many invisible depends on parent field', function (assert) { + QUnit.test('one2many invisible depends on parent field', async function (assert) { assert.expect(4); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2972,21 +2912,22 @@ QUnit.module('fields', {}, function () { }); assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input')); - testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter')); + 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')); assert.containsOnce(form, 'th', "should be 1 column when the product_id is set"); - form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup'); + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'), + '', 'keyup'); assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); + await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); assert.containsOnce(form, 'th', "should be 1 column after the value change"); form.destroy(); }); - QUnit.test('one2many column visiblity depends on onchange of parent field', function (assert) { + QUnit.test('one2many column visiblity depends on onchange of parent field', async function (assert) { assert.expect(3); this.data.partner.records[0].p = [2]; @@ -2999,7 +2940,7 @@ QUnit.module('fields', {}, function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3020,24 +2961,24 @@ QUnit.module('fields', {}, function () { "should be only 1 column ('foo') in the one2many"); assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // add a new o2m record - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.$('.o_field_one2many input:first').focus(); - testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line'); - testUtils.dom.click(form.$el); + await testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line'); + await testUtils.dom.click(form.$el); assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')"); form.destroy(); }); - QUnit.test('one2many column_invisible on view not inline', function (assert) { + QUnit.test('one2many column_invisible on view not inline', async function (assert) { assert.expect(4); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3064,15 +3005,16 @@ QUnit.module('fields', {}, function () { }); assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input')); - testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter')); + 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')); assert.containsOnce(form, 'th', "should be 1 column when the product_id is set"); - form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup'); + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'), + '', 'keyup'); assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); + await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); assert.containsOnce(form, 'th', "should be 1 column after the value change"); form.destroy(); |
