diff options
Diffstat (limited to 'addons/web/static/tests/fields/relational_fields')
3 files changed, 1632 insertions, 1702 deletions
diff --git a/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js index 949af90fafe..e20ad604c98 100644 --- a/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js +++ b/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js @@ -111,11 +111,11 @@ QUnit.module('fields', {}, function () { }] }, }; - } + }, }, function () { QUnit.module('FieldMany2Many'); - QUnit.test('many2many kanban: edition', function (assert) { + QUnit.test('many2many kanban: edition', async function (assert) { assert.expect(32); this.data.partner.records[0].timmy = [12, 14]; @@ -123,7 +123,7 @@ QUnit.module('fields', {}, function () { this.data.partner_type.records.push({ id: 18, display_name: "yellow", color: 4 }); this.data.partner_type.records.push({ id: 21, display_name: "blue", color: 1 }); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -187,7 +187,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_many2many .o-kanban-button-new').length, '"Add" button should not be visible in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, 'should contain 2 records'); @@ -201,20 +201,20 @@ QUnit.module('fields', {}, function () { 'Create button should have "Add" label'); // edit existing subrecord - testUtils.dom.click(form.$('.oe_kanban_global_click:first()')); + await testUtils.dom.click(form.$('.oe_kanban_global_click:first()')); - testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_kanban_record:first() span').text(), 'new name', 'value of subrecord should have been updated'); // add subrecords // -> single select - testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); + await testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); assert.ok($('.modal .o_list_view').length, "should have opened a list view in a modal"); assert.strictEqual($('.modal .o_list_view tbody .o_list_record_selector').length, 3, "list view should contain 3 records"); - testUtils.dom.click($('.modal .o_list_view tbody tr:contains(red)')); + await testUtils.dom.click($('.modal .o_list_view tbody tr:contains(red)')); assert.ok(!$('.modal .o_list_view').length, "should have closed the modal"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 3, 'kanban should now contain 3 records'); @@ -222,23 +222,23 @@ QUnit.module('fields', {}, function () { 'record "red" should be in the kanban'); // -> multiple select - testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); + await testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); assert.ok($('.modal .o_select_button').prop('disabled'), "select button should be disabled"); assert.strictEqual($('.modal .o_list_view tbody .o_list_record_selector').length, 2, "list view should contain 2 records"); - testUtils.dom.click($('.modal .o_list_view thead .o_list_record_selector input')); - testUtils.dom.click($('.modal .o_select_button')); + await testUtils.dom.click($('.modal .o_list_view thead .o_list_record_selector input')); + await testUtils.dom.click($('.modal .o_select_button')); assert.ok(!$('.modal .o_select_button').prop('disabled'), "select button should be enabled"); assert.ok(!$('.modal .o_list_view').length, "should have closed the modal"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 5, 'kanban should now contain 5 records'); // -> created record - testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); - testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)')); + await testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)')); assert.ok($('.modal .o_form_view.o_form_editable').length, "should have opened a form view in edit mode, in a modal"); - testUtils.fields.editInput($('.modal .o_form_view input'), 'A new type'); - testUtils.dom.click($('.modal:nth(1) footer .btn-primary:first()')); + await testUtils.fields.editInput($('.modal .o_form_view input'), 'A new type'); + await testUtils.dom.click($('.modal:nth(1) footer .btn-primary:first()')); assert.ok(!$('.modal').length, "should have closed both modals"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 6, 'kanban should now contain 6 records'); @@ -246,32 +246,32 @@ QUnit.module('fields', {}, function () { 'the newly created type should be in the kanban'); // delete subrecords - testUtils.dom.click(form.$('.o_kanban_record:contains(silver)')); + await testUtils.dom.click(form.$('.o_kanban_record:contains(silver)')); assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, 'There should be a modal having Remove Button'); - testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); + await testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 5, 'should contain 5 records'); assert.ok(!form.$('.o_kanban_record:contains(silver)').length, 'the removed record should not be in kanban anymore'); - testUtils.dom.click(form.$('.o_kanban_record:contains(blue) .delete_icon')); + await testUtils.dom.click(form.$('.o_kanban_record:contains(blue) .delete_icon')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4, 'should contain 4 records'); assert.ok(!form.$('.o_kanban_record:contains(blue)').length, 'the removed record should not be in kanban anymore'); // save the record - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('many2many kanban(editable): properly handle create_text node option', function (assert) { + QUnit.test('many2many kanban(editable): properly handle create_text node option', async function (assert) { assert.expect(1); this.data.partner.records[0].timmy = [12]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -291,19 +291,19 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_many2many[name="timmy"] .o-kanban-button-new').text().trim(), "Add timmy", "In M2M Kanban, Add button should have 'Add timmy' label"); form.destroy(); }); - QUnit.test('many2many kanban: create action disabled', function (assert) { + QUnit.test('many2many kanban: create action disabled', async function (assert) { assert.expect(4); this.data.partner.records[0].timmy = [12, 14]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -335,27 +335,27 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o-kanban-button-new').length, '"Add" button should not be available in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.ok(form.$('.o-kanban-button-new').length, '"Add" button should be available in edit'); assert.ok(form.$('.o_kanban_view .delete_icon').length, 'delete icon should be visible in edit'); - testUtils.dom.click(form.$('.o-kanban-button-new')); + await testUtils.dom.click(form.$('.o-kanban-button-new')); assert.strictEqual($('.modal .modal-footer .btn-primary').length, 1, // only button 'Select' '"Create" button should not be available in the modal'); form.destroy(); }); - QUnit.test('many2many list (non editable): edition', function (assert) { + QUnit.test('many2many list (non editable): edition', async function (assert) { assert.expect(27); this.data.partner.records[0].timmy = [12, 14]; this.data.partner_type.records.push({ id: 15, display_name: "bronze", color: 6 }); this.data.partner_type.fields.float_field = { string: 'Float', type: 'float' }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -392,7 +392,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not be visible in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 records'); @@ -404,34 +404,34 @@ QUnit.module('fields', {}, function () { '"Add an item" should be visible in edit'); // edit existing subrecord - testUtils.dom.click(form.$('.o_list_view tbody tr:first()')); + await testUtils.dom.click(form.$('.o_list_view tbody tr:first()')); - testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name', 'value of subrecord should have been updated'); // add new subrecords - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_list_view').length, 1, "a modal should be open"); assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1, "the list should contain one row"); - testUtils.dom.click($('.modal .o_list_view .o_data_row')); + await testUtils.dom.click($('.modal .o_list_view .o_data_row')); assert.strictEqual($('.modal .o_list_view').length, 0, "the modal should be closed"); assert.containsN(form, '.o_list_view td.o_list_number', 3, 'should contain 3 subrecords'); // remove subrecords - testUtils.dom.click(form.$('.o_list_record_remove:nth(1)')); + await testUtils.dom.click(form.$('.o_list_record_remove:nth(1)')); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 subrecords'); assert.strictEqual(form.$('.o_list_view .o_data_row td:first').text(), 'new name', 'the updated row still has the correct values'); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 subrecords'); assert.strictEqual(form.$('.o_list_view .o_data_row td:first').text(), @@ -453,13 +453,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2many list (editable): edition', function (assert) { + QUnit.test('many2many list (editable): edition', async function (assert) { assert.expect(31); this.data.partner.records[0].timmy = [12, 14]; this.data.partner_type.records.push({ id: 15, display_name: "bronze", color: 6 }); this.data.partner_type.fields.float_field = { string: 'Float', type: 'float' }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -494,7 +494,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not be visible in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 records'); @@ -508,17 +508,17 @@ QUnit.module('fields', {}, function () { '"Add an item" should not visible in edit'); // edit existing subrecord - testUtils.dom.click(form.$('.o_list_view tbody td:first()')); + await testUtils.dom.click(form.$('.o_list_view tbody td:first()')); assert.ok(!$('.modal').length, 'in edit, clicking on a subrecord should not open a dialog'); assert.hasClass(form.$('.o_list_view tbody tr:first()'),'o_selected_row', 'first row should be in edition'); - testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name'); + await testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name'); assert.hasClass(form.$('.o_list_view .o_data_row:first'),'o_selected_row', 'first row should still be in edition'); assert.strictEqual(form.$('.o_list_view input[name=display_name]').get(0), document.activeElement, 'edited field should still have the focus'); - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$el); assert.doesNotHaveClass(form.$('.o_list_view tbody tr:first'), 'o_selected_row', 'first row should not be in edition anymore'); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name', @@ -526,34 +526,32 @@ QUnit.module('fields', {}, function () { assert.verifySteps(['read', 'read']); // add new subrecords - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_list_view').length, 1, "a modal should be open"); assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1, "the list should contain one row"); - testUtils.dom.click($('.modal .o_list_view .o_data_row')); + await testUtils.dom.click($('.modal .o_list_view .o_data_row')); assert.strictEqual($('.modal .o_list_view').length, 0, "the modal should be closed"); assert.containsN(form, '.o_list_view td.o_list_number', 3, 'should contain 3 subrecords'); // remove subrecords - testUtils.dom.click(form.$('.o_list_record_remove:nth(1)')); + await testUtils.dom.click(form.$('.o_list_record_remove:nth(1)')); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 subrecord'); assert.strictEqual(form.$('.o_list_view tbody .o_data_row td:first').text(), 'new name', 'the updated row still has the correct values'); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 subrecords'); assert.strictEqual(form.$('.o_list_view .o_data_row td:first').text(), 'new name', 'the updated row still has the correct values'); assert.verifySteps([ - 'read', // main record - 'read', // relational field 'search_read', // list view in dialog 'read', // relational field (updated) 'write', // save main record @@ -564,12 +562,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2many: create & delete attributes', function (assert) { + QUnit.test('many2many: create & delete attributes', async function (assert) { assert.expect(4); this.data.partner.records[0].timmy = [12, 14]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -583,14 +581,14 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsOnce(form, '.o_field_x2many_list_row_add', "should have the 'Add an item' link"); assert.containsN(form, '.o_list_record_remove', 2, "should have the 'Add an item' link"); form.destroy(); - form = createView({ + form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -604,7 +602,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsNone(form, '.o_field_x2many_list_row_add', "should not have the 'Add an item' link"); assert.containsNone(form, '.o_list_record_remove', "should not have the 'Add an item' link"); @@ -612,9 +610,9 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2many list: create action disabled', function (assert) { + QUnit.test('many2many list: create action disabled', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -631,7 +629,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in edit either'); @@ -639,13 +637,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2many list: list of id as default value', function (assert) { + QUnit.test('many2many list: list of id as default value', async function (assert) { assert.expect(1); this.data.partner.fields.turtles.default = [2, 3]; this.data.partner.fields.turtles.type = "many2many"; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -664,13 +662,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2many checkboxes with default values', function (assert) { + QUnit.test('many2many checkboxes with default values', async function (assert) { assert.expect(7); this.data.partner.fields.turtles.default = [3]; this.data.partner.fields.turtles.type = "many2many"; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -694,10 +692,10 @@ QUnit.module('fields', {}, function () { assert.ok(form.$('.o_form_view .custom-checkbox input').eq(2).prop('checked'), "third checkbox should be checked"); - testUtils.dom.click(form.$('.o_form_view .custom-checkbox input:checked')); - testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first()); - testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first()); - testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first()); + await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input:checked')); + await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first()); + await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first()); + await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first()); assert.ok(form.$('.o_form_view .custom-checkbox input').eq(0).prop('checked'), "first checkbox should be checked"); @@ -706,12 +704,12 @@ QUnit.module('fields', {}, function () { assert.notOk(form.$('.o_form_view .custom-checkbox input').eq(2).prop('checked'), "third checkbox should not be checked"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('many2many list with x2many: add a record', function (assert) { + QUnit.test('many2many list with x2many: add a record', async function (assert) { assert.expect(18); this.data.partner_type.fields.m2m = { @@ -720,7 +718,7 @@ QUnit.module('fields', {}, function () { this.data.partner_type.records[0].m2m = [1, 2]; this.data.partner_type.records[1].m2m = [2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -742,7 +740,7 @@ QUnit.module('fields', {}, function () { assert.step(_.last(route.split('/')) + ' on ' + args.model); } if (args.model === 'turtle') { - assert.step(args.args[0]); // the read ids + assert.step(JSON.stringify(args.args[0])); // the read ids } return this._super.apply(this, arguments); }, @@ -751,16 +749,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click($('.modal .o_data_row:first')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_data_row:first')); assert.containsOnce(form, '.o_data_row', "the record should have been added to the relation"); assert.strictEqual(form.$('.o_data_row:first .o_badge_text').text(), 'leonardodonatello', "inner m2m should have been fetched and correctly displayed"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click($('.modal .o_data_row:first')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_data_row:first')); assert.containsN(form, '.o_data_row', 2, "the second record should have been added to the relation"); @@ -771,27 +769,27 @@ QUnit.module('fields', {}, function () { 'read on partner', 'search_read on partner_type', 'read on turtle', - [1, 2, 3], + '[1,2,3]', 'read on partner_type', 'read on turtle', - [1, 2], + '[1,2]', 'search_read on partner_type', 'read on turtle', - [2, 3], + '[2,3]', 'read on partner_type', 'read on turtle', - [2, 3], + '[2,3]', ]); form.destroy(); }); - QUnit.test('many2many with a domain', function (assert) { + QUnit.test('many2many with a domain', async function (assert) { // The domain specified on the field should not be replaced by the potential // domain the user writes in the dialog, they should rather be concatenated assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -812,24 +810,24 @@ 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')); assert.strictEqual($('.modal .o_data_row').length, 1, "should contain only one row (gold)"); - $('.modal .o_searchview_input').trigger({ type: 'keypress', which: 115 }); // s - $('.modal .o_searchview_input').trigger({ type: 'keydown', which: 13 }); // enter + await testUtils.fields.triggerKey('press', $('.modal .o_searchview_input'), 's'); + await testUtils.fields.triggerKeydown($('.modal .o_searchview_input'), 'enter'); assert.strictEqual($('.modal .o_data_row').length, 0, "should contain no row"); form.destroy(); }); - QUnit.test('many2many list with onchange and edition of a record', function (assert) { + QUnit.test('many2many list with onchange and edition of a record', async function (assert) { assert.expect(8); this.data.partner.fields.turtles.type = "many2many"; this.data.partner.onchanges.turtles = function () { }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -850,14 +848,14 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('td.o_data_cell:first')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('td.o_data_cell:first')); - testUtils.dom.click($('.modal-body input[type="checkbox"]')); - testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); + await testUtils.dom.click($('.modal-body input[type="checkbox"]')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); // there is nothing left to save -> should not do a 'write' RPC - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.verifySteps([ 'read', // read initial record (on partner) @@ -872,10 +870,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange with 40+ commands for a many2many', function (assert) { + QUnit.test('onchange with 40+ commands for a many2many', async function (assert) { // this test ensures that the basic_model correctly handles more LINK_TO // commands than the limit of the dataPoint (40 for x2many kanban) - assert.expect(23); + assert.expect(24); // create a lot of partner_types that will be linked by the onchange var commands = [[5]]; @@ -890,7 +888,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -925,44 +923,45 @@ QUnit.module('fields', {}, function () { assert.verifySteps(['read']); - testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange'); - assert.verifySteps(['read', 'onchange', 'read']); + assert.verifySteps(['onchange', 'read']); assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), '1-40 / 45', "pager should be correct"); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40, 'there should be 40 records displayed on page 1'); - testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next')); - assert.verifySteps(['read', 'onchange', 'read', 'read']); + await testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next')); + assert.verifySteps(['read']); assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), '41-45 / 45', "pager should be correct"); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5, 'there should be 5 records displayed on page 2'); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), '1-40 / 45', "pager should be correct"); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40, 'there should be 40 records displayed on page 1'); - testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next')); + await testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next')); assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), '41-45 / 45', "pager should be correct"); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5, 'there should be 5 records displayed on page 2'); - testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next')); + await testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next')); assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), '1-40 / 45', "pager should be correct"); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40, 'there should be 40 records displayed on page 1'); + assert.verifySteps(['write', 'read', 'read', 'read']); form.destroy(); }); - QUnit.test('default_get, onchange, onchange on m2m', function (assert) { + QUnit.test('default_get, onchange, onchange on m2m', async function (assert) { assert.expect(1); this.data.partner.onchanges.int_field = function (obj) { @@ -978,7 +977,7 @@ QUnit.module('fields', {}, function () { ]; }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -994,15 +993,15 @@ QUnit.module('fields', {}, function () { '</form>', }); - testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); + await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); form.destroy(); }); - QUnit.test('widget many2many_tags', function (assert) { + QUnit.test('widget many2many_tags', async function (assert) { assert.expect(1); this.data.turtle.records[0].partner_ids = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'turtle', data: this.data, @@ -1023,7 +1022,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2many list add *many* records, remove, re-add', function (assert) { + QUnit.test('many2many list add *many* records, remove, re-add', async function (assert) { assert.expect(5); this.data.partner.fields.timmy.domain = [['color', '=', 2]]; @@ -1035,7 +1034,7 @@ QUnit.module('fields', {}, function () { this.data.partner_type.records.push(new_record_partner_type); } - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1055,52 +1054,52 @@ 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); }, }); // First round: add 51 records in batch - testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); var $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); - testUtils.dom.click($modal.find('thead input[type=checkbox]')); + await testUtils.dom.click($modal.find('thead input[type=checkbox]')); - testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button')); + await testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button')); var m2m_records = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_data_cell:not(.o_many2many_tags_cell)'); assert.equal(m2m_records.length, 51, 'We should have added all the records present in the search view to the m2m field'); // the 50 in batch + 'gold' - testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_save')); + await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_save')); // Secound round: remove one record - testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit')); + await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit')); var trash_buttons = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_list_record_remove'); - testUtils.dom.click(trash_buttons.first()); + await testUtils.dom.click(trash_buttons.first()); var pager_limit = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_pager_limit'); assert.equal(pager_limit.text(), '50', 'We should have 50 records in the m2m field'); // Third round: re-add 1 records - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); - testUtils.dom.click($modal.find('thead input[type=checkbox]')); + await testUtils.dom.click($modal.find('thead input[type=checkbox]')); - testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button')); + await testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button')); pager_limit = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_pager_limit'); assert.equal(pager_limit.text(), '51', 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(); diff --git a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js index 18581b88078..c29bf4f1ec9 100644 --- a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js +++ b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js @@ -159,7 +159,7 @@ QUnit.module('fields', {}, function () { }, function () { QUnit.module('FieldOne2Many'); - QUnit.test('New record with a o2m also with 2 new records, ordered, and resequenced', function (assert) { + QUnit.test('New record with a o2m also with 2 new records, ordered, and resequenced', async function (assert) { assert.expect(3); // Needed to have two new records in a single stroke @@ -169,11 +169,11 @@ QUnit.module('fields', {}, function () { [5], [0, 0, { trululu: false }], [0, 0, { trululu: false }], - ] + ]; } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -190,7 +190,7 @@ QUnit.module('fields', {}, function () { mode: 'create', }, mockRPC: function (route, args) { - assert.step(args.method + ' ' + args.model) + assert.step(args.method + ' ' + args.model); return this._super(route, args); }, }); @@ -198,7 +198,7 @@ QUnit.module('fields', {}, function () { // change the int_field through drag and drop // that way, we'll trigger the sorting and the name_get // of the lines of "p" - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -211,7 +211,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('O2M List with pager, decoration and default_order: add and cancel adding', function (assert) { + QUnit.test('O2M List with pager, decoration and default_order: add and cancel adding', async function (assert) { assert.expect(3); // The decoration on the list implies that its condition will be evaluated @@ -222,7 +222,7 @@ QUnit.module('fields', {}, function () { // and evaluation of the decoration against *visible records* this.data.partner.records[0].p = [2, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -240,30 +240,25 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_field_x2many_list .o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list .o_field_x2many_list_row_add a')); - var $dataRows = form.$('.o_field_x2many_list .o_data_row'); - assert.equal($dataRows.length, 2, + assert.containsN(form, '.o_field_x2many_list .o_data_row', 2, 'There should be 2 rows'); - var $expectedSelectedRow = $dataRows.eq(1); + var $expectedSelectedRow = form.$('.o_field_x2many_list .o_data_row').eq(1); var $actualSelectedRow = form.$('.o_selected_row'); assert.equal($actualSelectedRow[0], $expectedSelectedRow[0], 'The selected row should be the new one'); // Cancel Creation - var escapeKey = $.ui.keyCode.ESCAPE; - $actualSelectedRow.find('input').trigger( - $.Event('keydown', { which: escapeKey, keyCode: escapeKey })); - - $dataRows = form.$('.o_field_x2many_list .o_data_row'); - assert.equal($dataRows.length, 1, + await testUtils.fields.triggerKeydown($actualSelectedRow.find('input'), 'escape'); + assert.containsOnce(form, '.o_field_x2many_list .o_data_row', 'There should be 1 row'); form.destroy(); }); - QUnit.test('O2M with parented m2o and domain on parent.m2o', function (assert) { + QUnit.test('O2M with parented m2o and domain on parent.m2o', async function (assert) { assert.expect(3); /* records in an o2m can have a m2o pointing to themselves @@ -272,7 +267,7 @@ QUnit.module('fields', {}, function () { */ this.data.turtle.fields.parent_id = { string: "Parent", type: "many2one", relation: 'turtle' }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -297,31 +292,31 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_field_x2many_list[name=turtles] .o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list[name=turtles] .o_field_x2many_list_row_add a')); - testUtils.fields.many2one.clickOpenDropdown('parent_id'); - testUtils.fields.many2one.clickHighlightedItem('parent_id'); + await testUtils.fields.many2one.clickOpenDropdown('parent_id'); + await testUtils.fields.many2one.clickHighlightedItem('parent_id'); var $modal = $('.modal-content'); - testUtils.dom.click($modal.eq(1).find('.modal-footer .btn-primary').eq(0)); - testUtils.dom.click($modal.eq(0).find('.modal-footer .btn-primary').eq(1)); + await testUtils.dom.click($modal.eq(1).find('.modal-footer .btn-primary').eq(0)); + await testUtils.dom.click($modal.eq(0).find('.modal-footer .btn-primary').eq(1)); - assert.equal(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', 'The main record should have the new record in its o2m'); $modal = $('.modal-content'); - testUtils.dom.click($modal.find('.o_field_many2one input')); + await testUtils.dom.click($modal.find('.o_field_many2one input')); form.destroy(); }); - QUnit.test('one2many list editable with cell readonly modifier', function (assert) { + QUnit.test('one2many list editable with cell readonly modifier', async function (assert) { assert.expect(4); this.data.partner.records[0].p = [2]; this.data.partner.records[1].turtles = [1, 2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -344,22 +339,22 @@ QUnit.module('fields', {}, function () { } }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); var $targetInput = $('.o_selected_row .o_input[name=foo]'); assert.equal($targetInput[0], document.activeElement, 'The first input of the line should have the focus'); // Simulating hitting the 'f' key twice - testUtils.fields.editInput($targetInput, 'f'); - testUtils.fields.editInput($targetInput, $targetInput.val() + 'f'); + await testUtils.fields.editInput($targetInput, 'f'); + await testUtils.fields.editInput($targetInput, $targetInput.val() + 'f'); assert.equal($targetInput[0], document.activeElement, 'The first input of the line should still have the focus'); // Simulating a TAB key - $targetInput.trigger($.Event('keydown', { which: 9, keyCode: 9 })); + await testUtils.fields.triggerKeydown($targetInput, 'tab'); var $secondTarget = $('.o_selected_row .o_input[name=qux]'); @@ -367,19 +362,19 @@ QUnit.module('fields', {}, function () { 'The second input of the line should have the focus after the TAB press'); - testUtils.fields.editInput($secondTarget, 9); - testUtils.fields.editInput($secondTarget, $secondTarget.val() + 9); + await testUtils.fields.editInput($secondTarget, 9); + await testUtils.fields.editInput($secondTarget, $secondTarget.val() + 9); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many basic properties', function (assert) { + QUnit.test('one2many basic properties', 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, @@ -412,7 +407,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('td.o_list_record_remove').length, "embedded one2many records should not have a remove icon"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.ok(form.$('.o_field_x2many_list_row_add').length, "embedded one2many should now be editable"); @@ -425,10 +420,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('transferring class attributes in one2many sub fields', function (assert) { + QUnit.test('transferring class attributes in one2many sub fields', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -445,12 +440,12 @@ QUnit.module('fields', {}, function () { assert.containsOnce(form, 'td.hey', 'should have a td with the desired class'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsOnce(form, 'td.hey', 'should have a td with the desired class'); - testUtils.dom.click(form.$('td.o_data_cell')); + await testUtils.dom.click(form.$('td.o_data_cell')); assert.containsOnce(form, 'input[name="turtle_foo"].hey', 'should have an input with the desired class'); @@ -458,11 +453,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with date and datetime', function (assert) { + QUnit.test('one2many with date and datetime', async function (assert) { assert.expect(2); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -494,11 +489,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('rendering with embedded one2many', function (assert) { + QUnit.test('rendering with embedded one2many', async function (assert) { assert.expect(2); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -526,11 +521,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('use the limit attribute in arch (in field o2m inline tree view)', function (assert) { + QUnit.test('use the limit attribute in arch (in field o2m inline tree view)', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [1, 2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -556,11 +551,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('use the limit attribute in arch (in field o2m non inline tree view)', function (assert) { + QUnit.test('use the limit attribute in arch (in field o2m non inline tree view)', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [1, 2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -585,11 +580,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with default_order on view not inline', function (assert) { + QUnit.test('one2many with default_order on view not inline', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = [1, 2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -615,11 +610,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('embedded one2many with widget', function (assert) { + QUnit.test('embedded one2many with widget', async function (assert) { assert.expect(1); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -644,7 +639,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('embedded one2many with handle widget', function (assert) { + QUnit.test('embedded one2many with handle widget', async function (assert) { assert.expect(10); var nbConfirmChange = 0; @@ -657,7 +652,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles = [1, 2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -685,14 +680,14 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa", "should have the 3 rows in the correct order"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa", "should still have the 3 rows in the correct order"); assert.strictEqual(nbConfirmChange, 0, "should not have confirmed any change yet"); // Drag and drop the second line in first position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -705,7 +700,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipyopkawa", "should have the 3 rows in the new order"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.deepEqual(_.map(this.data.turtle.records, function (turtle) { return _.pick(turtle, 'id', 'turtle_foo', 'turtle_int'); @@ -723,7 +718,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange for embedded one2many in a one2many with a second page', function (assert) { + QUnit.test('onchange for embedded one2many in a one2many with a second page', async function (assert) { assert.expect(1); this.data.turtle.fields.partner_ids.type = 'one2many'; @@ -747,7 +742,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -778,16 +773,16 @@ QUnit.module('fields', {}, function () { } }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_data_cell').eq(1)); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_data_cell').eq(1)); var $cell = form.$('.o_selected_row .o_input[name=turtle_foo]'); - testUtils.fields.editSelect($cell, "hop"); - testUtils.form.clickSave(form); + await testUtils.fields.editSelect($cell, "hop"); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('onchange for embedded one2many in a one2many updated by server', function (assert) { + QUnit.test('onchange for embedded one2many in a one2many updated by server', async function (assert) { // here we test that after an onchange, the embedded one2many field has // been updated by a new list of ids by the server response, to this new // list should be correctly sent back at save time @@ -809,7 +804,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -840,11 +835,11 @@ QUnit.module('fields', {}, function () { assert.deepEqual(form.$('.o_many2many_tags_cell').text().trim(), "second record", "the partner_ids should be as specified at initialization"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_data_cell').eq(1)); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_data_cell').eq(1)); var $cell = form.$('.o_selected_row .o_input[name=turtle_foo]'); - testUtils.fields.editSelect($cell, "hop"); - testUtils.form.clickSave(form); + await testUtils.fields.editSelect($cell, "hop"); + await testUtils.form.clickSave(form); assert.deepEqual(form.$('.o_many2many_tags_cell').text().trim().split(/\s+/), ["second", "record", "aaa"], @@ -853,24 +848,24 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange for embedded one2many with handle widget', function (assert) { + QUnit.test('onchange for embedded one2many with handle widget', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [1, 2, 3]; var partnerOnchange = 0; this.data.partner.onchanges = { - turtles: function (obj) { + turtles: function () { partnerOnchange++; }, }; var turtleOnchange = 0; this.data.turtle.onchanges = { - turtle_int: function (obj) { + turtle_int: function () { turtleOnchange++; }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -891,10 +886,10 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // Drag and drop the second line in first position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -906,7 +901,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange for embedded one2many with handle widget using same sequence', function (assert) { + QUnit.test('onchange for embedded one2many with handle widget using same sequence', async function (assert) { assert.expect(4); this.data.turtle.records[0].turtle_int = 1; @@ -920,7 +915,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -948,14 +943,14 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa", "should have the 3 rows in the correct order"); // Drag and drop the second line in first position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -965,11 +960,11 @@ QUnit.module('fields', {}, function () { "should still have the 3 rows in the correct order"); assert.strictEqual(turtleOnchange, 3, "should update all lines"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('onchange (with command 5) for embedded one2many with handle widget', function (assert) { + QUnit.test('onchange (with command 5) for embedded one2many with handle widget', async function (assert) { assert.expect(3); var ids = []; @@ -990,7 +985,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1009,16 +1004,16 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa", "should have the 3 rows in the correct order"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp'); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp'); // Drag and drop the third line in second position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(2), form.$('.o_field_one2many tbody tr').eq(1), { position: 'top' } @@ -1026,8 +1021,8 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_cell').text(), "blurpkawablip", "should display to record in 'turtle_int' order"); - testUtils.form.clickSave(form); - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); assert.strictEqual(form.$('.o_data_cell:not(.o_handle_cell)').text(), "blurpkawablip", "should display to record in 'turtle_int' order"); @@ -1035,7 +1030,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange with modifiers for embedded one2many on the second page', function (assert) { + QUnit.test('onchange with modifiers for embedded one2many on the second page', async function (assert) { assert.expect(7); var data = this.data; @@ -1074,7 +1069,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: data, @@ -1094,29 +1089,29 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29", "should display the records in order"); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp'); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp'); // the domain fail if the widget does not use the allready loaded data. - testUtils.form.clickDiscard(form); + await testUtils.form.clickDiscard(form); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "blurp#21#22#23#24#25#26#27#28#29", "should display the records in order with the changes"); - testUtils.dom.click($('.modal .modal-footer button:first')); + await testUtils.dom.click($('.modal .modal-footer button:first')); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29", "should cancel changes and display the records in order"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // Drag and drop the third line in second position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(2), form.$('.o_field_one2many tbody tr').eq(1), { position: 'top' } @@ -1126,7 +1121,7 @@ QUnit.module('fields', {}, function () { "should display the records in order after resequence (display record with turtle_int=0)"); // Drag and drop the third line in second position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(2), form.$('.o_field_one2many tbody tr').eq(1), { position: 'top' } @@ -1135,12 +1130,12 @@ QUnit.module('fields', {}, function () { assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#39#40#41#42#43#44#45#46#47", "should display the records in order after resequence (display record with turtle_int=0)"); - testUtils.form.clickDiscard(form); + await testUtils.form.clickDiscard(form); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#39#40#41#42#43#44#45#46#47", "should display the records in order after resequence"); - testUtils.dom.click($('.modal .modal-footer button:first')); + await testUtils.dom.click($('.modal .modal-footer button:first')); assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29", "should cancel changes and display the records in order"); @@ -1148,7 +1143,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange followed by edition on the second page', function (assert) { + QUnit.test('onchange followed by edition on the second page', async function (assert) { assert.expect(12); var ids = []; @@ -1169,7 +1164,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1188,30 +1183,30 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1'); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2'); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1'); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2'); assert.containsN(form, '.o_data_row', 40, "should display 40 records"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 0, "should display '#39' at the first line"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, '.o_data_row', 40, "should display 39 records and the create line"); assert.containsOnce(form, '.o_data_row:first .o_field_char', "should display the create line in first position"); assert.strictEqual(form.$('.o_data_row:first .o_field_char').val(), "", "should an empty input"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 1, "should display '#39' at the second line"); - testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3'); + await testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3'); assert.containsOnce(form, '.o_data_row:first .o_field_char', "should display the create line in first position after onchange"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 1, "should display '#39' at the second line after onchange"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, '.o_data_row', 40, "should display 39 records and the create line"); assert.containsOnce(form, '.o_data_row:first .o_field_char', "should display the create line in first position"); @@ -1221,7 +1216,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange followed by edition on the second page (part 2)', function (assert) { + QUnit.test('onchange followed by edition on the second page (part 2)', async function (assert) { assert.expect(8); var ids = []; @@ -1244,7 +1239,7 @@ QUnit.module('fields', {}, function () { // bottom order - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1263,25 +1258,25 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1'); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2'); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1'); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2'); assert.containsN(form, '.o_data_row', 40, "should display 40 records"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#77))').index(), 39, "should display '#77' at the last line"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, '.o_data_row', 41, "should display 41 records and the create line"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#76))').index(), 38, "should display '#76' at the penultimate line"); assert.strictEqual(form.$('.o_data_row:has(.o_field_char)').index(), 40, "should display the create line at the last position"); - testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3'); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, '.o_data_row', 42, "should display 42 records and the create line"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#76))').index(), 38, "should display '#76' at the penultimate line"); @@ -1290,7 +1285,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange returning a command 6 for an x2many', function (assert) { + QUnit.test('onchange returning a command 6 for an x2many', async function (assert) { assert.expect(2); this.data.partner.onchanges = { @@ -1299,7 +1294,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1321,7 +1316,7 @@ QUnit.module('fields', {}, function () { "there should be one record in the relation"); // change the value of foo to trigger the onchange - testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); assert.containsN(form, '.o_data_row', 3, "there should be three records in the relation"); @@ -1329,7 +1324,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('x2many fields inside x2manys are fetched after an onchange', function (assert) { + QUnit.test('x2many fields inside x2manys are fetched after an onchange', async function (assert) { assert.expect(6); this.data.turtle.records[0].partner_ids = [1]; @@ -1340,7 +1335,7 @@ QUnit.module('fields', {}, function () { }; var checkRPC = false; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1379,7 +1374,7 @@ QUnit.module('fields', {}, function () { // change the value of foo to trigger the onchange checkRPC = true; // enable flag to check read RPC for the m2m field - testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); assert.containsN(form, '.o_data_row', 3, "there should be three records in the relation"); @@ -1389,7 +1384,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('reference fields inside x2manys are fetched after an onchange', function (assert) { + QUnit.test('reference fields inside x2manys are fetched after an onchange', async function (assert) { assert.expect(5); this.data.turtle.records[1].turtle_ref = 'product,41'; @@ -1400,7 +1395,7 @@ QUnit.module('fields', {}, function () { }; var checkRPC = false; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1437,7 +1432,7 @@ QUnit.module('fields', {}, function () { // change the value of foo to trigger the onchange checkRPC = true; // enable flag to check read RPC for reference field - testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); assert.containsN(form, '.o_data_row', 3, "there should be three records in the relation"); @@ -1447,7 +1442,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange on one2many containing x2many in form view', function (assert) { + QUnit.test('onchange on one2many containing x2many in form view', async function (assert) { assert.expect(16); this.data.partner.onchanges = { @@ -1456,7 +1451,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1486,20 +1481,20 @@ QUnit.module('fields', {}, function () { // open the created o2m record in a form view, and add a m2m subrecord // in its relation - testUtils.dom.click(form.$('.o_data_row')); + await testUtils.dom.click(form.$('.o_data_row')); assert.strictEqual($('.modal').length, 1, "should have opened a dialog"); assert.strictEqual($('.modal .o_data_row').length, 0, "there should be no record in the one2many in the dialog"); // add a many2many subrecord - testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 2, "should have opened a second dialog"); // select a many2many subrecord - testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first')); + await testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first')); assert.strictEqual($('.modal').length, 1, "second dialog should be closed"); @@ -1509,25 +1504,25 @@ QUnit.module('fields', {}, function () { 'm2m pager should be hidden'); // click on 'Save & Close' - testUtils.dom.click($('.modal-footer .btn-primary:first')); + await testUtils.dom.click($('.modal-footer .btn-primary:first')); assert.strictEqual($('.modal').length, 0, "dialog should be closed"); // reopen o2m record, and another m2m subrecord in its relation, but // discard the changes - testUtils.dom.click(form.$('.o_data_row')); + await testUtils.dom.click(form.$('.o_data_row')); assert.strictEqual($('.modal').length, 1, "should have opened a dialog"); assert.strictEqual($('.modal .o_data_row').length, 1, "there should be one record in the one2many in the dialog"); // add another m2m subrecord - testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 2, "should have opened a second dialog"); - testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first')); + await testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first')); assert.strictEqual($('.modal').length, 1, "second dialog should be closed"); @@ -1535,12 +1530,12 @@ QUnit.module('fields', {}, function () { "there should be two records in the one2many in the dialog"); // click on 'Discard' - testUtils.dom.clickFirst($('.modal-footer .btn-secondary')); + await testUtils.dom.clickFirst($('.modal-footer .btn-secondary')); assert.strictEqual($('.modal').length, 0, "dialog should be closed"); // reopen o2m record to check that second changes have properly been discarded - testUtils.dom.click(form.$('.o_data_row')); + await testUtils.dom.click(form.$('.o_data_row')); assert.strictEqual($('.modal').length, 1, "should have opened a dialog"); assert.strictEqual($('.modal .o_data_row').length, 1, @@ -1549,7 +1544,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('embedded one2many with handle widget with minimum setValue calls', function (assert) { + QUnit.test('embedded one2many with handle widget with minimum setValue calls', async function (assert) { var done = assert.async(); assert.expect(20); @@ -1574,7 +1569,7 @@ QUnit.module('fields', {}, function () { }); this.data.partner.records[0].turtles = [1, 2, 3, 4, 5, 6, 7]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1596,28 +1591,26 @@ QUnit.module('fields', {}, function () { }); testUtils.mock.intercept(form, "field_changed", function (event) { - assert.step(form.model.get(event.data.changes.turtles.id).res_id); + assert.step(String(form.model.get(event.data.changes.turtles.id).res_id)); }, true); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - var steps = []; var positions = [ - [6, 0, 'top', [3, 6, 1, 2, 5, 7, 4]], // move the last to the first line - [5, 1, 'top', [7, 6, 1, 2, 5]], // move the penultimate to the second line - [2, 5, 'center', [1, 2, 5, 6]], // move the third to the penultimate line + [6, 0, 'top', ['3', '6', '1', '2', '5', '7', '4']], // move the last to the first line + [5, 1, 'top', ['7', '6', '1', '2', '5']], // move the penultimate to the second line + [2, 5, 'center', ['1', '2', '5', '6']], // move the third to the penultimate line ]; - function dragAndDrop() { + async function dragAndDrop() { var pos = positions.shift(); - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(pos[0]), form.$('tbody tr').eq(pos[1]), { position: pos[2] } ); - steps = steps.concat(pos[3]); - assert.verifySteps(steps, + assert.verifySteps(pos[3], "sequences values should be apply from the begin index to the drop index"); if (positions.length) { @@ -1644,11 +1637,11 @@ QUnit.module('fields', {}, function () { dragAndDrop(); }); - QUnit.test('embedded one2many (editable list) with handle widget', function (assert) { + QUnit.test('embedded one2many (editable list) with handle widget', async function (assert) { assert.expect(8); this.data.partner.records[0].p = [1, 2, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1676,12 +1669,12 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "My little Foo Valueblipyop", "should have the 3 rows in the correct order"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "My little Foo Valueblipyop", "should still have the 3 rows in the correct order"); // Drag and drop the second line in first position - testUtils.dom.dragAndDrop( + await testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -1693,19 +1686,19 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipMy little Foo Valueyop", "should have the 3 rows in the new order"); - testUtils.dom.click(form.$('tbody tr:first td:first')); + await testUtils.dom.click(form.$('tbody tr:first td:first')); assert.strictEqual(form.$('tbody tr:first td.o_data_cell:not(.o_handle_cell) input').val(), "blip", "should edit the correct row"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipMy little Foo Valueyop", "should still have the 3 rows in the new order"); form.destroy(); }); - QUnit.test('one2many field when using the pager', function (assert) { + QUnit.test('one2many field when using the pager', async function (assert) { assert.expect(13); var ids = []; @@ -1721,7 +1714,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[1].p = ids.slice(42); var count = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1759,6 +1752,7 @@ QUnit.module('fields', {}, function () { // related records of record 1 anymore). Two additional RPCs should have // been done form.pager.next(); + await testUtils.nextTick(); assert.strictEqual(count, 4, 'two RPCs should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 3, 'one2many kanban should contain 3 cards for record 2'); @@ -1766,19 +1760,21 @@ QUnit.module('fields', {}, function () { // move back to record 1, which should contain again its first 40 related // records form.pager.previous(); + await testUtils.nextTick(); assert.strictEqual(count, 6, 'two RPCs should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40, 'one2many kanban should contain 40 cards for record 1'); // move to the second page of the o2m: 1 RPC should have been done to fetch // the 2 subrecords of page 2, and those records should now be displayed - testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); + await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); assert.strictEqual(count, 7, 'one RPC should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 2, 'one2many kanban should contain 2 cards for record 1 at page 2'); // move to record 2 again and check that everything is correctly updated form.pager.next(); + await testUtils.nextTick(); assert.strictEqual(count, 9, 'two RPCs should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 3, 'one2many kanban should contain 3 cards for record 2'); @@ -1786,15 +1782,16 @@ QUnit.module('fields', {}, function () { // move back to record 1 and move to page 2 again: all data should have // been correctly reloaded form.pager.previous(); + await testUtils.nextTick(); assert.strictEqual(count, 11, 'two RPCs should have been done'); - testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); + await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); assert.strictEqual(count, 12, 'one RPC should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 2, 'one2many kanban should contain 2 cards for record 1 at page 2'); form.destroy(); }); - QUnit.test('edition of one2many field with pager', function (assert) { + QUnit.test('edition of one2many field with pager', async function (assert) { assert.expect(31); var ids = []; @@ -1811,7 +1808,7 @@ QUnit.module('fields', {}, function () { var saveCount = 0; var checkRead = false; var readIDs; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1894,10 +1891,10 @@ QUnit.module('fields', {}, function () { // add a record on page one checkRead = true; - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o-kanban-button-new')); - testUtils.fields.editInput($('.modal input'), 'new record'); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o-kanban-button-new')); + await testUtils.fields.editInput($('.modal input'), 'new record'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); // checks assert.strictEqual(readIDs, undefined, "should not have read any record"); assert.strictEqual(form.$('span:contains(new record)').length, 0, @@ -1909,14 +1906,14 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_kanban_record:first span:contains(new record)').length, 0, 'new record should not be on page 1'); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); // delete a record on page one checkRead = true; - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 10)').length, 1, 'first record should be the one with id 10 (next checks rely on that)'); - testUtils.dom.click(form.$('.delete_icon:first')); + await testUtils.dom.click(form.$('.delete_icon:first')); // checks assert.deepEqual(readIDs, [50], "should have read a record (to display 40 records on page 1)"); @@ -1925,31 +1922,31 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), '1-40 / 45', "pager range should be correct"); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); // add and delete records in both pages - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); checkRead = true; readIDs = undefined; // add and delete a record in page 1 - testUtils.dom.click(form.$('.o-kanban-button-new')); - testUtils.fields.editInput($('.modal input'), 'new record page 1'); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click(form.$('.o-kanban-button-new')); + await testUtils.fields.editInput($('.modal input'), 'new record page 1'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 11)').length, 1, 'first record should be the one with id 11 (next checks rely on that)'); - testUtils.dom.click(form.$('.delete_icon:first')); + await testUtils.dom.click(form.$('.delete_icon:first')); assert.deepEqual(readIDs, [51], "should have read a record (to display 40 records on page 1)"); // add and delete a record in page 2 - testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); + await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 52)').length, 1, 'first record should be the one with id 52 (next checks rely on that)'); checkRead = true; readIDs = undefined; - testUtils.dom.click(form.$('.delete_icon:first')); - testUtils.dom.click(form.$('.o-kanban-button-new')); - testUtils.fields.editInput($('.modal input'), 'new record page 2'); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click(form.$('.delete_icon:first')); + await testUtils.dom.click(form.$('.o-kanban-button-new')); + await testUtils.fields.editInput($('.modal input'), 'new record page 2'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual(readIDs, undefined, "should not have read any record"); // checks assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5, @@ -1961,12 +1958,12 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_kanban_record span:contains(new record page 2)').length, 1, 'new records should be on page 2'); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('edition of one2many field, with onchange and not inline sub view', function (assert) { + QUnit.test('edition of one2many field, with onchange and not inline sub view', async function (assert) { assert.expect(2); this.data.turtle.onchanges.turtle_int = function (obj) { @@ -1974,7 +1971,7 @@ QUnit.module('fields', {}, function () { }; this.data.partner.onchanges.turtles = function () { }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -1985,27 +1982,27 @@ QUnit.module('fields', {}, function () { 'turtle,false,list': '<tree><field name="turtle_foo"/></tree>', 'turtle,false,form': '<form><group><field name="turtle_foo"/><field name="turtle_int"/></group></form>', }, - mockRPC: function (route, args) { + mockRPC: function () { return this._super.apply(this, arguments); }, res_id: 1, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput($('input[name="turtle_int"]'), '5'); - testUtils.dom.click($('.modal-footer button.btn-primary').first()); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput($('input[name="turtle_int"]'), '5'); + await testUtils.dom.click($('.modal-footer button.btn-primary').first()); assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '5', 'should display 5 in the foo field'); - testUtils.dom.click(form.$('tbody tr:eq(1) td.o_data_cell')); + await testUtils.dom.click(form.$('tbody tr:eq(1) td.o_data_cell')); - testUtils.fields.editInput($('input[name="turtle_int"]'), '3'); - testUtils.dom.click($('.modal-footer button.btn-primary').first()); + await testUtils.fields.editInput($('input[name="turtle_int"]'), '3'); + await testUtils.dom.click($('.modal-footer button.btn-primary').first()); assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '3', 'should now display 3 in the foo field'); form.destroy(); }); - QUnit.test('sorting one2many fields', function (assert) { + QUnit.test('sorting one2many fields', async function (assert) { assert.expect(4); this.data.partner.fields.foo.sortable = true; @@ -2015,7 +2012,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].p = [23, 24, 25]; var rpcCount = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2040,20 +2037,20 @@ QUnit.module('fields', {}, function () { throw "should not render the whole form"; }; - testUtils.dom.click(form.$('table thead th:contains(Foo)')); + await testUtils.dom.click(form.$('table thead th:contains(Foo)')); assert.strictEqual(rpcCount, 0, 'sort should be in memory, no extra RPCs should have been done'); assert.ok(form.$('table tbody tr:eq(2) td:contains(xyz)').length, "the 3rd record is the one with 'xyz' value"); - testUtils.dom.click(form.$('table thead th:contains(Foo)')); + await testUtils.dom.click(form.$('table thead th:contains(Foo)')); assert.ok(form.$('table tbody tr:eq(2) td:contains(abc)').length, "the 3rd record is the one with 'abc' value"); form.destroy(); }); - QUnit.test('one2many list field edition', function (assert) { + QUnit.test('one2many list field edition', async function (assert) { assert.expect(6); this.data.partner.records.push({ @@ -2062,7 +2059,7 @@ QUnit.module('fields', {}, function () { }); this.data.partner.records[1].p = [3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2079,33 +2076,33 @@ QUnit.module('fields', {}, function () { // edit the first line of the o2m assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'relational record 1', "display name of first record in o2m list should be 'relational record 1'"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_one2many tbody td').first()); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_one2many tbody td').first()); assert.hasClass(form.$('.o_field_one2many tbody td').first().parent(),'o_selected_row', "first row of o2m should be in edition"); - testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value"); + await testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value"); assert.hasClass(form.$('.o_field_one2many tbody td').first().parent(),'o_selected_row', "first row of o2m should still be in edition"); // // leave o2m edition - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$el); assert.doesNotHaveClass(form.$('.o_field_one2many tbody td').first().parent(), 'o_selected_row', "first row of o2m should be readonly again"); // discard changes - testUtils.form.clickDiscard(form); + await testUtils.form.clickDiscard(form); assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'new value', "changes shouldn't have been discarded yet, waiting for user confirmation"); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'relational record 1', "display name of first record in o2m list should be 'relational record 1'"); // edit again and save - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_one2many tbody td').first()); - testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value"); - testUtils.dom.click(form.$el); - testUtils.form.clickSave(form); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_one2many tbody td').first()); + await testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value"); + await testUtils.dom.click(form.$el); + await testUtils.form.clickSave(form); // FIXME: this next test doesn't pass as the save of updates of // relational data is temporarily disabled // assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'new value', @@ -2114,9 +2111,9 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list: create action disabled', function (assert) { + QUnit.test('one2many list: create action disabled', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2133,17 +2130,17 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in readonly'); form.destroy(); }); - QUnit.test('one2many list: unlink two records', function (assert) { + QUnit.test('one2many list: unlink two records', async function (assert) { assert.expect(9); this.data.partner.records[0].p = [1, 2, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2174,7 +2171,7 @@ QUnit.module('fields', {}, function () { '<form string="Partner"><field name="display_name"/></form>', }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsN(form, 'td.o_list_record_remove button', 3, "should have 3 remove buttons"); @@ -2182,28 +2179,28 @@ QUnit.module('fields', {}, function () { assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-times', "should have X icons to remove (unlink) records"); - testUtils.dom.click(form.$('td.o_list_record_remove button').first()); + await testUtils.dom.click(form.$('td.o_list_record_remove button').first()); assert.containsN(form, 'td.o_list_record_remove button', 2, "should have 2 remove buttons (a record is supposed to have been unlinked)"); - testUtils.dom.click(form.$('tr.o_data_row').first()); + await testUtils.dom.click(form.$('tr.o_data_row').first()); assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, 'there should be a modal having Remove Button'); - testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); + await testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); assert.containsOnce(form, 'td.o_list_record_remove button', "should have 1 delete button (another record is supposed to have been unlinked)"); // save and check that the correct command has been generated - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many list: deleting two records', function (assert) { + QUnit.test('one2many list: deleting two records', async function (assert) { assert.expect(9); this.data.partner.records[0].p = [1, 2, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2234,7 +2231,7 @@ QUnit.module('fields', {}, function () { '<form string="Partner"><field name="display_name"/></form>', }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsN(form, 'td.o_list_record_remove button', 3, "should have 3 remove buttons"); @@ -2242,21 +2239,21 @@ QUnit.module('fields', {}, function () { assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-trash-o', "should have trash bin icons to remove (delete) records"); - testUtils.dom.click(form.$('td.o_list_record_remove button').first()); + await testUtils.dom.click(form.$('td.o_list_record_remove button').first()); assert.containsN(form, 'td.o_list_record_remove button', 2, "should have 2 remove buttons (a record is supposed to have been deleted)"); - testUtils.dom.click(form.$('tr.o_data_row').first()); + await testUtils.dom.click(form.$('tr.o_data_row').first()); assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, 'there should be a modal having Remove Button'); - testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); + await testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); assert.containsOnce(form, 'td.o_list_record_remove button', "should have 1 remove button (another record is supposed to have been deleted)"); // save and check that the correct command has been generated - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); // FIXME: it would be nice to test that the view is re-rendered correctly, // but as the relational data isn't re-fetched, the rendering is ok even @@ -2264,11 +2261,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many kanban: edition', function (assert) { + QUnit.test('one2many kanban: edition', async function (assert) { assert.expect(17); this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2303,7 +2300,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_one2many .o-kanban-button-new').length, '"Create" button should not be visible in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1, 'should contain 1 record'); @@ -2321,40 +2318,40 @@ QUnit.module('fields', {}, function () { 'Create button should have "Add" label'); // edit existing subrecord - testUtils.dom.click(form.$('.oe_kanban_global_click')); + await testUtils.dom.click(form.$('.oe_kanban_global_click')); - testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new name'); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new name'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_kanban_record span:first').text(), 'new name', 'value of subrecord should have been updated'); // create a new subrecord - testUtils.dom.click(form.$('.o-kanban-button-new')); - testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 1'); - testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); + await testUtils.dom.click(form.$('.o-kanban-button-new')); + await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 1'); + await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, 'should contain 2 records'); assert.strictEqual(form.$('.o_kanban_record:nth(1) span').text(), 'new subrecord 1', 'value of newly created subrecord should be "new subrecord 1"'); // create two new subrecords - testUtils.dom.click(form.$('.o-kanban-button-new')); - testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 2'); - testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)')); - testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 3'); - testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); + await testUtils.dom.click(form.$('.o-kanban-button-new')); + await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 2'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)')); + await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 3'); + await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4, 'should contain 4 records'); // delete subrecords - testUtils.dom.click(form.$('.oe_kanban_global_click').first()); + await testUtils.dom.click(form.$('.oe_kanban_global_click').first()); assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, 'There should be a modal having Remove Button'); - testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); + await testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 3, 'should contain 3 records'); - testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()')); - testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()')); + await testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()')); + await testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1, 'should contain 1 records'); assert.strictEqual(form.$('.o_kanban_record span:first').text(), 'new subrecord 3', @@ -2362,10 +2359,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many kanban (editable): properly handle create_text node option', function (assert) { + QUnit.test('one2many kanban (editable): properly handle create_text node option', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2385,19 +2382,19 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o-kanban-button-new').text().trim(), "Add turtle", "In O2M Kanban, Add button should have 'Add turtle' label"); form.destroy(); }); - QUnit.test('one2many kanban: create action disabled', function (assert) { + QUnit.test('one2many kanban: create action disabled', async function (assert) { assert.expect(3); this.data.partner.records[0].p = [4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2422,7 +2419,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o-kanban-button-new').length, '"Add" button should not be available in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.ok(!form.$('.o-kanban-button-new').length, '"Add" button should not be available in edit'); @@ -2431,13 +2428,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable one2many list, pager is updated', function (assert) { + QUnit.test('editable one2many list, pager is updated', async function (assert) { assert.expect(1); this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' }); this.data.partner.records[0].turtles = [1, 2, 3, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2452,21 +2449,21 @@ QUnit.module('fields', {}, function () { }); // add a record, then click in form view to confirm it - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$el); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 5', "pager should display the correct total"); form.destroy(); }); - QUnit.test('one2many list (non editable): edition', function (assert) { + QUnit.test('one2many list (non editable): edition', async function (assert) { assert.expect(12); var nbWrite = 0; this.data.partner.records[0].p = [2, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2497,7 +2494,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not be visible in readonly'); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 records'); @@ -2509,10 +2506,10 @@ QUnit.module('fields', {}, function () { '"Add an item" should not visible in edit'); // edit existing subrecord - testUtils.dom.click(form.$('.o_list_view tbody tr:first() td:eq(1)')); + await testUtils.dom.click(form.$('.o_list_view tbody tr:first() td:eq(1)')); - testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name', 'value of subrecord should have been updated'); assert.strictEqual(nbWrite, 0, "should not have write anything in DB"); @@ -2521,23 +2518,23 @@ QUnit.module('fields', {}, function () { // TODO when 'Add an item' will be implemented // remove subrecords - testUtils.dom.click(form.$('.o_list_record_remove:nth(1)')); + await testUtils.dom.click(form.$('.o_list_record_remove:nth(1)')); assert.containsOnce(form, '.o_list_view td.o_list_number', 'should contain 1 subrecord'); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name', 'the remaining subrecord should be "new name"'); - testUtils.form.clickSave(form); // save the record + await testUtils.form.clickSave(form); // save the record assert.strictEqual(nbWrite, 1, "should have write the changes in DB"); form.destroy(); }); - QUnit.test('one2many list (editable): edition', function (assert) { + QUnit.test('one2many list (editable): edition', async function (assert) { assert.expect(7); this.data.partner.records[0].p = [2, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2557,25 +2554,25 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in readonly'); - testUtils.dom.click(form.$('.o_list_view tbody td:first()')); + await testUtils.dom.click(form.$('.o_list_view tbody td:first()')); assert.ok($('.modal .o_form_readonly').length, 'in readonly, clicking on a subrecord should open it in readonly in a dialog'); - testUtils.dom.click($('.modal .o_form_button_cancel')); + await testUtils.dom.click($('.modal .o_form_button_cancel')); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.ok(form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should be available in edit'); // edit existing subrecord - testUtils.dom.click(form.$('.o_list_view tbody td:first()')); + await testUtils.dom.click(form.$('.o_list_view tbody td:first()')); assert.strictEqual($('.modal').length, 0, 'in edit, clicking on a subrecord should not open a dialog'); assert.hasClass(form.$('.o_list_view tbody tr:first()'),'o_selected_row', 'first row should be in edition'); - testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name'); + await testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name'); - testUtils.dom.click(form.$('.o_list_view tbody tr:nth(1) td:first')); + await testUtils.dom.click(form.$('.o_list_view tbody tr:nth(1) td:first')); assert.doesNotHaveClass(form.$('.o_list_view tbody tr:first'), 'o_selected_row', 'first row should not be in edition anymore'); assert.strictEqual(form.$('.o_list_view tbody td:first').text(), 'new name', @@ -2586,10 +2583,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list (editable): edition, part 2', function (assert) { + QUnit.test('one2many list (editable): edition, part 2', async function (assert) { assert.expect(8); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2613,12 +2610,12 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item and enter a value - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'kartoffel'); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'kartoffel'); // click again 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.strictEqual(form.$('td:contains(kartoffel)').length, 1, "should have one td with the new value"); assert.containsOnce(form, '.o_selected_row > td input', @@ -2626,8 +2623,8 @@ QUnit.module('fields', {}, function () { assert.containsN(form, 'tr.o_data_row', 2, "should have 2 data rows"); // enter another value and save - testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'gemuse'); - testUtils.form.clickSave(form); + await testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'gemuse'); + await testUtils.form.clickSave(form); assert.containsN(form, 'tr.o_data_row', 2, "should have 2 data rows"); assert.strictEqual(form.$('td:contains(kartoffel)').length, 1, "should have one td with the new value"); @@ -2637,10 +2634,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list (editable): edition, part 3', function (assert) { + QUnit.test('one2many list (editable): edition, part 3', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2659,22 +2656,22 @@ QUnit.module('fields', {}, function () { // edit mode, then click on Add an item 2 times assert.containsOnce(form, 'tr.o_data_row', "should have 1 data rows"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, 'tr.o_data_row', 3, "should have 3 data rows"); // cancel the edition - testUtils.form.clickDiscard(form); - testUtils.dom.click($('.modal-footer button.btn-primary').first()); + await testUtils.form.clickDiscard(form); + await testUtils.dom.click($('.modal-footer button.btn-primary').first()); assert.containsOnce(form, 'tr.o_data_row', "should have 1 data rows"); form.destroy(); }); - QUnit.test('one2many list (editable): edition, part 4', function (assert) { + QUnit.test('one2many list (editable): edition, part 4', async function (assert) { assert.expect(3); var i = 0; @@ -2687,7 +2684,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2707,26 +2704,26 @@ QUnit.module('fields', {}, function () { // edit mode, then click on Add an item assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('textarea').val(), "", "field turtle_description should be empty"); // add a value in the turtle_trululu field to trigger an onchange - testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); - testUtils.fields.many2one.clickHighlightedItem('turtle_trululu'); + await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); + await testUtils.fields.many2one.clickHighlightedItem('turtle_trululu'); assert.strictEqual(form.$('textarea').val(), "Some Description", "field turtle_description should be set to the result of the onchange"); form.destroy(); }); - QUnit.test('one2many list (editable): discarding required empty data', function (assert) { + QUnit.test('one2many list (editable): discarding required empty data', async function (assert) { assert.expect(7); this.data.turtle.fields.turtle_foo.required = true; delete this.data.turtle.fields.turtle_foo.default; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2751,15 +2748,15 @@ QUnit.module('fields', {}, function () { // edit mode, then click on Add an item, then click elsewhere assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('label.o_form_label').first()); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('label.o_form_label').first()); assert.containsNone(form, 'tr.o_data_row', "should still have 0 data rows"); // click on Add an item again, then click on save - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickSave(form); assert.containsNone(form, 'tr.o_data_row', "should still have 0 data rows"); @@ -2767,11 +2764,11 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable one2many list, adding line when only one page', function (assert) { + QUnit.test('editable one2many list, adding line when only one page', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = [1, 2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2786,22 +2783,21 @@ QUnit.module('fields', {}, function () { }); // add a record, to reach the page size limit - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // the record currently being added should not count in the pager assert.isNotVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager')); form.destroy(); }); - QUnit.test('editable one2many list, adding line, then discarding', function (assert) { + QUnit.test('editable one2many list, adding line, then discarding', async function (assert) { assert.expect(2); this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' }); this.data.partner.records[0].turtles = [1, 2, 3, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2816,12 +2812,12 @@ QUnit.module('fields', {}, function () { }); // add a record, then discard - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.form.clickDiscard(form); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickDiscard(form); // confirm the discard operation - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.isVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager')); assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4', @@ -2830,14 +2826,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable one2many list, required field and pager', function (assert) { + QUnit.test('editable one2many list, required field and pager', async function (assert) { assert.expect(1); this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' }); this.data.turtle.fields.turtle_foo.required = true; this.data.partner.records[0].turtles = [1, 2, 3, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2852,24 +2848,24 @@ QUnit.module('fields', {}, function () { }); // add a (empty) record - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // go on next page. The new record is not valid and should be discarded - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); assert.containsOnce(form, 'tr.o_data_row'); form.destroy(); }); - QUnit.test('editable one2many list, required field, pager and confirm discard', function (assert) { + QUnit.test('editable one2many list, required field, pager and confirm discard', async function (assert) { assert.expect(3); this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' }); this.data.turtle.fields.turtle_foo.required = true; this.data.partner.records[0].turtles = [1, 2, 3, 4]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2885,19 +2881,19 @@ QUnit.module('fields', {}, function () { }); // add a record with a dirty state, but not valid - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('input[name="turtle_int"]'), 4321); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), 4321); // go to next page. The new record is not valid, but dirty. we should // see a confirm dialog - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4', "pager should still display the correct total"); // click on cancel - testUtils.dom.click($('.modal .modal-footer .btn-secondary')); + await testUtils.dom.click($('.modal .modal-footer .btn-secondary')); assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4', "pager should again display the correct total"); @@ -2906,12 +2902,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable one2many list, adding, discarding, and pager', function (assert) { + QUnit.test('editable one2many list, adding, discarding, and pager', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [1]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2926,18 +2922,18 @@ QUnit.module('fields', {}, function () { }); // add a 4 records record (to make the pager appear) - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // go on next page - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); // discard - testUtils.form.clickDiscard(form); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.form.clickDiscard(form); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.containsOnce(form, 'tr.o_data_row'); assert.isNotVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager')); @@ -2945,13 +2941,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('unselecting a line with missing required data', function (assert) { + QUnit.test('unselecting a line with missing required data', async function (assert) { assert.expect(5); this.data.turtle.fields.turtle_foo.required = true; delete this.data.turtle.fields.turtle_foo.default; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -2971,40 +2967,40 @@ QUnit.module('fields', {}, function () { // edit mode, then click on Add an item, then click elsewhere assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsOnce(form, 'tr.o_data_row', "should have 1 data rows"); // adding a value in the non required field, so it is dirty, but with // a missing required field - testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '12345'); + await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '12345'); // click elsewhere, - testUtils.dom.click(form.$('label.o_form_label')); + await testUtils.dom.click(form.$('label.o_form_label')); assert.strictEqual($('.modal').length, 1, 'a confirmation model should be opened'); // click on cancel, the line should still be selected - testUtils.dom.click($('.modal .modal-footer button.btn-secondary')); + await testUtils.dom.click($('.modal .modal-footer button.btn-secondary')); assert.containsOnce(form, 'tr.o_data_row.o_selected_row', "should still have 1 selected data row"); // click elsewhere, and click on ok (on the confirmation dialog) - testUtils.dom.click(form.$('label.o_form_label')); - testUtils.dom.click($('.modal .modal-footer button.btn-primary')); + await testUtils.dom.click(form.$('label.o_form_label')); + await testUtils.dom.click($('.modal .modal-footer button.btn-primary')); assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows (invalid line has been discarded"); form.destroy(); }); - QUnit.test('pressing enter in a o2m with a required empty field', function (assert) { + QUnit.test('pressing enter in a o2m with a required empty field', async function (assert) { assert.expect(4); this.data.turtle.fields.turtle_foo.required = true; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3025,19 +3021,16 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item, then click elsewhere - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - form.$('input[name="turtle_foo"]').trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'enter'); assert.hasClass(form.$('input[name="turtle_foo"]'),'o_field_invalid', "input should be marked invalid"); assert.verifySteps(['read', 'default_get']); form.destroy(); }); - QUnit.test('editing a o2m, with required field and onchange', function (assert) { + QUnit.test('editing a o2m, with required field and onchange', async function (assert) { assert.expect(12); this.data.turtle.fields.turtle_foo.required = true; @@ -3048,7 +3041,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3074,16 +3067,16 @@ QUnit.module('fields', {}, function () { // edit mode, then click on Add an item assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // input some text in required turtle_foo field - testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'aubergine'); + await testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'aubergine'); assert.strictEqual(form.$('input[name="turtle_int"]').val(), "9", "onchange should have been triggered"); // save and check everything is fine - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_data_row td:contains(aubergine)').length, 1, "should have one row with turtle_foo value"); assert.strictEqual(form.$('.o_data_row td:contains(9)').length, 1, @@ -3093,10 +3086,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable o2m, pressing ESC discard current changes', function (assert) { + QUnit.test('editable o2m, pressing ESC discard current changes', async function (assert) { assert.expect(5); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3114,24 +3107,24 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsOnce(form, 'tr.o_data_row', "there should be one data row"); - form.$('input[name="turtle_foo"]').trigger({ type: 'keydown', which: $.ui.keyCode.ESCAPE }); + await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'escape'); assert.containsNone(form, 'tr.o_data_row', "data row should have been discarded"); assert.verifySteps(['read', 'default_get']); form.destroy(); }); - QUnit.test('editable o2m with required field, pressing ESC discard current changes', function (assert) { + QUnit.test('editable o2m with required field, pressing ESC discard current changes', async function (assert) { assert.expect(5); this.data.turtle.fields.turtle_foo.required = true; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3149,22 +3142,22 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsOnce(form, 'tr.o_data_row', "there should be one data row"); - form.$('input[name="turtle_foo"]').trigger({ type: 'keydown', which: $.ui.keyCode.ESCAPE }); + await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'escape'); assert.containsNone(form, 'tr.o_data_row', "data row should have been discarded"); assert.verifySteps(['read', 'default_get']); form.destroy(); }); - QUnit.test('pressing escape in editable o2m list in dialog', function (assert) { + QUnit.test('pressing escape in editable o2m list in dialog', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3192,14 +3185,13 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_data_row.o_selected_row').length, 1, "there should be a row in edition in the dialog"); - // trigger keydown ESCAPE in the edited row - $('.modal .o_data_cell input').trigger({ type: 'keydown', which: $.ui.keyCode.ESCAPE }); + await testUtils.fields.triggerKeydown($('.modal .o_data_cell input'), 'escape'); assert.strictEqual($('.modal').length, 1, "dialog should still be open"); @@ -3209,7 +3201,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable o2m with onchange and required field: delete an invalid line', function (assert) { + QUnit.test('editable o2m with onchange and required field: delete an invalid line', async function (assert) { assert.expect(5); this.data.partner.onchanges = { @@ -3218,7 +3210,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles = [1]; this.data.turtle.records[0].product_id = 37; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3239,16 +3231,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_data_cell:first')); + await testUtils.dom.click(form.$('.o_data_cell:first')); form.$('.o_field_widget[name="product_id"] input').val('').trigger('keyup'); assert.verifySteps(['read', 'read'], 'no onchange should be done as line is invalid'); - testUtils.dom.click(form.$('.o_list_record_remove')); - assert.verifySteps(['read', 'read', 'onchange'], 'onchange should have been done'); + await testUtils.dom.click(form.$('.o_list_record_remove')); + assert.verifySteps(['onchange'], 'onchange should have been done'); form.destroy(); }); - QUnit.test('onchange in a one2many', function (assert) { + QUnit.test('onchange in a one2many', async function (assert) { assert.expect(1); this.data.partner.records.push({ @@ -3258,7 +3250,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[1].p = [3]; this.data.partner.onchanges = { p: true }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3272,7 +3264,7 @@ QUnit.module('fields', {}, function () { res_id: 2, mockRPC: function (route, args) { if (args.method === 'onchange') { - return $.when({ + return Promise.resolve({ value: { p: [ [5], // delete all @@ -3285,17 +3277,17 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_one2many tbody td').first()); - testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value"); - testUtils.form.clickSave(form); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_one2many tbody td').first()); + await testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value"); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'from onchange', "display name of first record in o2m list should be 'new value'"); form.destroy(); }); - QUnit.test('one2many, default_get and onchange (basic)', function (assert) { + QUnit.test('one2many, default_get and onchange (basic)', async function (assert) { assert.expect(1); this.data.partner.fields.p.default = [ @@ -3303,7 +3295,7 @@ QUnit.module('fields', {}, function () { ]; this.data.partner.onchanges = { p: true }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3316,7 +3308,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'onchange') { - return $.when({ + return Promise.resolve({ value: { p: [ [5], // delete all @@ -3334,14 +3326,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many and default_get (with date)', function (assert) { + QUnit.test('one2many and default_get (with date)', async function (assert) { assert.expect(1); this.data.partner.fields.p.default = [ [0, false, { date: '2017-10-08' }], ]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3360,14 +3352,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many and onchange (with integer)', function (assert) { + QUnit.test('one2many and onchange (with integer)', async function (assert) { assert.expect(4); this.data.turtle.onchanges = { - turtle_int: function (obj) { } + turtle_int: function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3384,10 +3376,10 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('td:contains(9)')); - testUtils.fields.editInput(form.$('td input[name="turtle_int"]'), "3"); + await testUtils.dom.click(form.$('td:contains(9)')); + await testUtils.fields.editInput(form.$('td input[name="turtle_int"]'), "3"); // the 'change' event is triggered on the input when we focus somewhere // else, for example by clicking in the body. However, if we try to @@ -3399,15 +3391,15 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many and onchange (with date)', function (assert) { + QUnit.test('one2many and onchange (with date)', async function (assert) { assert.expect(7); this.data.partner.onchanges = { - date: function (obj) { } + date: function () { } }; this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3424,23 +3416,28 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.form.clickEdit(form); - - testUtils.dom.click(form.$('td:contains(01/25/2017)')); - testUtils.dom.click(form.$('.o_datepicker_input')); - testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first()); - testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)')); - testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)')); - testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1)); - testUtils.dom.click($('.day:contains(22)')); + await testUtils.form.clickEdit(form); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('td:contains(01/25/2017)')); + await testUtils.dom.click(form.$('.o_datepicker_input')); + await testUtils.nextTick(); + await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first()); + await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)')); + await testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)')); + await testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1)); + await testUtils.dom.click($('.day:contains(22)')); + // trigger the blur of input before the click on Save, to closely mock what actually + // happens when we really click on Save + // this is required to close the datepicker before removing the input from the DOM + // (because of the re-rendering in readonly), otherwise tempusdominus crashes + await testUtils.dom.triggerEvents(form.$('.o_datepicker_input'), 'blur'); + await testUtils.form.clickSave(form); assert.verifySteps(['read', 'read', 'onchange', 'write', 'read', 'read']); form.destroy(); }); - QUnit.test('one2many and onchange (with command DELETE_ALL)', function (assert) { + QUnit.test('one2many and onchange (with command DELETE_ALL)', async function (assert) { assert.expect(5); this.data.partner.onchanges = { @@ -3451,7 +3448,7 @@ QUnit.module('fields', {}, function () { }; this.data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3482,34 +3479,34 @@ QUnit.module('fields', {}, function () { "o2m should contain one row"); // empty o2m by triggering the onchange - testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange'); assert.containsNone(form, '.o_data_row', "rows of the o2m should have been deleted"); // add two new subrecords - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'x'); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'y'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'x'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'y'); assert.containsN(form, '.o_data_row', 2, "o2m should contain two rows"); // empty o2m by triggering the onchange - testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange again'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange again'); assert.containsNone(form, '.o_data_row', "rows of the o2m should have been deleted"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'z'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'z'); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many and onchange only write modified field', function (assert) { + QUnit.test('one2many and onchange only write modified field', async function (assert) { assert.expect(2); this.data.partner.onchanges = { @@ -3532,7 +3529,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles = [3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3567,14 +3564,14 @@ QUnit.module('fields', {}, function () { assert.containsOnce(form, '.o_data_row', "o2m should contain one row"); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first')); - testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp'); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first')); + await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp'); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many with CREATE onchanges correctly refreshed', function (assert) { + QUnit.test('one2many with CREATE onchanges correctly refreshed', async function (assert) { assert.expect(5); var delta = 0; @@ -3626,7 +3623,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3648,27 +3645,27 @@ QUnit.module('fields', {}, function () { assert.containsNone(form, '.o_data_row', "o2m shouldn't contain any row"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // trigger the first onchange deactiveOnchange = false; - testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '10'); + await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '10'); // put the list back in non edit mode - testUtils.dom.click(form.$('input[name="foo"]')); + await testUtils.dom.click(form.$('input[name="foo"]')); assert.strictEqual(form.$('.o_data_row').text(), "first10second-10", "should correctly refresh the records"); // trigger the second onchange - testUtils.dom.click(form.$('.o_field_x2many_list tbody tr:first td:first')); - testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '20'); + await testUtils.dom.click(form.$('.o_field_x2many_list tbody tr:first td:first')); + await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '20'); - testUtils.dom.click(form.$('input[name="foo"]')); + await testUtils.dom.click(form.$('input[name="foo"]')); assert.strictEqual(form.$('.o_data_row').text(), "first20second-20", "should correctly refresh the records"); assert.containsN(form, '.o_field_widget', delta, "all (non visible) field widgets should have been destroyed"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_data_row').text(), "first20second-20", "should correctly refresh the records after save"); @@ -3677,7 +3674,7 @@ QUnit.module('fields', {}, function () { testUtils.mock.unpatch(AbstractField); }); - QUnit.test('editable one2many with sub widgets are rendered in readonly', function (assert) { + QUnit.test('editable one2many with sub widgets are rendered in readonly', async function (assert) { assert.expect(2); var editableWidgets = 0; @@ -3690,7 +3687,7 @@ QUnit.module('fields', {}, function () { }, }); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3710,7 +3707,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(editableWidgets, 1, "o2m is only widget in edit mode"); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.strictEqual(editableWidgets, 3, "3 widgets currently in edit mode"); @@ -3719,7 +3716,7 @@ QUnit.module('fields', {}, function () { testUtils.mock.unpatch(AbstractField); }); - QUnit.test('one2many editable list with onchange keeps the order', function (assert) { + QUnit.test('one2many editable list with onchange keeps the order', async function (assert) { assert.expect(2); this.data.partner.records[0].p = [1, 2, 4]; @@ -3727,7 +3724,7 @@ QUnit.module('fields', {}, function () { p: function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3747,9 +3744,9 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_cell').text(), 'first recordsecond recordaaa', "records should be display in the correct order"); - testUtils.dom.click(form.$('.o_data_row:first .o_data_cell')); - testUtils.fields.editInput(form.$('.o_selected_row .o_field_widget[name=display_name]'), 'new'); - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$('.o_data_row:first .o_data_cell')); + await testUtils.fields.editInput(form.$('.o_selected_row .o_field_widget[name=display_name]'), 'new'); + await testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_data_cell').text(), 'newsecond recordaaa', "records should be display in the correct order"); @@ -3757,14 +3754,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list (editable): readonly domain is evaluated', function (assert) { + QUnit.test('one2many list (editable): readonly domain is evaluated', async function (assert) { assert.expect(2); this.data.partner.records[0].p = [2, 4]; this.data.partner.records[1].product_id = false; this.data.partner.records[2].product_id = 37; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3779,7 +3776,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.hasClass(form.$('.o_list_view tbody tr:eq(0) td:first'),'o_readonly_modifier', "first record should have display_name in readonly mode"); @@ -3789,12 +3786,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('pager of one2many field in new record', function (assert) { + QUnit.test('pager of one2many field in new record', async function (assert) { assert.expect(3); this.data.partner.records[0].p = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3811,7 +3808,7 @@ QUnit.module('fields', {}, function () { 'o2m pager should be hidden'); // click to create a subrecord - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.containsOnce(form, 'tr.o_data_row'); assert.ok(!form.$('.o_x2m_control_panel .o_cp_pager div').is(':visible'), @@ -3819,7 +3816,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list with a many2one', function (assert) { + QUnit.test('one2many list with a many2one', async function (assert) { assert.expect(5); this.data.partner.records[0].p = [2]; @@ -3833,7 +3830,7 @@ QUnit.module('fields', {}, function () { // }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3863,14 +3860,14 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('tbody td:contains(xpad)').length, 0, "should not display 'xpad' anywhere"); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); - testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); testUtils.fields.many2one.clickItem('product_id', 'xpad'); - testUtils.dom.click($('.modal .modal-footer button:eq(0)')); + await testUtils.dom.click($('.modal .modal-footer button:eq(0)')); assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1, "should display 'xpad' on a td"); @@ -3879,14 +3876,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list with inline form view', function (assert) { + QUnit.test('one2many list with inline form view', async function (assert) { assert.expect(5); this.data.partner.records[0].p = []; - var rpcCount = 0; - - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -3907,7 +3902,6 @@ QUnit.module('fields', {}, function () { '</form>', res_id: 1, mockRPC: function (route, args) { - rpcCount++; if (args.method === 'write') { assert.deepEqual(args.args[1].p, [[0, args.args[1].p[0][1], { foo: false, int_field: 123, product_id: 41, @@ -3917,63 +3911,63 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); // write in the many2one field, value = 37 (xphone) - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickHighlightedItem('product_id'); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickHighlightedItem('product_id'); // write in the integer field - testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '123'); + await testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '123'); // save and close - testUtils.dom.click($('.modal .modal-footer button:eq(0)')); + await testUtils.dom.click($('.modal .modal-footer button:eq(0)')); assert.strictEqual(form.$('tbody td:contains(xphone)').length, 1, "should display 'xphone' in a td"); // reopen the record in form view - testUtils.dom.click(form.$('tbody td:contains(xphone)')); + await testUtils.dom.click(form.$('tbody td:contains(xphone)')); assert.strictEqual($('.modal .modal-body input').val(), "xphone", "should display 'xphone' in an input"); - testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '456'); + await testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '456'); // discard - testUtils.dom.click($('.modal .modal-footer span:contains(Discard)')); + await testUtils.dom.click($('.modal .modal-footer span:contains(Discard)')); // reopen the record in form view - testUtils.dom.click(form.$('tbody td:contains(xphone)')); + await testUtils.dom.click(form.$('tbody td:contains(xphone)')); assert.strictEqual($('.modal .modal-body input.o_field_widget').val(), "123", "should display 123 (previous change has been discarded)"); // write in the many2one field, value = 41 (xpad) - testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); testUtils.fields.many2one.clickItem('product_id', 'xpad'); // save and close - testUtils.dom.click($('.modal .modal-footer button:eq(0)')); + await testUtils.dom.click($('.modal .modal-footer button:eq(0)')); assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1, "should display 'xpad' in a td"); // save the record - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many list with inline form view with context with parent key', function (assert) { + QUnit.test('one2many list with inline form view with context with parent key', async function (assert) { assert.expect(2); this.data.partner.records[0].p = [2]; this.data.partner.records[0].product_id = 41; this.data.partner.records[1].product_id = 37; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4001,23 +3995,23 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // open a modal - testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)')); + await testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)')); // write in the many2one field - testUtils.dom.click($('.modal .o_field_many2one input')); + await testUtils.dom.click($('.modal .o_field_many2one input')); form.destroy(); }); - QUnit.test('value of invisible x2many fields is correctly evaluated in context', function (assert) { + QUnit.test('value of invisible x2many fields is correctly evaluated in context', async function (assert) { assert.expect(1); this.data.partner.records[0].timmy = [12]; this.data.partner.records[0].p = [2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4040,19 +4034,19 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_widget[name=product_id] input')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_widget[name=product_id] input')); form.destroy(); }); - QUnit.test('one2many list, editable, with many2one and with context with parent key', function (assert) { + QUnit.test('one2many list, editable, with many2one and with context with parent key', async function (assert) { assert.expect(1); this.data.partner.records[0].p = [2]; this.data.partner.records[1].product_id = 37; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4074,23 +4068,23 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)')); + await testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)')); // trigger a name search - testUtils.dom.click(form.$('table td input')); + await testUtils.dom.click(form.$('table td input')); form.destroy(); }); - QUnit.test('one2many list, editable, with a date in the context', function (assert) { + QUnit.test('one2many list, editable, with a date in the context', async function (assert) { assert.expect(1); this.data.partner.records[0].p = [2]; this.data.partner.records[1].product_id = 37; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4114,18 +4108,18 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.destroy(); }); - QUnit.test('one2many field with context', function (assert) { + QUnit.test('one2many field with context', async function (assert) { assert.expect(2); var counter = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4152,19 +4146,19 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'hammer'); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'hammer'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.destroy(); }); - QUnit.test('one2many list edition, some basic functionality', function (assert) { + QUnit.test('one2many list edition, some basic functionality', async function (assert) { assert.expect(3); this.data.partner.fields.foo.default = false; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4177,30 +4171,30 @@ QUnit.module('fields', {}, function () { '</form>', res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.containsOnce(form, 'td input.o_field_widget', "should have created a row in edit mode"); - testUtils.fields.editInput(form.$('td input.o_field_widget'), 'a'); + await testUtils.fields.editInput(form.$('td input.o_field_widget'), 'a'); assert.containsOnce(form, 'td input.o_field_widget', "should not have unselected the row after edition"); - testUtils.fields.editInput(form.$('td input.o_field_widget'), 'abc'); - testUtils.form.clickSave(form); + await testUtils.fields.editInput(form.$('td input.o_field_widget'), 'abc'); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('td:contains(abc)').length, 1, "should have a row with the correct value"); form.destroy(); }); - QUnit.test('one2many list, the context is properly evaluated and sent', function (assert) { + QUnit.test('one2many list, the context is properly evaluated and sent', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4223,15 +4217,15 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); form.destroy(); }); - QUnit.test('one2many with many2many widget: create', function (assert) { + QUnit.test('one2many with many2many widget: create', async function (assert) { assert.expect(10); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4271,28 +4265,28 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_data_row').length, 2, "sould have 2 records in the select view (the last one is not displayed because it is already selected)"); - testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input')); - testUtils.dom.click($('.modal .o_select_button')); - testUtils.dom.click($('.o_form_button_save')); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input')); + await testUtils.dom.click($('.modal .o_select_button')); + await testUtils.dom.click($('.o_form_button_save')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_data_row').length, 1, "sould have 1 record in the select view"); - testUtils.dom.click($('.modal-footer button:eq(1)')); - testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_foo"]'), 'tototo'); - testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_int"]'), 50); - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickHighlightedItem('product_id'); + await testUtils.dom.click($('.modal-footer button:eq(1)')); + await testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_foo"]'), 'tototo'); + await testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_int"]'), 50); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickHighlightedItem('product_id'); - testUtils.dom.click($('.modal-footer button:contains(&):first')); + await testUtils.dom.click($('.modal-footer button:contains(&):first')); assert.strictEqual($('.modal').length, 0, "sould close the modals"); @@ -4301,15 +4295,15 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_row').text(), "blip1.59yop1.50tototo1.550xphone", "should display the record values in one2many list"); - testUtils.dom.click($('.o_form_button_save')); + await testUtils.dom.click($('.o_form_button_save')); form.destroy(); }); - QUnit.test('one2many with many2many widget: edition', function (assert) { + QUnit.test('one2many with many2many widget: edition', async function (assert) { assert.expect(7); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4351,44 +4345,44 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: one2many turtle field', "modal should use the python field string as title"); - testUtils.dom.click($('.modal .o_form_button_cancel')); - testUtils.form.clickEdit(form); + await testUtils.dom.click($('.modal .o_form_button_cancel')); + await testUtils.form.clickEdit(form); // edit the first one2many record - testUtils.dom.click(form.$('.o_data_row:first')); - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickHighlightedItem('product_id'); - testUtils.dom.click($('.modal-footer button:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickHighlightedItem('product_id'); + await testUtils.dom.click($('.modal-footer button:first')); - testUtils.dom.click($('.o_form_button_save')); + await testUtils.dom.click($('.o_form_button_save')); // add a one2many record - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input')); - testUtils.dom.click($('.modal .o_select_button')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input')); + await testUtils.dom.click($('.modal .o_select_button')); // edit the second one2many record - testUtils.dom.click(form.$('.o_data_row:eq(1)')); - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickHighlightedItem('product_id'); - testUtils.dom.click($('.modal-footer button:first')); + await testUtils.dom.click(form.$('.o_data_row:eq(1)')); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickHighlightedItem('product_id'); + await testUtils.dom.click($('.modal-footer button:first')); - testUtils.dom.click($('.o_form_button_save')); + await testUtils.dom.click($('.o_form_button_save')); form.destroy(); }); - QUnit.test('new record, the context is properly evaluated and sent', function (assert) { + QUnit.test('new record, the context is properly evaluated and sent', async function (assert) { assert.expect(2); this.data.partner.fields.int_field.default = 17; var n = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4413,15 +4407,15 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); form.destroy(); }); - QUnit.test('parent data is properly sent on an onchange rpc', function (assert) { + QUnit.test('parent data is properly sent on an onchange rpc', async function (assert) { assert.expect(1); this.data.partner.onchanges = { bar: function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4444,16 +4438,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); form.destroy(); }); - QUnit.test('parent data is properly sent on an onchange rpc, new record', function (assert) { + QUnit.test('parent data is properly sent on an onchange rpc, new record', async function (assert) { assert.expect(6); this.data.turtle.onchanges = { turtle_bar: function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4475,12 +4469,12 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.verifySteps(['default_get', 'onchange', 'default_get', 'onchange']); form.destroy(); }); - QUnit.test('id in one2many obtained in onchange is properly set', function (assert) { + QUnit.test('id in one2many obtained in onchange is properly set', async function (assert) { assert.expect(1); this.data.partner.onchanges.turtles = function (obj) { @@ -4489,7 +4483,7 @@ QUnit.module('fields', {}, function () { [1, 3, { turtle_foo: "kawa" }] ]; }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4508,10 +4502,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('id field in one2many in a new record', function (assert) { + QUnit.test('id field in one2many in a new record', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4533,19 +4527,19 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.dom.click(form.$('td.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('td input[name="turtle_foo"]'), 'cat'); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('td.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('td input[name="turtle_foo"]'), 'cat'); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('sub form view with a required field', function (assert) { + QUnit.test('sub form view with a required field', async function (assert) { assert.expect(2); this.data.partner.fields.foo.required = true; this.data.partner.fields.foo.default = null; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4562,9 +4556,9 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); - testUtils.dom.click($('.modal-footer button.btn-primary').first()); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal-footer button.btn-primary').first()); assert.strictEqual($('.modal').length, 1, "should still have an open modal"); assert.strictEqual($('.modal tbody label.o_field_invalid').length, 1, @@ -4572,12 +4566,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list with action button', function (assert) { + QUnit.test('one2many list with action button', 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, @@ -4605,17 +4599,17 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_list_button button')); + await testUtils.dom.click(form.$('.o_list_button button')); form.destroy(); }); - QUnit.test('one2many kanban with action button', function (assert) { + QUnit.test('one2many kanban with action button', 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, @@ -4649,12 +4643,12 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.oe_kanban_action_button')); + await testUtils.dom.click(form.$('.oe_kanban_action_button')); form.destroy(); }); - QUnit.test('one2many kanban with edit type action and domain widget (widget using SpecialData)', function (assert) { + QUnit.test('one2many kanban with edit type action and domain widget (widget using SpecialData)', async function (assert) { assert.expect(1); this.data.turtle.fields.model_name = { string: "Domain Condition Model", type: "char" }; @@ -4664,7 +4658,7 @@ QUnit.module('fields', {}, function () { record.condition = '[]'; }); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4694,12 +4688,12 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.dom.click(form.$('.oe_kanban_action:eq(0)')); + await testUtils.dom.click(form.$('.oe_kanban_action:eq(0)')); assert.strictEqual($('.o_domain_selector').length, 1, "should add domain selector widget"); form.destroy(); }); - QUnit.test('one2many list with onchange and domain widget (widget using SpecialData)', function (assert) { + QUnit.test('one2many list with onchange and domain widget (widget using SpecialData)', async function (assert) { assert.expect(3); this.data.turtle.fields.model_name = { string: "Domain Condition Model", type: "char" }; @@ -4729,7 +4723,7 @@ QUnit.module('fields', {}, function () { }, }; var nbFetchSpecialDomain = 0; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4762,28 +4756,28 @@ QUnit.module('fields', {}, function () { } }); - testUtils.dom.click(form.$('.o_field_one2many .o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_one2many .o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 1, "form view dialog should be opened"); - testUtils.fields.editInput($('.modal-body input[name="model_name"]'), 'partner'); - testUtils.dom.click($('.modal-footer button:first')); + await testUtils.fields.editInput($('.modal-body input[name="model_name"]'), 'partner'); + await testUtils.dom.click($('.modal-footer button:first')); assert.strictEqual(form.$('.o_field_one2many tbody tr:first').text(), "coucouhas changed[]", "the onchange should create one new record and remove the existing"); - testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(0) td:first')); + await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(0) td:first')); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(nbFetchSpecialDomain, 1, "should only fetch special domain once"); form.destroy(); }); - QUnit.test('one2many without inline tree arch', function (assert) { + QUnit.test('one2many without inline tree arch', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4809,13 +4803,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('many2one and many2many in one2many', function (assert) { + QUnit.test('many2one and many2many in one2many', async function (assert) { assert.expect(11); this.data.turtle.records[1].product_id = 37; this.data.partner.records[0].turtles = [2, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4862,46 +4856,46 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_row:first td:nth(2) .badge:first span').text(), 'second record', "m2m values should have been correctly fetched"); - testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .o_field_widget').text(), "xphone", 'should display the form view dialog with the many2one value'); - testUtils.dom.click($('.modal-footer button')); + await testUtils.dom.click($('.modal-footer button')); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // edit the m2m of first row - testUtils.dom.click(form.$('.o_list_view tbody td:first()')); + await testUtils.dom.click(form.$('.o_list_view tbody td:first()')); // remove a tag - testUtils.dom.click(form.$('.o_field_many2manytags .badge:contains(aaa) .o_delete')); + await testUtils.dom.click(form.$('.o_field_many2manytags .badge:contains(aaa) .o_delete')); assert.strictEqual(form.$('.o_selected_row .o_field_many2manytags .o_badge_text:contains(aaa)').length, 0, "tag should have been correctly removed"); // add a tag - testUtils.fields.many2one.clickOpenDropdown('partner_ids'); - testUtils.fields.many2one.clickHighlightedItem('partner_ids'); + await testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + await testUtils.fields.many2one.clickHighlightedItem('partner_ids'); assert.strictEqual(form.$('.o_selected_row .o_field_many2manytags .o_badge_text:contains(first record)').length, 1, "tag should have been correctly added"); // edit the m2o of first row - testUtils.fields.many2one.clickOpenDropdown('product_id'); - testUtils.fields.many2one.clickItem('product_id', 'xpad'); + await testUtils.fields.many2one.clickOpenDropdown('product_id'); + await testUtils.fields.many2one.clickItem('product_id', 'xpad'); assert.strictEqual(form.$('.o_selected_row .o_field_many2one:first input').val(), 'xpad', "m2o value should have been updated"); // save (should correctly generate the commands) - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('many2manytag in one2many, onchange, some modifiers, and more than one page', function (assert) { + QUnit.test('many2manytag in one2many, onchange, some modifiers, and more than one page', async function (assert) { assert.expect(9); this.data.partner.records[0].turtles = [1, 2, 3]; this.data.partner.onchanges.turtles = function () { }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -4922,8 +4916,8 @@ QUnit.module('fields', {}, function () { }); assert.containsN(form, '.o_data_row', 2, 'there should be only 2 rows displayed'); - testUtils.dom.clickFirst(form.$('.o_list_record_remove')); - testUtils.dom.clickFirst(form.$('.o_list_record_remove')); + await testUtils.dom.clickFirst(form.$('.o_list_record_remove')); + await testUtils.dom.clickFirst(form.$('.o_list_record_remove')); assert.containsOnce(form, '.o_data_row', 'there should be just one remaining row'); @@ -4940,7 +4934,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange many2many in one2many list editable', function (assert) { + QUnit.test('onchange many2many in one2many list editable', async function (assert) { assert.expect(14); this.data.product.records.push({ @@ -4988,7 +4982,7 @@ QUnit.module('fields', {}, function () { turtles: partnerOnchange, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5007,11 +5001,11 @@ QUnit.module('fields', {}, function () { }); // add new line (first, xpad) - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first'); - testUtils.dom.click(form.$('div[name="product_id"] input')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first'); + await testUtils.dom.click(form.$('div[name="product_id"] input')); // the onchange won't be generated - testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter')); + await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter')); assert.containsOnce(form, '.o_field_many2manytags.o_input', 'should display the line in editable mode'); @@ -5020,7 +5014,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_field_many2manytags.o_input .o_badge_text').text(), "first record", 'should display the tag from the onchange'); - testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]')); + await testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]')); assert.strictEqual(form.$('.o_data_cell.o_required_modifier').text(), "xpad", 'should display the product xpad'); @@ -5028,7 +5022,7 @@ QUnit.module('fields', {}, function () { 'should display the tag in readonly'); // enable the many2many onchange and generate it - testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); + await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); assert.strictEqual(form.$('.o_data_cell.o_required_modifier').text(), "xenomorphexphone", 'should display the product xphone and xenomorphe'); @@ -5036,21 +5030,21 @@ QUnit.module('fields', {}, function () { 'should display the name, one2many and many2many value'); // disable the many2many onchange - testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '0'); + await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '0'); // remove and start over - testUtils.dom.click(form.$('.o_list_record_remove:first button')); - testUtils.dom.click(form.$('.o_list_record_remove:first button')); + await testUtils.dom.click(form.$('.o_list_record_remove:first button')); + await testUtils.dom.click(form.$('.o_list_record_remove:first button')); // enable the many2many onchange - testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); + await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); // add new line (first, xenomorphe) - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first'); - testUtils.dom.click(form.$('div[name="product_id"] input')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first'); + await testUtils.dom.click(form.$('div[name="product_id"] input')); // generate the onchange - testUtils.dom.click($('li.ui-menu-item a:contains(xenomorphe)').trigger('mouseenter')); + await testUtils.dom.click($('li.ui-menu-item a:contains(xenomorphe)').trigger('mouseenter')); assert.containsOnce(form, '.o_field_many2manytags.o_input', 'should display the line in editable mode'); @@ -5060,19 +5054,19 @@ QUnit.module('fields', {}, function () { 'should display the tag from the onchange'); // put list in readonly mode - testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]')); + await testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]')); assert.strictEqual(form.$('.o_data_cell.o_required_modifier').text(), "xenomorphexphone", 'should display the product xphone and xenomorphe'); assert.strictEqual(form.$('.o_field_many2manytags:not(.o_input) .o_badge_text').text(), "second recordfirst record", 'should display the tag in readonly (first record and second record)'); - testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); + await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); assert.strictEqual(form.$('.o_data_row').text().replace(/\s+/g, ' '), "firstxenomorphe second record new linexphone first record ", 'should display the name, one2many and many2many value'); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_data_row').text().replace(/\s+/g, ' '), "firstxenomorphe second record new linexphone first record ", 'should display the name, one2many and many2many value after save'); @@ -5080,14 +5074,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('load view for x2many in one2many', function (assert) { + QUnit.test('load view for x2many in one2many', async function (assert) { assert.expect(2); this.data.turtle.records[1].product_id = 37; this.data.partner.records[0].turtles = [2, 3]; this.data.partner.records[2].turtles = [1, 3]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5116,7 +5110,7 @@ QUnit.module('fields', {}, function () { assert.containsN(form, '.o_data_row', 2, 'should display the 2 turtles'); - testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .o_field_widget[name="partner_ids"] .o_list_view').length, 1, 'should display many2many list view in the modal'); @@ -5124,12 +5118,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many (who contains a one2many) with tree view and without form view', function (assert) { + QUnit.test('one2many (who contains a one2many) with tree view and without form view', async function (assert) { assert.expect(1); // avoid error in _postprocess - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5148,7 +5142,7 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .o_field_widget[name="turtle_foo"]').text(), 'blip', 'should open the modal and display the form field'); @@ -5156,7 +5150,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with x2many in form view (but not in list view)', function (assert) { + QUnit.test('one2many with x2many in form view (but not in list view)', async function (assert) { assert.expect(1); // avoid error when saving the edited related record (because the @@ -5165,7 +5159,7 @@ QUnit.module('fields', {}, function () { this.data.turtle.fields.o2m = { string: "o2m", type: "one2many", relation: 'user' }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5197,26 +5191,26 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_data_row:first')); // edit first record + await testUtils.dom.click(form.$('.o_data_row:first')); // edit first record - testUtils.fields.many2one.clickOpenDropdown('partner_ids'); - testUtils.fields.many2one.clickHighlightedItem('partner_ids'); + await testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + await testUtils.fields.many2one.clickHighlightedItem('partner_ids'); // add a many2many tag and save - testUtils.dom.click($('.modal .o_field_many2manytags input')); - testUtils.fields.editInput($('.modal .o_field_many2manytags input'), 'test'); - testUtils.dom.click($('.modal .modal-footer .btn-primary')); // save + await testUtils.dom.click($('.modal .o_field_many2manytags input')); + await testUtils.fields.editInput($('.modal .o_field_many2manytags input'), 'test'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); // save - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('many2many list in a one2many opened by a many2one', function (assert) { + QUnit.test('many2many list in a one2many opened by a many2one', 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, @@ -5243,7 +5237,7 @@ QUnit.module('fields', {}, function () { }, mockRPC: function (route, args) { if (route === '/web/dataset/call_kw/partner/get_formview_id') { - return $.when(false); + return Promise.resolve(false); } if (args.method === 'write') { assert.deepEqual(args.args[1].timmy, [[6, false, [12]]], @@ -5254,27 +5248,27 @@ QUnit.module('fields', {}, function () { }); // edit the first partner in the one2many partner 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')); // open form view for many2one - testUtils.dom.click(form.$('.o_external_button')); + await testUtils.dom.click(form.$('.o_external_button')); // click on add, to add a new partner in the m2m - testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); // select the partner_type 'gold' (this closes the 2nd modal) - testUtils.dom.click($('.modal td:contains(gold)')); + await testUtils.dom.click($('.modal td:contains(gold)')); // confirm the changes in the modal - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('nested x2many default values', function (assert) { + QUnit.test('nested x2many default values', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5287,7 +5281,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.model === 'partner' && args.method === 'default_get') { - return $.when({ + return Promise.resolve({ turtles: [ [0, 0, { partner_ids: [[6, 0, [4]]] }], [0, 0, { partner_ids: [[6, 0, [1]]] }], @@ -5308,12 +5302,12 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many (who contains display_name) with tree view and without form view', function (assert) { + QUnit.test('one2many (who contains display_name) with tree view and without form view', async function (assert) { assert.expect(1); // avoid error in _fetchX2Manys - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5332,7 +5326,7 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_data_row:first')); + await testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .o_field_widget[name="turtle_foo"]').text(), 'blip', 'should open the modal and display the form field'); @@ -5340,10 +5334,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many field with virtual ids', function (assert) { + QUnit.test('one2many field with virtual ids', async function (assert) { assert.expect(11); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5387,13 +5381,13 @@ QUnit.module('fields', {}, function () { "should not have kanban records yet"); // // switch to edit mode and create a new kanban record - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_widget .o-kanban-button-new')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_widget .o-kanban-button-new')); // save & close the modal assert.strictEqual($('.modal-content input.o_field_widget').val(), 'My little Foo Value', "should already have the default value for field foo"); - testUtils.dom.click($('.modal-content .btn-primary').first()); + await testUtils.dom.click($('.modal-content .btn-primary').first()); assert.containsOnce(form, '.o_field_widget .o_kanban_view', "should have one inner kanban view for the one2many field"); @@ -5405,7 +5399,7 @@ QUnit.module('fields', {}, function () { 'My little Foo Value', "should have a value for the foo field"); // save the view to force a create of the new record in the one2many - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.containsOnce(form, '.o_field_widget .o_kanban_view', "should have one inner kanban view for the one2many field"); assert.strictEqual(form.$('.o_field_widget .o_kanban_view .o_kanban_record:not(.o_kanban_ghost)').length, 1, @@ -5418,10 +5412,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('focusing fields in one2many list', function (assert) { + QUnit.test('focusing fields in one2many list', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5438,23 +5432,23 @@ QUnit.module('fields', {}, function () { '</form>', res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_data_row:first td:first')); + await testUtils.dom.click(form.$('.o_data_row:first td:first')); assert.strictEqual(form.$('input[name="turtle_foo"]')[0], document.activeElement, "turtle foo field should have focus"); - form.$('input[name="turtle_foo"]').trigger({ type: 'keydown', which: $.ui.keyCode.TAB }); + await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'tab'); assert.strictEqual(form.$('input[name="turtle_int"]')[0], document.activeElement, "turtle int field should have focus"); form.destroy(); }); - QUnit.test('one2many list editable = top', function (assert) { + QUnit.test('one2many list editable = top', async function (assert) { assert.expect(6); this.data.turtle.fields.turtle_foo.default = "default foo turtle"; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5479,12 +5473,12 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsOnce(form, '.o_data_row', "should start with one data row"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, '.o_data_row', 2, "should have 2 data rows"); @@ -5493,15 +5487,15 @@ QUnit.module('fields', {}, function () { assert.hasClass(form.$('tr.o_data_row:first'),'o_selected_row', "first row should be selected"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many list editable = bottom', function (assert) { + QUnit.test('one2many list editable = bottom', async function (assert) { assert.expect(6); this.data.turtle.fields.turtle_foo.default = "default foo turtle"; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5526,12 +5520,12 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.containsOnce(form, '.o_data_row', "should start with one data row"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, '.o_data_row', 2, "should have 2 data rows"); @@ -5540,14 +5534,14 @@ QUnit.module('fields', {}, function () { assert.hasClass(form.$('tr.o_data_row:eq(1)'),'o_selected_row', "second row should be selected"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('x2many fields use their "mode" attribute', function (assert) { + QUnit.test('x2many fields use their "mode" attribute', async function (assert) { assert.expect(1); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5578,8 +5572,8 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list editable, no onchange when required field is not set', function (assert) { - assert.expect(7); + QUnit.test('one2many list editable, no onchange when required field is not set', async function (assert) { + assert.expect(8); this.data.turtle.fields.turtle_foo.required = true; this.data.partner.onchanges = { @@ -5590,7 +5584,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].int_field = 0; this.data.partner.records[0].turtles = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5609,28 +5603,29 @@ QUnit.module('fields', {}, function () { }, res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0", "int_field should start with value 0"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0", "int_field should still be 0 (no onchange should have been done yet"); assert.verifySteps(['read', 'default_get'], "no onchange should have been applied"); - testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text"); + await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text"); + assert.verifySteps(['onchange']); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1", "int_field should now be 1 (the onchange should have been done"); form.destroy(); }); - QUnit.test('one2many list editable: trigger onchange when row is valid', function (assert) { + QUnit.test('one2many list editable: trigger onchange when row is valid', async function (assert) { // should omit require fields that aren't in the view as they (obviously) // have no value, when checking the validity of required fields // shouldn't consider numerical fields with value 0 as unset - assert.expect(12); + assert.expect(13); this.data.turtle.fields.turtle_foo.required = true; this.data.turtle.fields.turtle_qux.required = true; // required field not in the view @@ -5647,7 +5642,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].int_field = 0; this.data.partner.records[0].turtles = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5670,33 +5665,34 @@ QUnit.module('fields', {}, function () { }, res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0", "int_field should start with value 0"); // add a new row (which is invalid at first) - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0", "int_field should still be 0 (no onchange should have been done yet)"); assert.verifySteps(['load_views', 'read', 'default_get'], "no onchange should have been applied"); // fill turtle_foo field - testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text"); + await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text"); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0", "int_field should still be 0 (no onchange should have been done yet)"); - assert.verifySteps(['load_views', 'read', 'default_get'], "no onchange should have been applied"); + assert.verifySteps([], "no onchange should have been applied"); // fill partner_ids field with a tag (all required fields will then be set) - testUtils.fields.many2one.clickOpenDropdown('partner_ids'); - testUtils.fields.many2one.clickHighlightedItem('partner_ids'); + await testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + await testUtils.fields.many2one.clickHighlightedItem('partner_ids'); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1", "int_field should now be 1 (the onchange should have been done"); + assert.verifySteps(['name_search', 'read', 'onchange']); form.destroy(); }); - QUnit.test('one2many list editable: \'required\' modifiers is properly working', function (assert) { + QUnit.test('one2many list editable: \'required\' modifiers is properly working', async function (assert) { assert.expect(3); this.data.partner.onchanges = { @@ -5707,7 +5703,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5721,18 +5717,18 @@ QUnit.module('fields', {}, function () { '</form>', res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10", "int_field should start with value 10"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10", "int_field should still be 10 (no onchange, because line is not valid)"); // fill turtle_foo field - testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text"); + await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text"); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1", "int_field should be 1 (onchange triggered, because line is now valid)"); @@ -5740,7 +5736,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list editable: \'required\' modifiers is properly working, part 2', function (assert) { + QUnit.test('one2many list editable: \'required\' modifiers is properly working, part 2', async function (assert) { assert.expect(3); this.data.partner.onchanges = { @@ -5751,7 +5747,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5766,18 +5762,18 @@ QUnit.module('fields', {}, function () { '</form>', res_id: 1, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10", "int_field should start with value 10"); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10", "int_field should still be 10 (no onchange, because line is not valid)"); // fill turtle_int field - testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_int"]'), "1"); + await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_int"]'), "1"); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1", "int_field should be 1 (onchange triggered, because line is now valid)"); @@ -5785,7 +5781,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many list editable: add new line before onchange returns', function (assert) { + QUnit.test('one2many list editable: add new line before onchange returns', async function (assert) { // If the user adds a new row (with a required field with onchange), selects // a value for that field, then adds another row before the onchange returns, // the editable list must wait for the onchange to return before trying to @@ -5796,8 +5792,8 @@ QUnit.module('fields', {}, function () { turtle_trululu: function () { }, }; - var def; - var form = createView({ + var prom; + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5811,23 +5807,23 @@ 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 Promise.resolve(prom).then(_.constant(result)); } return result; }, }); // add a first line but hold the onchange back - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + prom = testUtils.makeTestPromise(); assert.containsOnce(form, '.o_data_row', "should have created the first row immediately"); - def = $.Deferred(); - testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); - testUtils.fields.many2one.clickHighlightedItem('turtle_trululu'); + await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); + await testUtils.fields.many2one.clickHighlightedItem('turtle_trululu'); // try to add a second line and check that it is correctly waiting // for the onchange to return - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 0, "no modal should be displayed"); assert.strictEqual($('.o_field_invalid').length, 0, "no field should be marked as invalid"); @@ -5836,8 +5832,9 @@ QUnit.module('fields', {}, function () { assert.hasClass(form.$('.o_data_row'),'o_selected_row', "first row should still be in edition"); - // resolve the onchange def - def.resolve(); + // resolve the onchange promise + prom.resolve(); + await testUtils.nextTick(); assert.containsN(form, '.o_data_row', 2, "second row should now have been created"); assert.doesNotHaveClass(form.$('.o_data_row:first'), 'o_selected_row', @@ -5846,15 +5843,15 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable list: multiple clicks on Add an item do not create invalid rows', function (assert) { + QUnit.test('editable list: multiple clicks on Add an item do not create invalid rows', async function (assert) { assert.expect(3); this.data.turtle.onchanges = { turtle_trululu: function () { }, }; - var def; - var form = createView({ + var prom; + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5868,21 +5865,21 @@ 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 Promise.resolve(prom).then(_.constant(result)); } return result; }, }); - + prom = testUtils.makeTestPromise(); // click twice to add a new line - def = $.Deferred(); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsNone(form, '.o_data_row', "no row should have been created yet (waiting for the onchange)"); - // resolve the onchange def - def.resolve(); + // resolve the onchange promise + prom.resolve(); + await testUtils.nextTick(); assert.containsOnce(form, '.o_data_row', "only one row should have been created"); assert.hasClass(form.$('.o_data_row:first'),'o_selected_row', @@ -5891,7 +5888,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable list: value reset by an onchange', function (assert) { + QUnit.test('editable list: value reset by an onchange', async function (assert) { // this test reproduces a subtle behavior that may occur in a form view: // the user adds a record in a one2many field, and directly clicks on a // datetime field of the form view which has an onchange, which totally @@ -5907,8 +5904,8 @@ QUnit.module('fields', {}, function () { }, }; - var def; - var form = createView({ + var prom; + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5923,22 +5920,23 @@ 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 Promise.resolve(prom).then(_.constant(result)); } return result; }, }); // trigger the two onchanges - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_data_row .o_field_widget'), 'a name'); - def = $.Deferred(); - testUtils.dom.click(form.$('.o_datepicker_input')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_data_row .o_field_widget'), 'a name'); + prom = testUtils.makeTestPromise(); + await testUtils.dom.click(form.$('.o_datepicker_input')); var dateTimeVal = fieldUtils.format.datetime(moment(), { timezone: false }); - testUtils.fields.editSelect(form.$('.o_datepicker_input'), dateTimeVal); + await testUtils.fields.editSelect(form.$('.o_datepicker_input'), dateTimeVal); - // resolve the onchange def - def.resolve(); + // resolve the onchange promise + prom.resolve(); + await testUtils.nextTick(); assert.containsOnce(form, '.o_data_row', "should have one record in the o2m"); @@ -5948,14 +5946,14 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editable list: onchange that returns a warning', function (assert) { + QUnit.test('editable list: onchange that returns a warning', async function (assert) { assert.expect(5); this.data.turtle.onchanges = { display_name: function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -5970,7 +5968,7 @@ QUnit.module('fields', {}, function () { mockRPC: function (route, args) { if (args.method === 'onchange') { assert.step(args.method); - return $.when({ + return Promise.resolve({ value: {}, warning: { title: "Warning", @@ -5991,22 +5989,22 @@ QUnit.module('fields', {}, function () { }); // add a line (this should trigger an onchange and a warning) - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // check if 'Add an item' still works (this should trigger an onchange // and a warning again) - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.verifySteps(['onchange', 'warning', 'onchange', 'warning']); form.destroy(); }); - QUnit.test('editable list: contexts are correctly sent', function (assert) { + QUnit.test('editable list: contexts are correctly sent', async function (assert) { assert.expect(5); this.data.partner.records[0].timmy = [12]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6051,14 +6049,14 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.dom.click(form.$('.o_data_cell:first')); - testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'abc'); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_data_cell:first')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'abc'); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('resetting invisible one2manys', function (assert) { + QUnit.test('resetting invisible one2manys', async function (assert) { assert.expect(3); this.data.partner.records[0].turtles = []; @@ -6066,7 +6064,7 @@ QUnit.module('fields', {}, function () { obj.turtles = [[5], [4, 1]]; }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6084,20 +6082,20 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.fields.editInput(form.$('input[name="foo"]'), 'abcd'); + await testUtils.fields.editInput(form.$('input[name="foo"]'), 'abcd'); assert.verifySteps(['read', 'onchange']); form.destroy(); }); - QUnit.test('one2many: onchange that returns unknow field in list, but not in form', function (assert) { + QUnit.test('one2many: onchange that returns unknow field in list, but not in form', async function (assert) { assert.expect(5); this.data.partner.onchanges = { name: function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6115,7 +6113,7 @@ QUnit.module('fields', {}, function () { '</form>', mockRPC: function (route, args) { if (args.method === 'onchange') { - return $.when({ + return Promise.resolve({ value: { p: [[5], [0, 0, { display_name: 'new', timmy: [[5], [4, 12]] }]], }, @@ -6130,7 +6128,7 @@ QUnit.module('fields', {}, function () { assert.containsNone(form, '.o_field_widget[name="timmy"]', "timmy should not be displayed in the list view"); - testUtils.dom.click(form.$('.o_data_row td:first')); + await testUtils.dom.click(form.$('.o_data_row td:first')); assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"]').length, 1, "timmy should be displayed in the form view"); @@ -6142,16 +6140,16 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange and required fields with override in arch', function (assert) { + QUnit.test('onchange and required fields with override in arch', async function (assert) { assert.expect(4); this.data.partner.onchanges = { - turtles: function (obj) { } + turtles: function () { } }; this.data.turtle.fields.turtle_foo.required = true; this.data.partner.records[0].turtles = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6169,16 +6167,16 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - testUtils.form.clickEdit(form); + await testUtils.form.clickEdit(form); // triggers an onchange on partner, because the new record is valid - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.verifySteps(['read', 'default_get', 'onchange']); form.destroy(); }); - QUnit.test('onchange on a one2many containing a one2many', function (assert) { + QUnit.test('onchange on a one2many containing a one2many', async function (assert) { // the purpose of this test is to ensure that the onchange specs are // correctly and recursively computed assert.expect(1); @@ -6187,7 +6185,7 @@ QUnit.module('fields', {}, function () { p: function () { } }; var checkOnchange = false; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6211,16 +6209,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); - testUtils.fields.editInput($('.modal .o_data_cell input'), 'new record'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); + await testUtils.fields.editInput($('.modal .o_data_cell input'), 'new record'); checkOnchange = true; - testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); + await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); form.destroy(); }); - QUnit.test('editing tabbed one2many (editable=bottom)', function (assert) { + QUnit.test('editing tabbed one2many (editable=bottom)', async function (assert) { assert.expect(12); this.data.partner.records[0].turtles = []; @@ -6230,7 +6228,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles.push(id); } - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6255,14 +6253,14 @@ QUnit.module('fields', {}, function () { }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, 'tr.o_data_row', 41); assert.hasClass(form.$('tr.o_data_row').last(), 'o_selected_row'); - testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); - testUtils.form.clickSave(form); + await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); + await testUtils.form.clickSave(form); assert.containsN(form, 'tr.o_data_row', 40); @@ -6270,7 +6268,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('editing tabbed one2many (editable=bottom), again...', function (assert) { + QUnit.test('editing tabbed one2many (editable=bottom), again...', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = []; @@ -6280,7 +6278,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles.push(id); } - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6295,18 +6293,18 @@ QUnit.module('fields', {}, function () { }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); - testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); - testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); + await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); + await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); assert.containsN(form, 'tr.o_data_row', 3, "should have 3 data rows on the current page"); form.destroy(); }); - QUnit.test('editing tabbed one2many (editable=top)', function (assert) { + QUnit.test('editing tabbed one2many (editable=top)', async function (assert) { assert.expect(15); this.data.partner.records[0].turtles = []; @@ -6317,7 +6315,7 @@ QUnit.module('fields', {}, function () { this.data.partner.records[0].turtles.push(id); } - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6342,12 +6340,12 @@ QUnit.module('fields', {}, function () { }); - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); assert.containsN(form, 'tr.o_data_row', 2); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.containsN(form, 'tr.o_data_row', 3); @@ -6356,8 +6354,8 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('tr.o_data_row input').val(), 'default foo', "selected input should have correct string"); - testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); - testUtils.form.clickSave(form); + await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); + await testUtils.form.clickSave(form); assert.containsN(form, 'tr.o_data_row', 40); @@ -6365,8 +6363,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many field: change value before pending onchange returns', function (assert) { - var done = assert.async(); + QUnit.test('one2many field: change value before pending onchange returns', async function (assert) { assert.expect(2); var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; @@ -6375,8 +6372,8 @@ QUnit.module('fields', {}, function () { this.data.partner.onchanges = { int_field: function () { } }; - var def; - var form = createView({ + var prom; + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6392,42 +6389,41 @@ QUnit.module('fields', {}, function () { var result = this._super.apply(this, arguments); if (args.method === 'onchange') { // delay the onchange RPC - return $.when(def).then(_.constant(result)); + return Promise.resolve(prom).then(_.constant(result)); } return result; }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - def = $.Deferred(); - testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), '44'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + prom = testUtils.makeTestPromise(); + await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), '44'); var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); // set trululu before onchange - form.$('.o_field_many2one input').val('first').trigger('keydown').trigger('keyup'); + await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'), + 'first', ['keydown', 'keyup']); // complete the onchange - def.resolve(); + prom.resolve(); assert.strictEqual(form.$('.o_field_many2one input').val(), 'first', 'should have kept the new value'); - concurrency.delay(0).then(function () { - // check name_search result - assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 1, - 'autocomplete should contains 1 suggestion'); + await testUtils.nextTick(); + // check name_search result + assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 1, + 'autocomplete should contains 1 suggestion'); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; + form.destroy(); }); - QUnit.test('focus is correctly reset after an onchange in an x2many', function (assert) { + QUnit.test('focus is correctly reset after an onchange in an x2many', async function (assert) { assert.expect(2); this.data.partner.onchanges = { int_field: function () { } }; - var def; - var form = createView({ + var prom; + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6445,37 +6441,38 @@ QUnit.module('fields', {}, function () { var result = this._super.apply(this, arguments); if (args.method === 'onchange') { // delay the onchange RPC - return $.when(def).then(_.constant(result)); + return Promise.resolve(prom).then(_.constant(result)); } return result; }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - def = $.Deferred(); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + prom = testUtils.makeTestPromise(); testUtils.fields.editAndTrigger(form.$('.o_field_widget[name=int_field]'), '44', ['input', { type: 'keydown', which: $.ui.keyCode.TAB }]); - def.resolve(); + prom.resolve(); + await testUtils.nextTick(); assert.strictEqual(document.activeElement, form.$('.o_field_widget[name=qux]')[0], "qux field should have the focus"); - testUtils.fields.many2one.clickOpenDropdown('trululu'); - testUtils.fields.many2one.clickHighlightedItem('trululu'); + await testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickHighlightedItem('trululu'); assert.strictEqual(form.$('.o_field_many2one input').val(), 'first record', "the one2many field should have the expected value"); form.destroy(); }); - QUnit.test('checkbox in an x2many that triggers an onchange', function (assert) { + QUnit.test('checkbox in an x2many that triggers an onchange', async function (assert) { assert.expect(1); this.data.partner.onchanges = { bar: function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6488,23 +6485,23 @@ QUnit.module('fields', {}, function () { '</form>', }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.dom.click(form.$('.o_field_widget[name=bar] input')); + await testUtils.dom.click(form.$('.o_field_widget[name=bar] input')); assert.notOk(form.$('.o_field_widget[name=bar] input').prop('checked'), "the checkbox should be unticked"); form.destroy(); }); - QUnit.test('one2many with default value: edit line to make it invalid', function (assert) { + QUnit.test('one2many with default value: edit line to make it invalid', async function (assert) { assert.expect(3); this.data.partner.fields.p.default = [ [0, false, { foo: "coucou", int_field: 5 }], ]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6519,9 +6516,9 @@ QUnit.module('fields', {}, function () { }); // edit the line and enter an invalid value for int_field - testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(1)')); - testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 'e'); - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(1)')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 'e'); + await testUtils.dom.click(form.$el); assert.containsOnce(form, '.o_data_row.o_selected_row', "line should not have been removed and should still be in edition"); @@ -6533,7 +6530,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('default value for nested one2manys (coming from onchange)', function (assert) { + QUnit.test('default value for nested one2manys (coming from onchange)', async function (assert) { assert.expect(3); this.data.partner.onchanges.p = function (obj) { @@ -6543,7 +6540,7 @@ QUnit.module('fields', {}, function () { ]; }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6568,17 +6565,17 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_cell').text(), '1 record', "should correctly display the value of the inner o2m"); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('display correct value after validation error', function (assert) { + QUnit.test('display correct value after validation error', async function (assert) { assert.expect(4); this.data.partner.onchanges.turtles = function () { }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6597,8 +6594,8 @@ QUnit.module('fields', {}, function () { // we simulate a validation error. In the 'real' web client, // the server error will be used by the session to display // an error dialog. From the point of view of the basic - // model, the deferred is just rejected. - return $.Deferred().reject(); + // model, the promise is just rejected. + return Promise.reject(); } } if (args.method === 'write') { @@ -6615,31 +6612,31 @@ QUnit.module('fields', {}, function () { "initial text should be correct"); // click and edit value to 'foo', which will trigger onchange - testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)')); - testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'foo'); - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'foo'); + await testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_data_row .o_data_cell:nth(0)').text(), 'foo', "field should have been changed to foo"); // click and edit value to 'pinky', which trigger a failed onchange - testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)')); - testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'pinky'); - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'pinky'); + await testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_data_row .o_data_cell:nth(0)').text(), 'foo', "turtle_foo text should now be set back to foo"); // we make sure here that when we save, the values are the current // values displayed in the field. - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('propagate context to sub views', function (assert) { + QUnit.test('propagate context to sub views', async function (assert) { assert.expect(5); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6659,14 +6656,14 @@ QUnit.module('fields', {}, function () { }, viewOptions: { context: { flutter: 'shy' } }, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'pinky pie'); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'pinky pie'); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('onchange on nested one2manys', function (assert) { + QUnit.test('onchange on nested one2manys', async function (assert) { assert.expect(6); this.data.partner.onchanges.display_name = function (obj) { @@ -6681,7 +6678,7 @@ QUnit.module('fields', {}, function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6715,30 +6712,30 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'trigger onchange'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'trigger onchange'); assert.strictEqual(form.$('.o_data_cell').text(), 'test', "should have added the new row to the one2many"); // open the new subrecord to check the value of the nested o2m, and to // ensure that it will be saved - testUtils.dom.click(form.$('.o_data_cell:first')); + await testUtils.dom.click(form.$('.o_data_cell:first')); assert.strictEqual($('.modal .o_data_cell').text(), 'test nested', "should have added the new row to the nested one2many"); - testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); + await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); form.destroy(); }); - QUnit.test('one2many with multiple pages and sequence field', function (assert) { + QUnit.test('one2many with multiple pages and sequence field', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.partner.onchanges.turtles = function () { }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6754,7 +6751,7 @@ QUnit.module('fields', {}, function () { res_id: 1, mockRPC: function (route, args) { if (args.method === 'onchange') { - return $.when({ + return Promise.resolve({ value: { turtles: [ [5], @@ -6769,19 +6766,19 @@ QUnit.module('fields', {}, function () { mode: 'edit', }, }); - testUtils.dom.click(form.$('.o_list_record_remove:first button')); + await testUtils.dom.click(form.$('.o_list_record_remove:first button')); assert.strictEqual(form.$('.o_data_row').text(), 'from onchange', 'onchange has been properly applied'); form.destroy(); }); - QUnit.test('one2many with multiple pages and sequence field, part2', function (assert) { + QUnit.test('one2many with multiple pages and sequence field, part2', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.partner.onchanges.turtles = function () { }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6797,7 +6794,7 @@ QUnit.module('fields', {}, function () { res_id: 1, mockRPC: function (route, args) { if (args.method === 'onchange') { - return $.when({ + return Promise.resolve({ value: { turtles: [ [5], @@ -6813,20 +6810,20 @@ QUnit.module('fields', {}, function () { mode: 'edit', }, }); - testUtils.dom.click(form.$('.o_list_record_remove:first button')); + await testUtils.dom.click(form.$('.o_list_record_remove:first button')); assert.strictEqual(form.$('.o_data_row').text(), 'from onchange id2from onchange id3', 'onchange has been properly applied'); form.destroy(); }); - QUnit.test('one2many with sequence field, override default_get, bottom when inline', function (assert) { + QUnit.test('one2many with sequence field, override default_get, bottom when inline', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.turtle.fields.turtle_int.default = 10; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6852,22 +6849,22 @@ QUnit.module('fields', {}, function () { // check line is at the correct place var inputText = 'ninja'; - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText); + await testUtils.form.clickSave(form); assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText); form.destroy(); }); - QUnit.test('one2many with sequence field, override default_get, top when inline', function (assert) { + QUnit.test('one2many with sequence field, override default_get, top when inline', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.turtle.fields.turtle_int.default = 10; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6893,22 +6890,22 @@ QUnit.module('fields', {}, function () { // check line is at the correct place var inputText = 'ninja'; - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText); + await testUtils.form.clickSave(form); assert.strictEqual($('.o_data_cell').text(), inputText + "blipyopkawa"); form.destroy(); }); - QUnit.test('one2many with sequence field, override default_get, bottom when popup', function (assert) { + QUnit.test('one2many with sequence field, override default_get, bottom when popup', async function (assert) { assert.expect(3); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.turtle.fields.turtle_int.default = 10; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6939,25 +6936,25 @@ QUnit.module('fields', {}, function () { // check line is at the correct place var inputText = 'ninja'; - testUtils.dom.click($('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput($('.o_input[name="turtle_foo"]'), inputText); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click($('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput($('.o_input[name="turtle_foo"]'), inputText); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText); - testUtils.dom.click($('.o_form_button_save')); + await testUtils.dom.click($('.o_form_button_save')); assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText); form.destroy(); }); - QUnit.test('one2many with sequence field, override default_get, not last page', function (assert) { + QUnit.test('one2many with sequence field, override default_get, not last page', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.turtle.fields.turtle_int.default = 10; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -6979,19 +6976,19 @@ QUnit.module('fields', {}, function () { // click add a new line // check turtle_int for new is the current max of the page - testUtils.dom.click($('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_input[name="turtle_int"]').val(), '10'); form.destroy(); }); - QUnit.test('one2many with sequence field, override default_get, last page', function (assert) { + QUnit.test('one2many with sequence field, override default_get, last page', async function (assert) { assert.expect(1); this.data.partner.records[0].turtles = [3, 2, 1]; this.data.turtle.fields.turtle_int.default = 10; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7013,12 +7010,12 @@ QUnit.module('fields', {}, function () { // click add a new line // check turtle_int for new is the current max of the page +1 - testUtils.dom.click($('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_input[name="turtle_int"]').val(), '22'); form.destroy(); }); - QUnit.test('one2many with sequence field, fetch name_get from empty list, field text', function (assert) { + QUnit.test('one2many with sequence field, fetch name_get from empty list, field text', async function (assert) { // There was a bug where a RPC would fail because no route was set. // The scenario is: // - create a new parent model, which has a one2many @@ -7043,7 +7040,7 @@ QUnit.module('fields', {}, function () { relation: 'product' }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7067,11 +7064,11 @@ QUnit.module('fields', {}, function () { var inputText1 = 'relax'; var inputText2 = 'max'; - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText1); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText2); - 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.editInput(form.$('.o_input[name="turtle_foo"]'), inputText1); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText2); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.o_data_cell:nth-child(2)').text(), inputText1 + inputText2); @@ -7079,7 +7076,7 @@ QUnit.module('fields', {}, function () { assert.equal($handles.length, 3, 'There should be 3 sequence handlers'); - testUtils.dom.dragAndDrop($handles.eq(1), + await testUtils.dom.dragAndDrop($handles.eq(1), form.$('tbody tr').first(), { position: 'top' } ); @@ -7089,7 +7086,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with several pages, onchange and default order', function (assert) { + QUnit.test('one2many with several pages, onchange and default order', async function (assert) { // This test reproduces a specific scenario where a one2many is displayed // over several pages, and has a default order such that a record that // would normally be on page 1 is actually on another page. Moreover, @@ -7117,7 +7114,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: data, @@ -7145,9 +7142,9 @@ QUnit.module('fields', {}, function () { "should display two records out of three, in the correct order"); // edit turtle_int field of first row - testUtils.dom.click(form.$('.o_data_cell:first')); - testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_int]'), 3); - testUtils.dom.click(form.$el); + await testUtils.dom.click(form.$('.o_data_cell:first')); + await testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_int]'), 3); + await testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_data_cell.foo').text(), 'blipkawa', "should still display the same two records"); @@ -7163,10 +7160,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('new record, with one2many with more default values than limit', function (assert) { + QUnit.test('new record, with one2many with more default values than limit', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7184,14 +7181,14 @@ QUnit.module('fields', {}, function () { }); assert.strictEqual(form.$('.o_data_row').text(), 'yopblip', 'data has been properly loaded'); - testUtils.form.clickSave(form); + await testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_data_row').text(), 'yopblip', 'data has been properly saved'); form.destroy(); }); - QUnit.test('add a new line after limit is reached should behave nicely', function (assert) { + QUnit.test('add a new line after limit is reached should behave nicely', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [1, 2, 3]; @@ -7208,7 +7205,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7225,16 +7222,16 @@ 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')); assert.containsN(form, '.o_data_row', 4, 'should have 4 data rows'); - testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), 'a'); + await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), 'a'); assert.containsN(form, '.o_data_row', 4, 'should still have 4 data rows (the limit is increased to 4)'); form.destroy(); }); - QUnit.test('onchange in a one2many with non inline view on an existing record', function (assert) { + QUnit.test('onchange in a one2many with non inline view on an existing record', async function (assert) { assert.expect(6); this.data.partner.fields.sequence = { string: 'Sequence', type: 'integer' }; @@ -7245,7 +7242,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]; - var form = testUtils.createView({ + var form = await createView({ View: FormView, model: 'partner_type', data: this.data, @@ -7265,13 +7262,13 @@ QUnit.module('fields', {}, function () { }); // swap 2 lines in the one2many - testUtils.dom.dragAndDrop(form.$('.ui-sortable-handle:eq(1)'), form.$('tbody tr').first(), + await testUtils.dom.dragAndDrop(form.$('.ui-sortable-handle:eq(1)'), form.$('tbody tr').first(), { position: 'top' }); assert.verifySteps(['load_views', 'read', 'read', 'onchange', 'onchange']); form.destroy(); }); - QUnit.test('onchange in a one2many with non inline view on a new record', function (assert) { + QUnit.test('onchange in a one2many with non inline view on a new record', async function (assert) { assert.expect(8); this.data.turtle.onchanges = { @@ -7282,7 +7279,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7300,8 +7297,8 @@ QUnit.module('fields', {}, function () { }); // add a row and trigger the onchange - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_data_row .o_field_widget[name=display_name]'), 'a name'); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_data_row .o_field_widget[name=display_name]'), 'a name'); assert.strictEqual(form.$('.o_data_row .o_field_widget[name=turtle_int]').val(), "44", "should have triggered the onchange"); @@ -7318,10 +7315,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('add a line, edit it and "Save & New"', function (assert) { + QUnit.test('add a line, edit it and "Save & New"', async function (assert) { assert.expect(5); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7337,27 +7334,27 @@ QUnit.module('fields', {}, function () { "there should be no record in the relation"); // add a new record - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput($('.modal .o_field_widget'), 'new record'); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput($('.modal .o_field_widget'), 'new record'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new record', "should display the new record"); // reopen freshly added record and edit it - testUtils.dom.click(form.$('.o_data_row .o_data_cell')); - testUtils.fields.editInput($('.modal .o_field_widget'), 'new record edited'); + await testUtils.dom.click(form.$('.o_data_row .o_data_cell')); + await testUtils.fields.editInput($('.modal .o_field_widget'), 'new record edited'); // save it, and choose to directly create another record - testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)')); assert.strictEqual($('.modal').length, 1, "the model should still be open"); assert.strictEqual($('.modal .o_field_widget').text(), '', "should have cleared the input"); - testUtils.fields.editInput($('.modal .o_field_widget'), 'another new record'); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.fields.editInput($('.modal .o_field_widget'), 'another new record'); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new record editedanother new record', "should display the two records"); @@ -7365,10 +7362,10 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('o2m add a line custom control create editable', function (assert) { + QUnit.test('o2m add a line custom control create editable', async function (assert) { assert.expect(5); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7402,25 +7399,25 @@ QUnit.module('fields', {}, function () { // click add food // check it's empty - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)')); assert.strictEqual($('.o_data_cell').text(), ""); // click add pizza // save the modal // check it's pizza - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)')); // click add pasta - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)')); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)')); + await testUtils.form.clickSave(form); assert.strictEqual($('.o_data_cell').text(), "pizzapasta"); form.destroy(); }); - QUnit.test('o2m add a line custom control create non-editable', function (assert) { + QUnit.test('o2m add a line custom control create non-editable', async function (assert) { assert.expect(6); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7454,31 +7451,31 @@ QUnit.module('fields', {}, function () { // click add food // check it's empty - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)')); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual($('.o_data_cell').text(), ""); // click add pizza // save the modal // check it's pizza - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)')); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual($('.o_data_cell').text(), "pizza"); // click add pasta // save the whole record // check it's pizzapasta - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)')); - testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual($('.o_data_cell').text(), "pizzapasta"); form.destroy(); }); - QUnit.test('o2m add a line custom control create align with handle', function (assert) { + QUnit.test('o2m add a line custom control create align with handle', async function (assert) { assert.expect(3); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7501,7 +7498,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many form view with action button', function (assert) { + QUnit.test('one2many form view with action button', async function (assert) { // once the action button is clicked, the record is reloaded (via the // on_close handler, executed because the python method does not return // any action, or an ir.action.act_window_close) ; this test ensures that @@ -7512,7 +7509,7 @@ QUnit.module('fields', {}, function () { var data = this.data; data.partner.records[0].p = [2]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: data, @@ -7547,21 +7544,21 @@ QUnit.module('fields', {}, function () { "initial display_name of o2m record should be correct"); // open one2many record in form view - testUtils.dom.click(form.$('.o_data_cell:first')); + await testUtils.dom.click(form.$('.o_data_cell:first')); assert.strictEqual($('.modal .o_form_view').length, 1, "should have opened the form view in a dialog"); assert.strictEqual($('.modal .o_form_view .o_data_row').length, 0, "there should be no record in the many2many"); // click on the action button - testUtils.dom.click($('.modal .o_form_view button')); + await testUtils.dom.click($('.modal .o_form_view button')); assert.strictEqual($('.modal .o_data_row').length, 1, "fields in the o2m form view should have been read"); assert.strictEqual($('.modal .o_data_cell').text(), 'gold', "many2many subrecord should have been fetched"); // save the dialog - testUtils.dom.click($('.modal .modal-footer .btn-primary')); + await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_data_cell').text(), 'new name', "fields in the o2m list view should have been read as well"); @@ -7569,7 +7566,7 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('onchange affecting inline unopened list view', function (assert) { + QUnit.test('onchange affecting inline unopened list view', async function (assert) { // when we got onchange result for fields of record that were not // already available because they were in a inline view not already // opened, in a given configuration the change were applied ignoring @@ -7605,7 +7602,7 @@ QUnit.module('fields', {}, function () { }, }; - var form = createView({ + var form = await createView({ View: FormView, model: 'user', data: this.data, @@ -7627,42 +7624,42 @@ QUnit.module('fields', {}, function () { }); // add a turtle on second partner - testUtils.form.clickEdit(form); - testUtils.dom.click(form.$('.o_data_row:eq(1)')); - testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); + await testUtils.form.clickEdit(form); + await testUtils.dom.click(form.$('.o_data_row:eq(1)')); + await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); $('.modal input[name="display_name"]').val('michelangelo').change(); - testUtils.dom.click($('.modal .btn-primary')); + await testUtils.dom.click($('.modal .btn-primary')); // open first partner so changes from previous action are applied - testUtils.dom.click(form.$('.o_data_row:eq(0)')); - testUtils.dom.click($('.modal .btn-primary')); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_data_row:eq(0)')); + await testUtils.dom.click($('.modal .btn-primary')); + await testUtils.form.clickSave(form); assert.strictEqual(numUserOnchange, 2, 'there should 2 and only 2 onchange from closing the partner modal'); - testUtils.dom.click(form.$('.o_data_row:eq(0)')); + await testUtils.dom.click(form.$('.o_data_row:eq(0)')); assert.strictEqual($('.modal .o_data_row').length, 1, 'only 1 turtle for first partner'); assert.strictEqual($('.modal .o_data_row').text(), 'donatello', 'first partner turtle is donatello'); - testUtils.dom.click($('.modal .o_form_button_cancel')); + await testUtils.dom.click($('.modal .o_form_button_cancel')); - testUtils.dom.click(form.$('.o_data_row:eq(1)')); + await testUtils.dom.click(form.$('.o_data_row:eq(1)')); assert.strictEqual($('.modal .o_data_row').length, 1, 'only 1 turtle for second partner'); assert.strictEqual($('.modal .o_data_row').text(), 'michelangelo', 'second partner turtle is michelangelo'); - testUtils.dom.click($('.modal .o_form_button_cancel')); + await testUtils.dom.click($('.modal .o_form_button_cancel')); form.destroy(); }); - QUnit.test('click on URL should not open the record', function (assert) { + QUnit.test('click on URL should not open the record', async function (assert) { assert.expect(2); this.data.partner.records[0].turtles = [1]; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7678,20 +7675,20 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.dom.click(form.$('.o_email_cell a')); + await testUtils.dom.click(form.$('.o_email_cell a')); assert.strictEqual($('.modal .o_form_view').length, 0, 'click should not open the modal'); - testUtils.dom.click(form.$('.o_url_cell a')); + await testUtils.dom.click(form.$('.o_url_cell a')); assert.strictEqual($('.modal .o_form_view').length, 0, 'click should not open the modal'); form.destroy(); }); - QUnit.test('create and edit on m2o in o2m, and press ESCAPE', function (assert) { + QUnit.test('create and edit on m2o in o2m, and press ESCAPE', async function (assert) { assert.expect(4); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7707,21 +7704,18 @@ 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')); assert.containsOnce(form, '.o_selected_row', "should have create a new row in edition"); - testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); - testUtils.fields.many2one.clickItem('turtle_trululu','Create and Edit...'); + await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); + await testUtils.fields.many2one.clickItem('turtle_trululu','Create and Edit...'); assert.strictEqual($('.modal .o_form_view').length, 1, "should have opened a form view in a dialog"); - $('.modal .o_form_view .o_field_widget[name=display_name]').trigger($.Event('keydown', { - which: $.ui.keyCode.ESCAPE, - keyCode: $.ui.keyCode.ESCAPE, - })); + await testUtils.fields.triggerKeydown($('.modal .o_form_view .o_field_widget[name=display_name]'), 'escape'); assert.strictEqual($('.modal .o_form_view').length, 0, "should have closed the dialog"); @@ -7731,13 +7725,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many add a line should not crash if orderedResIDs is not set', function (assert) { + QUnit.test('one2many add a line should not crash if orderedResIDs is not set', async function (assert) { // There is no assertion, the code will just crash before the bugfix. assert.expect(0); this.data.partner.records[0].turtles = []; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7761,16 +7755,16 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.dom.click($('button[name="action_invoice_open"]')); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click($('button[name="action_invoice_open"]')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.destroy(); }); - QUnit.test('one2many shortcut tab should not crash when there is no input widget', function (assert) { + QUnit.test('one2many shortcut tab should not crash when there is no input widget', async function (assert) { assert.expect(2); // create a one2many view which has no input (only 1 textarea in this case) - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7788,12 +7782,9 @@ QUnit.module('fields', {}, function () { }); // add a row, fill it, then trigger the tab shortcut - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editAndTrigger( - form.$('.o_input[name="turtle_foo"]'), - 'ninja', - ['input', $.Event('keydown', {which: $.ui.keyCode.TAB, keyCode: $.ui.keyCode.TAB,})] - ); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), 'ninja'); + await testUtils.fields.triggerKeydown(form.$('.o_input[name="turtle_foo"]'), 'tab'); assert.strictEqual(form.$('.o_field_text').text(), 'blipninja', 'current line should be saved'); @@ -7803,15 +7794,15 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('one2many with onchange, required field, shortcut enter', function (assert) { + QUnit.test('one2many with onchange, required field, shortcut enter', async function (assert) { assert.expect(5); this.data.turtle.onchanges = { turtle_foo: function () { }, }; - var def; - var form = createView({ + var prom; + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7825,7 +7816,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 Promise.resolve(prom).then(_.constant(result)); } return result; }, @@ -7837,20 +7828,15 @@ QUnit.module('fields', {}, function () { var value = "hello"; // add a new line - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // we want to add a delay to simulate an onchange - def = $.Deferred(); + prom = testUtils.makeTestPromise(); // write something in the field var $input = form.$('input[name="turtle_foo"]'); - testUtils.fields.editInput($input, value); - - // trigger keydown ENTER - $input.trigger($.Event('keydown', { - keyCode: $.ui.keyCode.ENTER, - which: $.ui.keyCode.ENTER, - })); + await testUtils.fields.editInput($input, value); + await testUtils.fields.triggerKeydown($input, 'enter'); // check that nothing changed before the onchange finished assert.strictEqual($input.val(), value, "input content shouldn't change"); @@ -7858,7 +7844,8 @@ QUnit.module('fields', {}, function () { "should still contain only one row"); // unlock onchange - def.resolve(); + prom.resolve(); + await testUtils.nextTick(); // check the current line is added with the correct content and a new line is editable assert.strictEqual(form.$('td.o_data_cell').text(), value); @@ -7869,13 +7856,13 @@ QUnit.module('fields', {}, function () { form.destroy(); }); - QUnit.test('no deadlock when leaving a one2many line with uncommitted changes', function (assert) { + QUnit.test('no deadlock when leaving a one2many line with uncommitted changes', async function (assert) { // Before unselecting a o2m line, field widgets are asked to commit their changes (new values // that they wouldn't have sent to the model yet). This test is added alongside a bug fix // ensuring that we don't end up in a deadlock when a widget actually has some changes to // commit at that moment. assert.expect(9); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -7895,13 +7882,13 @@ QUnit.module('fields', {}, function () { fieldDebounce: 5000, }); - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.fields.editInput(form.$('.o_field_widget[name=turtles] input'), 'some foo value'); + await testUtils.fields.editInput(form.$('.o_field_widget[name=turtles] input'), 'some foo value'); // click to add a second row to unselect the current one, then save - testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - testUtils.form.clickSave(form); + await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.form.clickSave(form); assert.containsOnce(form, '.o_form_readonly', "form view should be in readonly"); @@ -7919,10 +7906,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, @@ -7948,20 +7935,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'); @@ -7974,7 +7961,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]'); @@ -7992,11 +7979,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, @@ -8022,21 +8009,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]; @@ -8049,7 +8037,7 @@ QUnit.module('fields', {}, function () { } }; - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, @@ -8070,24 +8058,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, @@ -8114,24 +8102,25 @@ 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('field context is correctly passed to x2m subviews', function (assert) { + QUnit.test('field context is correctly passed to x2m subviews', async function (assert) { assert.expect(2); - var form = createView({ + var form = await createView({ View: FormView, model: 'partner', data: this.data, |
