diff --git a/addons/account/static/tests/reconciliation_tests.js b/addons/account/static/tests/reconciliation_tests.js index 6feac45cf0a..23b59314db5 100644 --- a/addons/account/static/tests/reconciliation_tests.js +++ b/addons/account/static/tests/reconciliation_tests.js @@ -595,22 +595,22 @@ QUnit.module('account', { assert.expect(11); var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { 'data': this.params.data, }); clientAction.appendTo($('#qunit-fixture')); var widget = clientAction.widgets[0]; - assert.ok(widget.$el.hasClass('o_reconciliation_line'), "should instance of widget reconciliation"); - assert.strictEqual(widget.$('.accounting_view').length, 1, "should have one view"); - assert.strictEqual(widget.$('.match').length, 1, "should have 'match' panel"); - assert.strictEqual(widget.$('.create').length, 1, "should have 'create' panel"); + assert.hasClass(widget.$el,'o_reconciliation_line', "should instance of widget reconciliation"); + assert.containsOnce(widget, '.accounting_view', "should have one view"); + assert.containsOnce(widget, '.match', "should have 'match' panel"); + assert.containsOnce(widget, '.create', "should have 'create' panel"); assert.strictEqual(widget.$('thead').text().replace(/[\n\r\s]+/g, ' '), " 101401 2017-01-01 SAJ/2014/002 and SAJ/2014/003 $ 1,175.00 ", "should display the line information"); assert.ok(widget.$('caption .o_field_many2one').length, "should display the many2one with to select a partner"); - assert.strictEqual(clientAction.$('[data-mode="inactive"]').length, 3, "should be as 'inactive' mode by default"); + assert.containsN(clientAction, '[data-mode="inactive"]', 3, "should be as 'inactive' mode by default"); assert.strictEqual(widget.$el.data('mode'), 'match', "the first one should automatically switch to match mode"); widget.$('.accounting_view thead td:first').trigger('click'); @@ -628,7 +628,7 @@ QUnit.module('account', { assert.expect(6); var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -647,9 +647,9 @@ QUnit.module('account', { assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Agrolait", "the partner many2one should display agrolait"); assert.strictEqual(clientAction.widgets[2].$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display Camptocamp"); widget.$('.accounting_view tfoot td:first').trigger('click'); - assert.strictEqual(widget.$('.create input.o_input').length, 7, + assert.containsN(widget, '.create input.o_input', 7, "create panel should contain 7 fields (account_id, tax_id, journal_id, analytic_account_id, analytic_tag_ids, label, amount)"); - assert.strictEqual(widget.$('.create .create_account_id .o_required_modifier, .create .create_label .o_required_modifier, .create .create_amount .o_required_modifier').length, 3, + assert.containsN(widget, '.create .create_account_id .o_required_modifier, .create .create_label .o_required_modifier, .create .create_amount .o_required_modifier', 3, "account_id, label and amount should be required fields"); assert.strictEqual(widget.$('.create .create_label input').val(), 'SAJ/2014/002 and SAJ/2014/003', "should use the name of the reconciliation line for the default label value"); @@ -663,7 +663,7 @@ QUnit.module('account', { assert.expect(17); var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -679,16 +679,16 @@ QUnit.module('account', { clientAction.appendTo($('#qunit-fixture')); var widget = clientAction.widgets[0]; - assert.strictEqual(widget.$('.mv_line').length, 2, "should display 2 account move lines"); + assert.containsN(widget, '.mv_line', 2, "should display 2 account move lines"); assert.strictEqual(widget.$('.mv_line').text().replace(/[\n\r\s]+/g, ' '), " 101200 2017-02-07 INV/2017/0002 $ 650.00 101200 2017-02-07 INV/2017/0003 $ 525.00 ", "should display 4 account move lines who contains the account_code, due_date, label and the credit"); assert.strictEqual(widget.$('.mv_line .cell_right:contains(".")').length, 2, "should display only the credit account move lines (hide the debit)"); clientAction.widgets[1].$('.accounting_view thead td:first').trigger('click'); - assert.strictEqual(clientAction.widgets[1].$('.mv_line').length, 5, "should display 5 account move lines"); + assert.containsN(clientAction.widgets[1], '.mv_line', 5, "should display 5 account move lines"); assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_right:contains(".")').length, 4, "should display only the credit account move lines (hide the debit)"); - assert.strictEqual(clientAction.widgets[1].$('.mv_line.already_reconciled').length, 3, "should display 3 already reconciled account move lines"); + assert.containsN(clientAction.widgets[1], '.mv_line.already_reconciled', 3, "should display 3 already reconciled account move lines"); assert.strictEqual(clientAction.widgets[1].$('.mv_line').text().replace(/[\n\r\s]+/g, ' '), " 101401 2017-01-23 ASUSTeK: BNK1/2017/0002: SUPP.OUT/2017/0002 : BILL/2017/0003 $ 376.00 101401 2017-01-23 Agrolait: BNK1/2017/0003: CUST.IN/2017/0001 $ 100.00 101401 2017-01-23 Agrolait: BNK1/2017/0004: CUST.IN/2017/0002 : INV/2017/0003 $ 525.50 101200 2017-02-07 Agrolait: INV/2017/0002 $ 650.00 101200 2017-02-22 Agrolait: INV/2017/0004 $ 525.00 ", "should display 4 account move lines who contains the account_code, due_date, label and the credit"); @@ -698,7 +698,7 @@ QUnit.module('account', { assert.ok(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should display the 'load more' button"); assert.equal(clientAction.widgets[1].$('.match div.load-more span').text(), 3, "should display 3 items remaining"); clientAction.widgets[1].$('.match div.load-more a').trigger('click'); - assert.strictEqual(clientAction.widgets[1].$('.mv_line').length, 8, "should load 3 more records"), + assert.containsN(clientAction.widgets[1], '.mv_line', 8, "should load 3 more records"), assert.notOk(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should not display the 'load more' button anymore"); assert.ok(clientAction.widgets[0].$('caption button.btn-secondary:visible').length, "should display the 'validate' button"); @@ -714,7 +714,7 @@ QUnit.module('account', { widget.$('.match .cell_account_code:first').trigger('click'); widget.$('.match .cell_account_code:first').trigger('click'); - testUtils.intercept(clientAction, 'call_service', function (event) { + testUtils.mock.intercept(clientAction, 'call_service', function (event) { assert.deepEqual(event.data.args[1].args, [[5],[{partner_id: 8, counterpart_aml_dicts: [{ "counterpart_aml_id": 109, @@ -747,7 +747,7 @@ QUnit.module('account', { assert.expect(1); // Test added to prevent this issue happening again: https://github.com/odoo/odoo/commit/3549688b21eb65e16b9c3f2b6462eb8d8b52cd47 var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -766,7 +766,7 @@ QUnit.module('account', { // Ensure that when we validate a line without any selection, it is the same // as when we manually create a line with the line.balance and that only one // line is send back to server. - testUtils.intercept(clientAction, 'call_service', function (event) { + testUtils.mock.intercept(clientAction, 'call_service', function (event) { assert.deepEqual(event.data.args[1].args, [[5],[{partner_id: 8, counterpart_aml_dicts: [], payment_aml_ids: [], new_aml_dicts: [{ @@ -791,7 +791,7 @@ QUnit.module('account', { assert.expect(1); // Test added to check this functionality: https://github.com/odoo/odoo/commit/2f3b469dee6f18cbccce1cdf2a81cfe57960c533 var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -815,7 +815,7 @@ QUnit.module('account', { // Ensure that when we validate a line with propositions and that there is a remaining balance // We also create a line which is the open balance. - testUtils.intercept(clientAction, 'call_service', function (event) { + testUtils.mock.intercept(clientAction, 'call_service', function (event) { assert.deepEqual(event.data.args[1].args, [[5],[{partner_id: 8, counterpart_aml_dicts: [{ @@ -847,7 +847,7 @@ QUnit.module('account', { assert.expect(10); var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, mockRPC: function (route, args) { console.log(args.method); @@ -894,12 +894,12 @@ QUnit.module('account', { widget.$('.o_input_dropdown input').trigger('click'); widget.$('.o_input_dropdown input').val('').trigger('keyup').trigger('blur'); - assert.strictEqual(widget.$('button.btn-primary:visible').length, 0, "should display the reconcile model buttons"); - assert.strictEqual(widget.$('.text-danger:visible').length, 1, "should display counterpart alert"); + assert.containsNone(widget, 'button.btn-primary:visible', "should display the reconcile model buttons"); + assert.containsOnce(widget, '.text-danger:visible', "should display counterpart alert"); widget.$('.accounting_view .cell_left .line_info_button').trigger('click'); - assert.strictEqual(widget.$('.accounting_view .cell_left .line_info_button').length, 1, "should display a partial reconciliation alert"); - assert.notOk(widget.$('.accounting_view .cell_left .line_info_button').hasClass('do_partial_reconcile_true'), "should display the partial reconciliation information"); - assert.strictEqual(widget.$('button.btn-primary:visible').length, 1, "should display the reconcile button"); + assert.containsOnce(widget, '.accounting_view .cell_left .line_info_button', "should display a partial reconciliation alert"); + assert.doesNotHaveClass(widget.$('.accounting_view .cell_left .line_info_button'), 'do_partial_reconcile_true', "should display the partial reconciliation information"); + assert.containsOnce(widget, 'button.btn-primary:visible', "should display the reconcile button"); assert.strictEqual( widget.$el.data('mode'), "inactive", "should be inactive mode"); widget.$('button.btn-primary:visible').trigger('click'); @@ -910,7 +910,7 @@ QUnit.module('account', { assert.expect(6); var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { 'data': this.params.data, }); @@ -918,11 +918,11 @@ QUnit.module('account', { assert.strictEqual(clientAction.$('h1.statement_name:visible').text(), "BNK/2014/001", "Should display the statement name"); clientAction.$('h1.statement_name').trigger('click'); - assert.strictEqual(clientAction.$('h1.statement_name:visible').length, 0, "Should hide the statement name title to edit the content"); - assert.strictEqual(clientAction.$('h1.statement_name_edition:visible').length, 1, "Should show the edition field of statement name"); - clientAction.$('h1.statement_name_edition input').val('BNK/2014/001-BB').trigger('input').blur(); - assert.strictEqual(clientAction.$('h1.statement_name_edition:visible').length, 0, "Should hide the edition field of statement name"); - assert.strictEqual(clientAction.$('h1.statement_name:visible').length, 1, "Should show the statement name"); + assert.containsNone(clientAction, 'h1.statement_name:visible', "Should hide the statement name title to edit the content"); + assert.containsOnce(clientAction, 'h1.statement_name_edition:visible', "Should show the edition field of statement name"); + testUtils.fields.editAndTrigger(clientAction.$('h1.statement_name_edition input'), 'BNK/2014/001-BB', ['input', 'blur']); + assert.containsNone(clientAction, 'h1.statement_name_edition:visible', "Should hide the edition field of statement name"); + assert.containsOnce(clientAction, 'h1.statement_name:visible', "Should show the statement name"); assert.strictEqual(clientAction.$('h1.statement_name:visible').text(), "BNK/2014/001-BB", "Should update the statement name"); clientAction.destroy(); @@ -933,7 +933,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { 'data': this.params.data, session: this.params.session, translateParameters: { @@ -966,7 +966,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, archs: { 'res.partner,false,list': '', @@ -979,20 +979,20 @@ QUnit.module('account', { clientAction.appendTo($('#qunit-fixture')); var widget = clientAction.widgets[0]; assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Agrolait", "the partner many2one should display agrolait"); - assert.strictEqual(widget.$('.match table tr').length, 2, "agrolait should have 2 propositions for reconciliation"); + assert.containsN(widget, '.match table tr', 2, "agrolait should have 2 propositions for reconciliation"); // Adding the two propositions // This is in order to try that after changing partner the propositions are emptied widget.$('.match .cell_account_code:first').trigger('click'); widget.$('.match .cell_account_code:first').trigger('click'); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "Both proposition should be selected"); + assert.containsN(widget, '.accounting_view tbody tr', 2, "Both proposition should be selected"); // Similate changing partner to one that does not have propositions to see if create mode is open after widget.$('.o_input_dropdown input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(partner 1)').trigger('mouseenter').trigger('click'); clientAction._onAction({target: widget, name: 'change_partner', data: {data: {display_name: 'partner 1', id: 1}}, stopped: false}); assert.strictEqual(widget.$('.o_input_dropdown input').val(), "partner 1", "the partner many2one should display partner 1"); - assert.strictEqual(widget.$('.match table tr.mv_line').length, 0, "partner 1 should have 0 propositions for reconciliation"); + assert.containsNone(widget, '.match table tr.mv_line', "partner 1 should have 0 propositions for reconciliation"); assert.strictEqual(widget.$el.data('mode'), 'create', "widget should be in create mode"); // Simulate changing partner @@ -1000,7 +1000,7 @@ QUnit.module('account', { $('.ui-autocomplete .ui-menu-item a:contains(Camptocamp)').trigger('mouseenter').trigger('click'); clientAction._onAction({target: widget, name: 'change_partner', data: {data: {display_name: 'Camptocamp', id: 12}}, stopped: false}); assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display Camptocamp"); - assert.strictEqual(widget.$('.match table tr.mv_line').length, 3, "camptocamp should have 3 propositions for reconciliation"); + assert.containsN(widget, '.match table tr.mv_line', 3, "camptocamp should have 3 propositions for reconciliation"); // Simulate changing partner with SelectCreateDialog widget = clientAction.widgets[1]; @@ -1008,21 +1008,21 @@ QUnit.module('account', { widget.$('.o_input_dropdown input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(Search More):eq(1)').trigger('mouseenter').trigger('click'); assert.strictEqual($('.modal').length, 1, "should open a SelectCreateDialog"); - $('.modal table.o_list_view td:contains(Camptocamp)').click(); + testUtils.dom.click($('.modal table.o_list_view td:contains(Camptocamp)')); assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display Camptocamp"); widget = clientAction.widgets[2]; widget.$('.accounting_view thead td:first').trigger('click'); widget.$('.accounting_view .mv_line .cell_label').trigger('click'); assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display agrolait"); - assert.strictEqual(widget.$('.match table tr').length, 3, "Camptocamp should have 3 propositions for reconciliation"); + assert.containsN(widget, '.match table tr', 3, "Camptocamp should have 3 propositions for reconciliation"); assert.notOk(widget.$('.match div.load-more a:visible').length, "should not display the load more button"); // Simulate remove partner widget.$('.o_input_dropdown input').trigger('click'); widget.$('.o_input_dropdown input').val('').trigger('keyup').trigger('blur'); assert.strictEqual(widget.$('.o_input_dropdown input').val(), "", "the partner many2one should be empty"); - assert.strictEqual(widget.$('.match table tr.mv_line').length, 5, "should have 5 propositions for reconciliation if partner is false"); + assert.containsN(widget, '.match table tr.mv_line', 5, "should have 5 propositions for reconciliation if partner is false"); assert.ok(widget.$('.match div.load-more a:visible').length, "should display the load more button"); clientAction.destroy(); @@ -1033,7 +1033,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -1058,44 +1058,44 @@ QUnit.module('account', { $('.ui-autocomplete .ui-menu-item a:contains(101200 Account Receivable)').trigger('mouseenter').trigger('click'); assert.notOk(widget.$('.accounting_view tfoot .cell_label').text(), "should not display 'Open Balance' line because the rest to reconcile is null"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 1, "should have only the created reconcile line"); + assert.containsOnce(widget, '.accounting_view tbody tr', "should have only the created reconcile line"); assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' '), " 101200 New SAJ/2014/002 and SAJ/2014/003 1175.00 ", "the new line should have the selected account, name and amout"); assert.ok(widget.$('caption button.btn-primary:visible').length, "should display the 'Reconcile' button"); - testUtils.intercept(clientAction, 'do_action', function (event) { + testUtils.mock.intercept(clientAction, 'do_action', function (event) { assert.strictEqual(JSON.stringify(event.data.action), '{"type":"ir.actions.act_window","res_model":"account.reconcile.model","views":[[false,"form"]],"target":"current"}', "should open the reconcile model form view"); }); widget.$('.create .reconcile_model_create').trigger('click'); - testUtils.intercept(clientAction, 'do_action', function (event) { + testUtils.mock.intercept(clientAction, 'do_action', function (event) { assert.strictEqual(JSON.stringify(event.data.action), '{"type":"ir.actions.act_window","res_model":"account.reconcile.model","views":[[false,"list"],[false,"form"]],"view_type":"list","view_mode":"list","target":"current"}', "should open the reconcile model list view"); }); widget.$('.create .reconcile_model_edit').trigger('click'); - widget.$('.create .create_amount input').val('1100.00').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_amount input'), '1100.00'); assert.strictEqual(widget.$('.accounting_view tbody .cell_right').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '), "$ 1100.00", "should display the value 1100.00 in right column"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "$ 75.00", "should display 'Open Balance' line because the rest to reconcile is 75.00"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 1, "should have ever only the created reconcile line"); + assert.containsOnce(widget, '.accounting_view tbody tr', "should have ever only the created reconcile line"); assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' '), " 101200 New SAJ/2014/002 and SAJ/2014/003 1100.00 ", "the new line should be update the amout"); assert.ok(widget.$('caption button.btn-secondary:visible').length, "should display the 'validate' button"); widget.$('.create .add_line').trigger('click').trigger('click'); - widget.$('.create .create_amount input').val('-100').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_amount input'), '-100'); widget.$('.create .create_account_id input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click'); - widget.$('.create .create_label input').val('test0').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_label input'), 'test0'); assert.strictEqual(widget.$('.accounting_view tbody .cell_left:last').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '), "$ 100.00", "should display the value 100.00 in left column"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "$ 175.00", "should display 'Open Balance' line because the rest to reconcile is 175.00"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "should have 2 created reconcile lines"); + assert.containsN(widget, '.accounting_view tbody tr', 2, "should have 2 created reconcile lines"); assert.strictEqual(widget.$('.accounting_view tbody tr:eq(1)').text().replace(/[\n\r\s$,]+/g, ' '), " 101000 New test0 100.00 ", "the new line should have the selected account, name and amout"); @@ -1104,15 +1104,15 @@ QUnit.module('account', { assert.strictEqual(widget.$('.create .create_amount input').val(), "175.00", "should have '175.00' as default amount value"); - widget.$('.create .create_amount input').val('200').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_amount input'), '200'); widget.$('.create .create_account_id input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click'); - widget.$('.create .create_label input').val('test1').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_label input'), 'test1'); assert.strictEqual(widget.$('.accounting_view tbody .cell_right:last').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '), "$ 200.00", "should display the value 200.00 in left column"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open balance'"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_left').text(), "$ 25.00", "should display 'Open balance' with 25.00 in left column"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 3, "should have 3 created reconcile lines"); + assert.containsN(widget, '.accounting_view tbody tr', 3, "should have 3 created reconcile lines"); clientAction.destroy(); }); @@ -1123,7 +1123,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); var def = $.Deferred(); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -1163,7 +1163,7 @@ QUnit.module('account', { widget.$('.create .create_account_id input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(Search)').trigger('mouseenter').trigger('click'); // select the account who does not appear in the drop drown - $('.modal tr.o_data_row:contains(502)').click(); + testUtils.dom.click($('.modal tr.o_data_row:contains(502)')); assert.strictEqual(widget.$('.create .create_account_id input').val(), "101200 Account Receivable", "Selected account does not change"); // wait the name_get to render the changes def.resolve(); @@ -1177,7 +1177,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -1196,13 +1196,13 @@ QUnit.module('account', { widget.$('.accounting_view tfoot td:first').trigger('click'); widget.$('.create .create_account_id input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click'); - widget.$('.create .create_label input').val('test1').trigger('input'); - widget.$('.create .create_amount input').val('1100').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_label input'), 'test1'); + testUtils.fields.editInput(widget.$('.create .create_amount input'), '1100'); assert.strictEqual(widget.$('.accounting_view tbody .cell_right:last').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '), "$ 1100.00", "should display the value 1100.00 in left column"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "$\u00a075.00", "should display 'Open Balance' with 75.00 in right column"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 1, "should have 1 created reconcile lines"); + assert.containsOnce(widget, '.accounting_view tbody tr', "should have 1 created reconcile lines"); widget.$('.create .create_tax_id input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(10.00%)').trigger('mouseenter').trigger('click'); @@ -1211,7 +1211,7 @@ QUnit.module('account', { assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "$\u00a075.00", "should display 'Open Balance' with 75.00 in right column"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_left').text(), "", "should display 'Open Balance' without any value in left column"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "should have 2 created reconcile lines"); + assert.containsN(widget, '.accounting_view tbody tr', 2, "should have 2 created reconcile lines"); widget.$('.create .create_tax_id input').trigger('click'); $('.ui-autocomplete .ui-menu-item a:contains(20.00%)').trigger('mouseenter').trigger('click'); @@ -1219,7 +1219,7 @@ QUnit.module('account', { assert.strictEqual(widget.$('.accounting_view tbody .cell_right').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '), "$ 1100.00 $ 220.00", "should have 2 created reconcile lines with right column values"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open balance'"); assert.strictEqual(widget.$('.accounting_view tfoot .cell_left').text(), "$\u00a0145.00", "should display 'Open balance' with 145.00 in right column"); - assert.strictEqual(widget.$('.accounting_view tbody tr').length, 2, "should have 2 created reconcile lines"); + assert.containsN(widget, '.accounting_view tbody tr', 2, "should have 2 created reconcile lines"); clientAction.destroy(); }); @@ -1229,7 +1229,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, }); clientAction.appendTo($('#qunit-fixture')); @@ -1244,7 +1244,7 @@ QUnit.module('account', { assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ' '), "Open balance229.12", "should display the 'Open balance' line with value in left column"); - widget.$('.create .create_amount input').val('100').trigger('input'); + testUtils.fields.editInput(widget.$('.create .create_amount input'), '100'); assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' '), " 101120 New ATOS Banque 1075.00 101120 New Tax 20.00% 215.00 101130 New ATOS Frais 90.91 101300 New Tax 10.00% include 9.09 ", @@ -1271,7 +1271,7 @@ QUnit.module('account', { var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: this.params.session, }); @@ -1281,8 +1281,8 @@ QUnit.module('account', { " 101000 Current AssetsLast Reconciliation: 2017-02-16 101000 ", "should display the account as title"); assert.strictEqual(clientAction.$('.o_reconciliation_line:first').data('mode'), "inactive", "should be in 'inactive' mode because no line to displayed and the balance amount is null"); - assert.strictEqual(clientAction.$('.accounting_view:first tbody tr').length, 2, "should have 2 propositions"); - assert.strictEqual(clientAction.$('.accounting_view:first .o_reconcile:visible').length, 1, "should display the reconcile button"); + assert.containsN(clientAction, '.accounting_view:first tbody tr', 2, "should have 2 propositions"); + assert.containsOnce(clientAction, '.accounting_view:first .o_reconcile:visible', "should display the reconcile button"); clientAction.$('.accounting_view:first .o_reconcile:visible').trigger('click'); @@ -1295,7 +1295,7 @@ QUnit.module('account', { assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match tr:first .cell_right .o_multi_currency').data('content'), "10,222.00 €", "sould display the monetary information in €"); - assert.strictEqual(clientAction.$('.accounting_view:first .o_no_valid:visible').length, 1, "should display the skip button"); + assert.containsOnce(clientAction, '.accounting_view:first .o_no_valid:visible', "should display the skip button"); clientAction.$('.accounting_view:eq(1) thead td:first').trigger('click'); clientAction.$('.o_reconciliation_line:eq(1) [data-line-id="21"] .cell_label').trigger('click'); @@ -1306,7 +1306,7 @@ QUnit.module('account', { clientAction.$('.o_reconciliation_line:eq(1) .o_reconcile:visible').trigger('click'); - assert.strictEqual(clientAction.$('.o_reconciliation_line[data-mode!="inactive"]').length, 1, "should have only one line open"); + assert.containsOnce(clientAction, '.o_reconciliation_line[data-mode!="inactive"]', "should have only one line open"); clientAction.$('.o_reconciliation_line:eq(1) [data-line-id="23"] .cell_label').trigger('click'); clientAction.$('.o_reconciliation_line:eq(1) [data-line-id="24"] .cell_label').trigger('click'); @@ -1336,7 +1336,7 @@ QUnit.module('account', { amount_str: "$ 999.00", debit: 999.0, account_code: "101200", ref: "", already_paid: false}; var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, mockRPC: function (route, args) { if (args.method === 'process_bank_statement_line') { @@ -1391,14 +1391,14 @@ QUnit.module('account', { assert.ok($reconciliationAlert.length, "should display the partial reconciliation alert"); - $reconciliationAlert.click(); + testUtils.dom.click($reconciliationAlert); var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)'); assert.equal($buttonReconcile.length, 1, 'The reconcile button must be visible'); - $buttonReconcile.click(); + testUtils.dom.click($buttonReconcile); clientAction.destroy(); }); @@ -1429,7 +1429,7 @@ QUnit.module('account', { amount_str: "$ 1200.00", debit: 1200.0, account_code: "101200", ref: "", already_paid: false}; var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, mockRPC: function (route, args) { if (args.method === 'process_bank_statement_line') { @@ -1498,15 +1498,15 @@ QUnit.module('account', { assert.equal(writeOffCreate.find('input[name=amount]').val(), -1225, 'The right amount should be proposed for the write-off'); - writeOffCreate.find('.create_account_id input.ui-autocomplete-input').click(); - $('ul.ui-autocomplete li a:first').click(); // select first account to do the write off in + testUtils.dom.click(writeOffCreate.find('.create_account_id input.ui-autocomplete-input')); + testUtils.dom.click($('ul.ui-autocomplete li a:first')); var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)'); assert.equal($buttonReconcile.length, 1, 'The reconcile button must be visible'); - $buttonReconcile.click(); + testUtils.dom.click($buttonReconcile); clientAction.destroy(); }); @@ -1524,7 +1524,7 @@ QUnit.module('account', { ]; var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, mockRPC: function (route, args) { if (args.method === 'process_move_lines') { @@ -1572,13 +1572,13 @@ QUnit.module('account', { 'The right amount should be proposed for the write-off'); // remove the first line, the other two will balance one another - widget.$('tr[data-line-id="999"] td:first').click() + testUtils.dom.click(widget.$('tr[data-line-id="999"] td:first')); var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)'); assert.equal($buttonReconcile.length, 1, 'The reconcile button must be visible'); - $buttonReconcile.click(); + testUtils.dom.click($buttonReconcile); clientAction.destroy(); }); @@ -1587,7 +1587,7 @@ QUnit.module('account', { assert.expect(2); var clientAction = new ReconciliationClientAction.ManualAction(null, this.params.options); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.params.data, session: { currencies: { @@ -1610,7 +1610,7 @@ QUnit.module('account', { assert.notOk('data-line-id' in emptyLine.getAttributes(), 'Empty line should be empty'); - emptyLine.find('td:first').click(); + testUtils.dom.click(emptyLine.find('td:first')); // Check that a create form is here var writeOffCreate = widget.$('div.create .create_account_id'); diff --git a/addons/account/static/tests/section_and_note_tests.js b/addons/account/static/tests/section_and_note_tests.js index 3cf6bd1e361..c40790fd9f7 100644 --- a/addons/account/static/tests/section_and_note_tests.js +++ b/addons/account/static/tests/section_and_note_tests.js @@ -67,26 +67,26 @@ QUnit.module('section_and_note', { // section should be displayed correctly var $tr0 = form.$('tr.o_data_row:eq(0)'); - assert.strictEqual($tr0.hasClass('o_is_line_section'), false, + assert.doesNotHaveClass($tr0, 'o_is_line_section', "should not have a section class"); var $tr1 = form.$('tr.o_data_row:eq(1)'); - assert.strictEqual($tr1.hasClass('o_is_line_section'), true, + assert.hasClass($tr1, 'o_is_line_section', "should have a section class"); // enter edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // editing line should be textarea $tr0 = form.$('tr.o_data_row:eq(0)'); - $tr0.find('td.o_data_cell').click(); + testUtils.dom.click($tr0.find('td.o_data_cell')); assert.strictEqual($tr0.find('td.o_data_cell textarea[name="name"]').length, 1, "editing line should be textarea"); // editing section should be input $tr1 = form.$('tr.o_data_row:eq(1)'); - $tr1.find('td.o_data_cell').click(); + testUtils.dom.click($tr1.find('td.o_data_cell')); assert.strictEqual($tr1.find('td.o_data_cell input[name="name"]').length, 1, "editing section should be input"); diff --git a/addons/barcodes/static/tests/barcode_tests.js b/addons/barcodes/static/tests/barcode_tests.js index 0e2996d8608..58cf13925b7 100644 --- a/addons/barcodes/static/tests/barcode_tests.js +++ b/addons/barcodes/static/tests/barcode_tests.js @@ -11,7 +11,7 @@ var testUtils = require('web.test_utils'); var NotificationService = require('web.NotificationService'); var createView = testUtils.createView; -var triggerKeypressEvent = testUtils.triggerKeypressEvent; +var triggerKeypressEvent = testUtils.dom.triggerKeypressEvent; QUnit.module('Barcodes', { beforeEach: function () { @@ -109,23 +109,23 @@ QUnit.test('edit, save and cancel buttons', function (assert) { // O-CMD.EDIT _.each(["O","-","C","M","D",".","E","D","I","T","Enter"], triggerKeypressEvent); - assert.strictEqual(form.$(".o_form_editable").length, 1, + assert.containsOnce(form, ".o_form_editable", "should have switched to 'edit' mode"); // dummy change to check that it actually saves - form.$('.o_field_widget').val('test').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget'), 'test'); // O-CMD.SAVE _.each(["O","-","C","M","D",".","S","A","V","E","Enter"], triggerKeypressEvent); - assert.strictEqual(form.$(".o_form_readonly").length, 1, + assert.containsOnce(form, ".o_form_readonly", "should have switched to 'readonly' mode"); assert.verifySteps(['save'], 'should have saved'); // O-CMD.EDIT _.each(["O","-","C","M","D",".","E","D","I","T","Enter"], triggerKeypressEvent); // dummy change to check that it correctly discards - form.$('.o_field_widget').val('test').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget'), 'test'); // O-CMD.CANCEL _.each(["O","-","C","M","D",".","D","I","S","C","A","R","D","Enter"], triggerKeypressEvent); - assert.strictEqual(form.$(".o_form_readonly").length, 1, + assert.containsOnce(form, ".o_form_readonly", "should have switched to 'readonly' mode"); assert.verifySteps(['save'], 'should not have saved'); @@ -169,7 +169,7 @@ QUnit.test('do no update form twice after a command barcode scanned', function ( var delay = barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms; barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = 0; - testUtils.patch(FormController, { + testUtils.mock.patch(FormController, { update: function () { assert.step('update'); return this._super.apply(this, arguments); @@ -212,7 +212,7 @@ QUnit.test('do no update form twice after a command barcode scanned', function ( form.destroy(); barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay; - testUtils.unpatch(FormController); + testUtils.mock.unpatch(FormController); }); QUnit.test('widget field_float_scannable', function (assert) { @@ -250,7 +250,7 @@ QUnit.test('widget field_float_scannable', function (assert) { assert.strictEqual(form.$('.o_field_widget[name=int_field]').text(), '4', "should display the correct value in readonly"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name=int_field]').val(), '4', "should display the correct value in edit"); @@ -387,7 +387,7 @@ QUnit.test('specification of widget barcode_handler', function (assert) { }, }); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "one2many should contain 2 rows"); // scan twice product 1 @@ -403,7 +403,7 @@ QUnit.test('specification of widget barcode_handler', function (assert) { assert.strictEqual(form.$('.o_data_row:nth(1) .o_data_cell:nth(1)').text(), '1', "quantity of line one should have been incremented"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); barcodeEvents.BarcodeEvents.max_time_between_keys_in_ms = delay; @@ -526,7 +526,7 @@ QUnit.test('barcode_scanned only trigger error for active view', function (asser }, }); - form.$('.o_data_row:first').click(); + testUtils.dom.click(form.$('.o_data_row:first')); // We do not trigger on the body since modal and // form view are both inside it. diff --git a/addons/base_import/static/tests/import_buttons_tests.js b/addons/base_import/static/tests/import_buttons_tests.js index e5326c1d25e..f231b551fa2 100644 --- a/addons/base_import/static/tests/import_buttons_tests.js +++ b/addons/base_import/static/tests/import_buttons_tests.js @@ -35,11 +35,11 @@ QUnit.test('add import button in list', function(assert) { assert.ok(list.$buttons.find('.o_button_import:contains(Import)').is(':visible'), "should have a visible Import button"); - testUtils.intercept(list, 'do_action', function() { + testUtils.mock.intercept(list, 'do_action', function() { assert.ok(true, "should have triggered a do_action"); }); - list.$buttons.find('.o_button_import:contains(Import)').click(); + testUtils.dom.click(list.$buttons.find('.o_button_import:contains(Import)')); list.destroy(); }); @@ -77,11 +77,11 @@ QUnit.test('add import button in kanban', function(assert) { assert.ok(kanban.$buttons.find('.o_button_import:contains(Import)').is(':visible'), "should have a visible Import button"); - testUtils.intercept(kanban, 'do_action', function() { + testUtils.mock.intercept(kanban, 'do_action', function() { assert.ok(true, "should have triggered a do_action"); }); - kanban.$buttons.find('.o_button_import:contains(Import)').click(); + testUtils.dom.click(kanban.$buttons.find('.o_button_import:contains(Import)')); kanban.destroy(); }); diff --git a/addons/board/static/tests/dashboard_tests.js b/addons/board/static/tests/dashboard_tests.js index 1e17ca71db1..1803875d33c 100644 --- a/addons/board/static/tests/dashboard_tests.js +++ b/addons/board/static/tests/dashboard_tests.js @@ -55,7 +55,7 @@ QUnit.test('dashboard basic rendering', function (assert) { '', }); - assert.notOk(form.renderer.$el.hasClass('o_dashboard'), + assert.doesNotHaveClass(form.renderer.$el, 'o_dashboard', "should not have the o_dashboard css class"); form.destroy(); @@ -71,9 +71,9 @@ QUnit.test('dashboard basic rendering', function (assert) { '', }); - assert.ok(form.renderer.$el.hasClass('o_dashboard'), + assert.hasClass(form.renderer.$el,'o_dashboard', "with a dashboard, the renderer should have the proper css class"); - assert.strictEqual(form.$('.o_dashboard .o_view_nocontent').length, 1, + assert.containsOnce(form, '.o_dashboard .o_view_nocontent', "should have a no content helper"); assert.strictEqual(form.get('title'), "My Dashboard", "should have the correct title"); @@ -99,7 +99,7 @@ QUnit.test('display the no content helper', function (assert) { }, }); - assert.strictEqual(form.$('.o_dashboard .o_view_nocontent').length, 1, + assert.containsOnce(form, '.o_dashboard .o_view_nocontent', "should have a no content helper with action help"); form.destroy(); }); @@ -141,53 +141,53 @@ QUnit.test('basic functionality, with one sub action', function (assert) { }, }); - assert.strictEqual(form.$('.oe_dashboard_links').length, 1, + assert.containsOnce(form, '.oe_dashboard_links', "should have rendered a link div"); - assert.strictEqual(form.$('table.oe_dashboard[data-layout="2-1"]').length, 1, + assert.containsOnce(form, 'table.oe_dashboard[data-layout="2-1"]', "should have rendered a table"); - assert.strictEqual(form.$('td.o_list_record_selector').length, 0, + assert.containsNone(form, 'td.o_list_record_selector', "td should not have a list selector"); assert.strictEqual(form.$('h2 span.oe_header_txt:contains(ABC)').length, 1, "should have rendered a header with action string"); - assert.strictEqual(form.$('tr.o_data_row').length, 3, + assert.containsN(form, 'tr.o_data_row', 3, "should have rendered 3 data rows"); assert.ok(form.$('.oe_content').is(':visible'), "content is visible"); - form.$('.oe_fold').click(); + testUtils.dom.click(form.$('.oe_fold')); assert.notOk(form.$('.oe_content').is(':visible'), "content is no longer visible"); - form.$('.oe_fold').click(); + testUtils.dom.click(form.$('.oe_fold')); assert.ok(form.$('.oe_content').is(':visible'), "content is visible again"); assert.verifySteps(['load action', 'edit custom', 'edit custom']); assert.strictEqual($('.modal').length, 0, "should have no modal open"); - form.$('button.oe_dashboard_link_change_layout').click(); + testUtils.dom.click(form.$('button.oe_dashboard_link_change_layout')); assert.strictEqual($('.modal').length, 1, "should have opened a modal"); assert.strictEqual($('.modal li[data-layout="2-1"] i.oe_dashboard_selected_layout').length, 1, "should mark currently selected layout"); - $('.modal .oe_dashboard_layout_selector li[data-layout="1-1"]').click(); + testUtils.dom.click($('.modal .oe_dashboard_layout_selector li[data-layout="1-1"]')); assert.strictEqual($('.modal').length, 0, "should have no modal open"); - assert.strictEqual(form.$('table.oe_dashboard[data-layout="1-1"]').length, 1, + assert.containsOnce(form, 'table.oe_dashboard[data-layout="1-1"]', "should have rendered a table with correct layout"); - assert.strictEqual(form.$('.oe_action').length, 1, "should have one displayed action"); - form.$('span.oe_close').click(); + assert.containsOnce(form, '.oe_action', "should have one displayed action"); + testUtils.dom.click(form.$('span.oe_close')); assert.strictEqual($('.modal').length, 1, "should have opened a modal"); // confirm the close operation - $('.modal button.btn-primary').click(); + testUtils.dom.click($('.modal button.btn-primary')); assert.strictEqual($('.modal').length, 0, "should have no modal open"); - assert.strictEqual(form.$('.oe_action').length, 0, "should have no displayed action"); + assert.containsNone(form, '.oe_action', "should have no displayed action"); assert.verifySteps(['load action', 'edit custom', 'edit custom', 'edit custom', 'edit custom']); form.destroy(); @@ -282,7 +282,7 @@ QUnit.test('can sort a sub list', function (assert) { assert.strictEqual($('tr.o_data_row').text(), 'yoplalalaabc', "should have correct initial data"); - form.$('th.o_column_sortable:contains(Foo)').click(); + testUtils.dom.click(form.$('th.o_column_sortable:contains(Foo)')); assert.strictEqual($('tr.o_data_row').text(), 'abclalalayop', "data should have been sorted"); @@ -328,7 +328,7 @@ QUnit.test('can open a record', function (assert) { }, }); - form.$('tr.o_data_row td:contains(yop)').click(); + testUtils.dom.click(form.$('tr.o_data_row td:contains(yop)')); form.destroy(); }); @@ -373,7 +373,7 @@ QUnit.test('can open record using action form view', function (assert) { }, }); - form.$('tr.o_data_row td:contains(yop)').click(); + testUtils.dom.click(form.$('tr.o_data_row td:contains(yop)')); form.destroy(); }); @@ -410,14 +410,14 @@ QUnit.test('can drag and drop a view', function (assert) { }, }); - assert.strictEqual(form.$('td.index_0 .oe_action').length, 1, + assert.containsOnce(form, 'td.index_0 .oe_action', "initial action is in column 0"); - testUtils.dragAndDrop(form.$('.oe_dashboard_column.index_0 .oe_header'), + testUtils.dom.dragAndDrop(form.$('.oe_dashboard_column.index_0 .oe_header'), form.$('.oe_dashboard_column.index_1')); - assert.strictEqual(form.$('td.index_0 .oe_action').length, 0, + assert.containsNone(form, 'td.index_0 .oe_action', "initial action is not in column 0"); - assert.strictEqual(form.$('td.index_1 .oe_action').length, 1, + assert.containsOnce(form, 'td.index_1 .oe_action', "initial action is in in column 1"); form.destroy(); @@ -555,7 +555,7 @@ QUnit.test('clicking on a kanban\'s button should trigger the action', function } }); - form.$('.o_kanban_test').find('button:first').click(); + testUtils.dom.click(form.$('.o_kanban_test').find('button:first')); form.destroy(); }); @@ -564,7 +564,7 @@ QUnit.test('subviews are aware of attach in or detach from the DOM', function (a assert.expect(2); // patch list renderer `on_attach_callback` for the test only - testUtils.patch(ListRenderer, { + testUtils.mock.patch(ListRenderer, { on_attach_callback: function () { assert.step('subview on_attach_callback'); } @@ -599,7 +599,7 @@ QUnit.test('subviews are aware of attach in or detach from the DOM', function (a assert.verifySteps(['subview on_attach_callback']); // restore on_attach_callback of ListRenderer - testUtils.unpatch(ListRenderer); + testUtils.mock.unpatch(ListRenderer); form.destroy(); }); @@ -609,7 +609,7 @@ QUnit.test('dashboard intercepts custom events triggered by sub controllers', fu // we patch the ListController to force it to trigger the custom events that // we want the dashboard to intercept (to stop them or to tweak their data) - testUtils.patch(ListController, { + testUtils.mock.patch(ListController, { start: function () { this.trigger_up('update_filters'); this.trigger_up('env_updated'); @@ -655,7 +655,7 @@ QUnit.test('dashboard intercepts custom events triggered by sub controllers', fu 'env_updated', // triggered by the dashboard itself ]); - testUtils.unpatch(ListController); + testUtils.mock.unpatch(ListController); board.destroy(); }); @@ -687,13 +687,15 @@ QUnit.test('save actions to dashboard', function (assert) { views: [[false, 'list']], }); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); assert.strictEqual($('.o_add_to_dashboard_link').length, 1, "should allow the 'Add to dashboard' feature"); // add this action to dashboard - $('.o_add_to_dashboard_button').click(); + testUtils.dom.click($('.o_search_options .o_dropdown button:contains(Favorites)')); + testUtils.dom.click($('.o_add_to_dashboard_link')); + testUtils.dom.click($('.o_add_to_dashboard_button')); actionManager.destroy(); }); @@ -737,13 +739,15 @@ QUnit.test('save to dashboard actions with flag keepSearchView', function (asser views: [[false, 'graph']], }, options); - assert.strictEqual(actionManager.$('.o_graph').length, 1, + assert.containsOnce(actionManager, '.o_graph', "should display the graph view"); assert.strictEqual($('.o_add_to_dashboard_link').length, 1, "should allow the 'Add to dashboard' feature (this is the same searchview)"); // add this action to dashboard - $('.o_add_to_dashboard_button').click(); + testUtils.dom.click($('.o_search_options .o_dropdown button:contains(Favorites)')); + testUtils.dom.click($('.o_add_to_dashboard_link')); + testUtils.dom.click($('.o_add_to_dashboard_button')); actionManager.destroy(); }); diff --git a/addons/bus/static/tests/bus_tests.js b/addons/bus/static/tests/bus_tests.js index e90f5d6cf30..3c81398c09a 100644 --- a/addons/bus/static/tests/bus_tests.js +++ b/addons/bus/static/tests/bus_tests.js @@ -27,7 +27,7 @@ QUnit.module('Bus', { var pollDeferred = $.Deferred(); var parent = new Widget(); - testUtils.addMockEnvironment(parent, { + testUtils.mock.addMockEnvironment(parent, { data: {}, services: { bus_service: BusService, @@ -87,7 +87,7 @@ QUnit.module('Bus', { assert.expect(3); // Simulate no ID of last notification in the local storage - testUtils.patch(LocalStorageServiceMock, { + testUtils.mock.patch(LocalStorageServiceMock, { getItem: function (key) { if (key === 'last_ts') { return 0; @@ -98,7 +98,7 @@ QUnit.module('Bus', { var pollDeferred = $.Deferred(); var parent = new Widget(); - testUtils.addMockEnvironment(parent, { + testUtils.mock.addMockEnvironment(parent, { data: {}, services: { bus_service: BusService, @@ -127,7 +127,7 @@ QUnit.module('Bus', { widget.call('bus_service', 'addChannel', 'lambda'); assert.verifySteps(['/longpolling/poll']); - testUtils.unpatch(LocalStorageServiceMock); + testUtils.mock.unpatch(LocalStorageServiceMock); parent.destroy(); }); @@ -140,7 +140,7 @@ QUnit.module('Bus', { var pollDeferredMaster = $.Deferred(); var parentMaster = new Widget(); - testUtils.addMockEnvironment(parentMaster, { + testUtils.mock.addMockEnvironment(parentMaster, { data: {}, services: { bus_service: BusService, @@ -172,7 +172,7 @@ QUnit.module('Bus', { setTimeout(function () { var parentSlave = new Widget(); - testUtils.addMockEnvironment(parentSlave, { + testUtils.mock.addMockEnvironment(parentSlave, { data: {}, services: { bus_service: BusService, diff --git a/addons/calendar/static/tests/calendar_tests.js b/addons/calendar/static/tests/calendar_tests.js index 9e3c8a936b5..fd00ed3074c 100644 --- a/addons/calendar/static/tests/calendar_tests.js +++ b/addons/calendar/static/tests/calendar_tests.js @@ -62,16 +62,16 @@ QUnit.module('calendar', { }, }); - assert.ok(form.$('.o_field_widget[name="partner_ids"]').hasClass('o_field_many2manytags')); - assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] .badge').length, 2, + assert.hasClass(form.$('.o_field_widget[name="partner_ids"]'), 'o_field_many2manytags'); + assert.containsN(form, '.o_field_widget[name="partner_ids"] .badge', 2, "there should be 2 tags"); assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] .badge:first').text().trim(), "Jesus", "the tag should be correctly named"); - assert.ok(form.$('.o_field_widget[name="partner_ids"] .badge:first .o_calendar_invitation').hasClass('accepted'), + assert.hasClass(form.$('.o_field_widget[name="partner_ids"] .badge:first .o_calendar_invitation'),'accepted', "Jesus should attend the meeting"); assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] .badge[data-id="2"]').text().trim(), "Mahomet", "the tag should be correctly named"); - assert.ok(form.$('.o_field_widget[name="partner_ids"] .badge[data-id="2"] .o_calendar_invitation').hasClass('needsAction'), + assert.hasClass(form.$('.o_field_widget[name="partner_ids"] .badge[data-id="2"] .o_calendar_invitation'),'needsAction', "Mohamet should still confirm his attendance to the meeting"); form.destroy(); diff --git a/addons/calendar/static/tests/systray_activity_menu_tests.js b/addons/calendar/static/tests/systray_activity_menu_tests.js index 803b43bb9e9..ac98f5751c9 100644 --- a/addons/calendar/static/tests/systray_activity_menu_tests.js +++ b/addons/calendar/static/tests/systray_activity_menu_tests.js @@ -41,7 +41,7 @@ QUnit.test('activity menu widget:today meetings', function (assert) { assert.expect(8); var self = this; var activityMenu = new ActivityMenu(); - testUtils.addMockEnvironment(activityMenu, { + testUtils.mock.addMockEnvironment(activityMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'systray_get_activities') { @@ -53,24 +53,24 @@ QUnit.test('activity menu widget:today meetings', function (assert) { activityMenu.appendTo($('#qunit-fixture')); - assert.ok(activityMenu.$el.hasClass('o_mail_systray_item'), 'should be the instance of widget'); + assert.hasClass(activityMenu.$el,'o_mail_systray_item', 'should be the instance of widget'); - testUtils.intercept(activityMenu, 'do_action', function (event) { + testUtils.mock.intercept(activityMenu, 'do_action', function (event) { assert.ok(true, "should have triggered a do_action"); assert.strictEqual(event.data.action.res_id, activityMenu.$('.o_meeting_filter').eq(0).data('res_id'), 'should open particular meeting form view'); }); - activityMenu.$('.dropdown-toggle').click(); - activityMenu.$('.o_meeting_filter').eq(0).click(); + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + testUtils.dom.click(activityMenu.$('.o_meeting_filter').eq(0)); - testUtils.intercept(activityMenu, 'do_action', function (event) { + testUtils.mock.intercept(activityMenu, 'do_action', function (event) { assert.strictEqual(event.data.action, "calendar.action_calendar_event", 'should open meeting calendar view in day mode'); }); - activityMenu.$('.o_mail_preview').click(); + testUtils.dom.click(activityMenu.$('.o_mail_preview')); assert.ok(activityMenu.$('.o_meeting_filter'), "should be a meeting"); - assert.strictEqual(activityMenu.$('.o_meeting_filter').length, 2, 'there should be 2 meetings'); - assert.strictEqual(activityMenu.$('.o_meeting_filter').eq(0).hasClass('o_meeting_bold'), true, 'this meeting is yet to start'); - assert.strictEqual(activityMenu.$('.o_meeting_filter').eq(1).hasClass('o_meeting_bold'), false, 'this meeting has been started'); + assert.containsN(activityMenu, '.o_meeting_filter', 2, 'there should be 2 meetings'); + assert.hasClass(activityMenu.$('.o_meeting_filter').eq(0), 'o_meeting_bold', 'this meeting is yet to start'); + assert.doesNotHaveClass(activityMenu.$('.o_meeting_filter').eq(1), 'o_meeting_bold', 'this meeting has been started'); activityMenu.destroy(); }); }); diff --git a/addons/crm/static/tests/sales_team_dashboard_tests.js b/addons/crm/static/tests/sales_team_dashboard_tests.js index ece5566f8f7..c28cf8f4157 100644 --- a/addons/crm/static/tests/sales_team_dashboard_tests.js +++ b/addons/crm/static/tests/sales_team_dashboard_tests.js @@ -1,6 +1,8 @@ odoo.define('crm.dashboard_tests', function (require) { "use strict"; +// this file is no longer loaded in the test suite, so i guess we can remove it + var testUtils = require('web.test_utils'); var view_registry = require('web.view_registry'); @@ -88,7 +90,7 @@ QUnit.test('dashboard set a new target', function (assert) { }, }); - kanban.$('.o_target_to_set').first().click(); // click on the target to set + testUtils.dom.click(kanban.$('.o_target_to_set').first()); kanban.$('.o_sales_dashboard input') .val('20000') .trigger($.Event('keyup', {which: $.ui.keyCode.ENTER})); // set the target @@ -122,14 +124,14 @@ QUnit.test('dashboard: click on a button to execute an action', function (assert }); - testUtils.intercept(kanban, 'execute_action', function (event) { + testUtils.mock.intercept(kanban, 'execute_action', function (event) { assert.strictEqual(event.data.action_data.name, 'func_name', 'execute_action should have been triggered with the correct data'); assert.strictEqual(event.data.action_data.type, 'object', 'execute_action should have been triggered with the correct data'); }); - kanban.$('.my_button:first()').click(); // click on the button of the first card + testUtils.dom.click(kanban.$('.my_button:first()')); kanban.destroy(); }); @@ -160,7 +162,7 @@ QUnit.test('dashboard should be displayed even if there is no content', function }, }); - assert.strictEqual(kanban.$('div.o_sales_dashboard').length, 1, + assert.containsOnce(kanban, 'div.o_sales_dashboard', "should render the dashboard"); assert.strictEqual(kanban.$('.o_view_nocontent:contains(A help message)').length, 1, "should correctly render the nocontent helper"); diff --git a/addons/document/static/tests/document_tests.js b/addons/document/static/tests/document_tests.js index 0e2c0038a71..8aebe4894e0 100644 --- a/addons/document/static/tests/document_tests.js +++ b/addons/document/static/tests/document_tests.js @@ -77,10 +77,10 @@ odoo.define('document.tests', function (require) { } }); - assert.strictEqual(form.sidebar.$('.o_sidebar_delete_attachment').length, 2, "there should be two attachments"); - form.sidebar.$('.o_sidebar_delete_attachment:eq(0)').click(); - $('.modal-footer .btn-primary').click(); - assert.strictEqual(form.sidebar.$('.o_sidebar_delete_attachment').length, 1, "there should be only one attachment"); + assert.containsN(form.sidebar, '.o_sidebar_delete_attachment', 2, "there should be two attachments"); + testUtils.dom.click(form.sidebar.$('.o_sidebar_delete_attachment:eq(0)')); + testUtils.dom.click($('.modal-footer .btn-primary')); + assert.containsOnce(form.sidebar, '.o_sidebar_delete_attachment', "there should be only one attachment"); form.destroy(); }); @@ -103,9 +103,9 @@ odoo.define('document.tests', function (require) { }); // select record then trigger render - list.$('.o_group_header:last').click(); - list.$('.o_data_row input').click(); - list.$('.o_group_header:first').click(); + testUtils.dom.click(list.$('.o_group_header:last')); + testUtils.dom.click(list.$('.o_data_row input')); + testUtils.dom.click(list.$('.o_group_header:first')); assert.verifySteps(['partner', 'partner', 'partner'], "ir.attachment not called when selecting record in list view"); diff --git a/addons/google_calendar/static/tests/google_calendar_tests.js b/addons/google_calendar/static/tests/google_calendar_tests.js index bba2286c163..704452771be 100644 --- a/addons/google_calendar/static/tests/google_calendar_tests.js +++ b/addons/google_calendar/static/tests/google_calendar_tests.js @@ -100,11 +100,11 @@ QUnit.module('Google Calendar', { return this._super.apply(this, arguments); }, }).then(function (calendar) { - assert.strictEqual(calendar.$('.fc-event').length, 2, "should display 2 events on the month"); + assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the month"); var $sidebar = calendar.$('.o_calendar_sidebar'); - calendar.$('.o_google_sync_button').click(); + testUtils.dom.click(calendar.$('.o_google_sync_button')); assert.verifySteps([ '/web/dataset/call_kw/calendar.event/search_read', @@ -112,7 +112,7 @@ QUnit.module('Google Calendar', { '/web/dataset/call_kw/calendar.event/search_read', ], 'should do a search_read before and after the call to sync_data'); - assert.strictEqual(calendar.$('.fc-event').length, 3, "should now display 3 events on the month"); + assert.containsN(calendar, '.fc-event', 3, "should now display 3 events on the month"); calendar.destroy(); done(); diff --git a/addons/google_drive/static/tests/gdrive_test.js b/addons/google_drive/static/tests/gdrive_test.js index ef91d66270d..1e96911de09 100644 --- a/addons/google_drive/static/tests/gdrive_test.js +++ b/addons/google_drive/static/tests/gdrive_test.js @@ -105,8 +105,10 @@ QUnit.module('gdrive_integration', { assert.strictEqual($googleAction.length, 1, 'The button to the google action should be present'); - // Trigger opening of the dynamic link - $googleAction.click(); + // click on gdrive sidebar item + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click($googleAction); + form.destroy(); }); @@ -114,6 +116,7 @@ QUnit.module('gdrive_integration', { assert.expect(3); var self = this; + var currentID; var form = createView({ View: FormView, model: 'partner', @@ -139,7 +142,7 @@ QUnit.module('gdrive_integration', { id: 1}]); } if (route === '/web/dataset/call_kw/google.drive.config/get_google_drive_url') { - assert.deepEqual(args.args, [27, self.activeId, 'T1000'], + assert.deepEqual(args.args, [27, currentID, 'T1000'], 'The route to get the Google url should have been called'); // We don't return anything useful, otherwise it will open a new tab return $.when(); @@ -148,16 +151,15 @@ QUnit.module('gdrive_integration', { }, }); - var nameToId = { - 'Locomotive Breath': 1, - 'Hey Macarena': 2, - } - // Trigger opening of the dynamic link - self.activeId = nameToId[$("[name='display_name']").text()]; - form.sidebar.$('.oe_share_gdoc').click(); - form.pager.$('.o_pager_next').click(); - self.activeId = nameToId[$("[name='display_name']").text()]; - form.sidebar.$('.oe_share_gdoc').click(); + currentID = 1; + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('.oe_share_gdoc')); + + testUtils.dom.click(form.pager.$('.o_pager_next')); + currentID = 2; + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('.oe_share_gdoc')); + form.destroy(); }); }); diff --git a/addons/hr_attendance/static/tests/hr_attendance_tests.js b/addons/hr_attendance/static/tests/hr_attendance_tests.js index ee582a5d7ad..4038212e8d7 100644 --- a/addons/hr_attendance/static/tests/hr_attendance_tests.js +++ b/addons/hr_attendance/static/tests/hr_attendance_tests.js @@ -58,7 +58,7 @@ QUnit.module('HR Attendance', { var $target = $('#qunit-fixture'); var clientAction = new MyAttendances(null); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.data, session: { uid: 1, @@ -79,7 +79,7 @@ QUnit.module('HR Attendance', { var self = this; var rpcCount = 0; var clientAction = new KioskMode(null); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: this.data, session: { uid: 1, @@ -123,7 +123,7 @@ QUnit.module('HR Attendance', { barcode: barcode, } var clientAction = new GreetingMessage(null, action); - testUtils.addMockEnvironment(clientAction, { + testUtils.mock.addMockEnvironment(clientAction, { data: self.data, session: { uid: 1, diff --git a/addons/hr_org_chart/static/tests/hr_org_chart_tests.js b/addons/hr_org_chart/static/tests/hr_org_chart_tests.js index d5a546b324b..d84cf293ae6 100644 --- a/addons/hr_org_chart/static/tests/hr_org_chart_tests.js +++ b/addons/hr_org_chart/static/tests/hr_org_chart_tests.js @@ -95,9 +95,9 @@ QUnit.module('hr_org_chart', { return this._super(route, args); } }); - assert.strictEqual(form.$('.o_org_chart_entry_sub').length, 1, + assert.containsOnce(form, '.o_org_chart_entry_sub', "the chart should have 1 subordinate"); - assert.strictEqual(form.$('.o_org_chart_entry_self').length, 1, + assert.containsOnce(form, '.o_org_chart_entry_self', "the current employee should only be displayed once in the chart"); form.destroy(); }); @@ -156,9 +156,9 @@ QUnit.module('hr_org_chart', { return this._super(route, args); } }); - assert.strictEqual(form.$('.o_org_chart_group_up .o_org_chart_entry_manager').length, 1, "the chart should have 1 manager"); - assert.strictEqual(form.$('.o_org_chart_group_down .o_org_chart_entry_sub').length, 1, "the chart should have 1 subordinate"); - assert.strictEqual(form.$('.o_org_chart_entry_self').length, 1, "the chart should have only once the current employee"); + assert.containsOnce(form, '.o_org_chart_group_up .o_org_chart_entry_manager', "the chart should have 1 manager"); + assert.containsOnce(form, '.o_org_chart_group_down .o_org_chart_entry_sub', "the chart should have 1 subordinate"); + assert.containsOnce(form, '.o_org_chart_entry_self', "the chart should have only once the current employee"); form.destroy(); }); }); diff --git a/addons/im_livechat/static/tests/website_livechat_window_tests.js b/addons/im_livechat/static/tests/website_livechat_window_tests.js index e57c34ac8af..4b8aa6635a8 100644 --- a/addons/im_livechat/static/tests/website_livechat_window_tests.js +++ b/addons/im_livechat/static/tests/website_livechat_window_tests.js @@ -45,16 +45,16 @@ QUnit.test('basic rendering', function (assert) { livechat.setMessages(messages); var chatWindow = new ChatWindow(parent, livechat); - testUtils.addMockEnvironment(parent, {}); + testUtils.mock.addMockEnvironment(parent, {}); chatWindow.appendTo($('#qunit-fixture')); chatWindow.render(); - assert.strictEqual(chatWindow.$('.o_thread_window_header').length, 1, + assert.containsOnce(chatWindow, '.o_thread_window_header', "should have a header"); assert.strictEqual(chatWindow.$('.o_thread_window_header').text().replace(/\s/g, ""), "myLivechat(2)", "should display the correct livechat name and unread message counter"); - assert.strictEqual(chatWindow.$('.o_thread_message').length, 2, + assert.containsN(chatWindow, '.o_thread_message', 2, "should display two messages"); parent.destroy(); diff --git a/addons/im_support/static/tests/helpers/test_utils.js b/addons/im_support/static/tests/helpers/test_utils.js index 3347c43029f..e0a5bdfd73a 100644 --- a/addons/im_support/static/tests/helpers/test_utils.js +++ b/addons/im_support/static/tests/helpers/test_utils.js @@ -58,7 +58,7 @@ function addMockSupportEnvironment(widget, params) { } return result; }; - testUtils.addMockEnvironment(widget, params); + testUtils.mock.addMockEnvironment(widget, params); var widgetDestroy = widget.destroy; widget.destroy = function () { supportSession.rpc = originalRPC; @@ -69,7 +69,7 @@ function addMockSupportEnvironment(widget, params) { // 'im_support.poll_timeout', to simulate a pending longpolling connection to // the Support server, such that the initSupport initiates a poll connection if (params.enableSupportPoll) { - testUtils.intercept(widget, 'call_service', function (ev) { + testUtils.mock.intercept(widget, 'call_service', function (ev) { if (ev.data.service === 'local_storage') { if (ev.data.method === 'getItem' && ev.data.args[0] === 'im_support.poll_timeout') { ev.data.callback(Date.now() + (60 * 1000)); diff --git a/addons/im_support/static/tests/systray_no_support_tests.js b/addons/im_support/static/tests/systray_no_support_tests.js index 89cb5b0389d..f835c0e55b7 100644 --- a/addons/im_support/static/tests/systray_no_support_tests.js +++ b/addons/im_support/static/tests/systray_no_support_tests.js @@ -38,15 +38,14 @@ QUnit.test('messaging menu does not display the Support channel if not available assert.expect(1); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]').length, - 0, "should not display the Support channel"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsNone(messagingMenu, '.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]', "should not display the Support channel"); messagingMenu.destroy(); }); diff --git a/addons/im_support/static/tests/systray_tests.js b/addons/im_support/static/tests/systray_tests.js index 3bf05417d7e..9f50ce1d29c 100644 --- a/addons/im_support/static/tests/systray_tests.js +++ b/addons/im_support/static/tests/systray_tests.js @@ -40,9 +40,8 @@ QUnit.test('messaging menu displays the Support channel', function (assert) { }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]').length, - 1, "should display the Support channel"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]', "should display the Support channel"); messagingMenu.destroy(); }); @@ -74,11 +73,10 @@ QUnit.test('clicking on Support channel: channel not available', function (asser }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]').length, - 1, "should display the Support channel"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]'); - messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]')); assert.strictEqual($('.o_thread_window').length, 1, "should have open a chat window"); assert.strictEqual($('.o_thread_window .o_thread_window_title').text().trim(), 'Support (offline)', @@ -119,11 +117,10 @@ QUnit.test('clicking on Support channel: channel available', function (assert) { }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]').length, - 1, "should display the Support channel"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]'); - messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]')); assert.strictEqual($('.o_thread_window').length, 1, "should have open a chat window"); assert.strictEqual($('.o_thread_window .o_thread_window_title').text().trim(), 'Support', @@ -164,11 +161,10 @@ QUnit.test('post messages in Support channel', function (assert) { }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]').length, - 1, "should display the Support channel"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]'); - messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]')); assert.strictEqual($('.o_thread_window .o_composer_input').length, 1, "should have a composer"); @@ -208,25 +204,24 @@ QUnit.test('fold Support channel', function (assert) { services: this.services, session: this.supportParams, }); - testUtils.intercept(messagingMenu, 'call_service', function (ev) { + testUtils.mock.intercept(messagingMenu, 'call_service', function (ev) { if (ev.data.service === 'local_storage') { assert.step('LocalStorage: ' + ev.data.method + ' ' + ev.data.args); } }, true); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]').length, - 1, "should display the Support channel"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_systray_dropdown_bottom .o_mail_preview[data-preview-id=SupportChannel]'); - messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview[data-preview-id=SupportChannel]')); assert.strictEqual($('.o_thread_window').length, 1, "should have open a chat window"); // fold, re-open and close channel - $('.o_thread_window .o_thread_window_title').click(); - $('.o_thread_window .o_thread_window_title').click(); - $('.o_thread_window .o_thread_window_close').click(); + testUtils.dom.click($('.o_thread_window .o_thread_window_title')); + testUtils.dom.click($('.o_thread_window .o_thread_window_title')); + testUtils.dom.click($('.o_thread_window .o_thread_window_close')); assert.verifySteps([ '/mail/init_messaging', @@ -322,7 +317,7 @@ QUnit.test('receive messages in the Support channel', function (assert) { "there should be a new message in the thread"); assert.strictEqual($('.o_thread_window .o_thread_message .o_thread_author ').text().trim(), 'An operator', "should correctly display the author"); - assert.strictEqual($('.o_thread_window .o_thread_message .o_thread_message_avatar').attr('data-src'), + assert.hasAttrValue($('.o_thread_window .o_thread_message .o_thread_message_avatar'), 'data-src', '/mail/static/src/img/odoo_o.png', "should have correct avatar"); assert.strictEqual($('.o_thread_window .o_thread_message .o_thread_message_content ').text().trim(), 'A message', "message is correct"); diff --git a/addons/lunch/static/tests/lunch_tests.js b/addons/lunch/static/tests/lunch_tests.js index 2b0405307f0..3ae1e3491cb 100644 --- a/addons/lunch/static/tests/lunch_tests.js +++ b/addons/lunch/static/tests/lunch_tests.js @@ -77,7 +77,7 @@ QUnit.module('lunch', { var widgetText = form.$('.o_field_widget[name="previous_order_widget"]').text(); assert.ok(widgetText.indexOf('This is the first time you order a meal') !== -1, "the widget should display its no content text"); - assert.strictEqual(form.$('.o_lunch_vignette').length, 0, + assert.containsNone(form, '.o_lunch_vignette', "there should be no vignette"); form.destroy(); @@ -125,16 +125,16 @@ QUnit.module('lunch', { }, }); - assert.strictEqual(form.$('.o_list_view tr.o_data_row').length, 0, + assert.containsNone(form, '.o_list_view tr.o_data_row', "there should be no row in the one2many list"); - assert.strictEqual(form.$('.o_lunch_vignette').length, 1, + assert.containsOnce(form, '.o_lunch_vignette', "there should be a vignette"); // add an order - form.$('.o_lunch_vignette .o_add_button').click(); + testUtils.dom.click(form.$('.o_lunch_vignette .o_add_button')); - assert.strictEqual(form.$('.o_list_view tr.o_data_row').length, 1, + assert.containsOnce(form, '.o_list_view tr.o_data_row', "there should be one new row in the one2many list"); assert.strictEqual(form.$('.o_list_view tr.o_data_row').text(), "Pizza Margheritacoucou6.90", "the line should contain the correct data"); diff --git a/addons/mail/static/tests/activity_tests.js b/addons/mail/static/tests/activity_tests.js index 9f7f7fd8808..0c3a9311dec 100644 --- a/addons/mail/static/tests/activity_tests.js +++ b/addons/mail/static/tests/activity_tests.js @@ -172,7 +172,7 @@ QUnit.test('activity view: simple activity rendering', function (assert) { } }); - assert.strictEqual(activity.$('table').length, 1, + assert.containsOnce(activity, 'table', 'should have a table'); assert.ok(activity.$('table thead tr:first th:nth-child(2) span:first:contains(Email)').length, 'should contain "Email" in header of first column'); @@ -204,7 +204,7 @@ QUnit.test('activity view: no content rendering', function (assert) { }, }); - assert.strictEqual(activity.$('.o_view_nocontent').length, 1, + assert.containsOnce(activity, '.o_view_nocontent', "should display the no content helper"); assert.strictEqual(activity.$('.o_view_nocontent .o_view_nocontent_empty_folder').text().trim(), "No data to display", @@ -234,16 +234,16 @@ QUnit.test('activity view: batch send mail on activity', function (assert) { assert.notOk(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show').length, 'dropdown shouldn\'t be displayed'); - activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v').click(); + testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v')); assert.ok(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show').length, 'dropdown should have appeared'); - activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:first:contains(Task: Rating Request)').click(); + testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:first:contains(Task: Rating Request)')); assert.notOk(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show').length, 'dropdown shouldn\'t be displayed'); - activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v').click(); - activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:nth-child(2):contains(Task: Reception Acknowledgment)').click(); + testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) i.fa-ellipsis-v')); + testUtils.dom.click(activity.$('table thead tr:first th:nth-child(2) span:nth-child(2) .dropdown-menu.show .o_send_mail_template:nth-child(2):contains(Task: Reception Acknowledgment)')); assert.verifySteps([ [[13, 30], 9], //send mail template 9 on tasl 13 and 30 [[13, 30], 8] //send mail template 8 on tasl 13 and 30 @@ -305,28 +305,28 @@ QUnit.test('activity view: activity widget', function (assert) { var today = activity.$('table tbody tr:first td:nth-child(2).today'); var dropdown = today.find('.dropdown-menu.o_activity'); - today.find('.o_closest_deadline').click(); - assert.ok(dropdown.hasClass('show'), "dropdown should be displayed"); + testUtils.dom.click(today.find('.o_closest_deadline')); + assert.hasClass(dropdown,'show', "dropdown should be displayed"); assert.ok(dropdown.find('.o_activity_color_today:contains(Today)').length, "Title should be today"); assert.ok(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first div:contains(template8)').length, "template8 should be available"); assert.ok(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:eq(1) div:contains(template9)').length, "template9 should be available"); - dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_preview').click(); - dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_send').click(); + testUtils.dom.click(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_preview')); + testUtils.dom.click(dropdown.find('.o_activity_title_entry[data-activity-id="2"]:first .o_activity_template_send')); var overdue = activity.$('table tbody tr:first td:nth-child(3).overdue'); - overdue.find('.o_closest_deadline').click(); + testUtils.dom.click(overdue.find('.o_closest_deadline')); dropdown = overdue.find('.dropdown-menu.o_activity'); assert.notOk(dropdown.find('.o_activity_title div div div:first span').length, "No template should be available"); - dropdown.find('.o_schedule_activity').click(); - overdue.find('.o_closest_deadline').click(); - dropdown.find('.o_mark_as_done').click(); + testUtils.dom.click(dropdown.find('.o_schedule_activity')); + testUtils.dom.click(overdue.find('.o_closest_deadline')); + testUtils.dom.click(dropdown.find('.o_mark_as_done')); dropdown.find('#activity_feedback').val("feedback2"); - dropdown.find('.o_activity_popover_done_next').click(); + testUtils.dom.click(dropdown.find('.o_activity_popover_done_next')); assert.verifySteps([ "do_action_compose", "activity_send_mail", diff --git a/addons/mail/static/tests/chatter_tests.js b/addons/mail/static/tests/chatter_tests.js index 4bcce4ab352..470b6045797 100644 --- a/addons/mail/static/tests/chatter_tests.js +++ b/addons/mail/static/tests/chatter_tests.js @@ -213,11 +213,11 @@ QUnit.test('basic rendering', function (assert) { "there should be a followers widget, moved inside the chatter's topbar"); assert.ok(form.$('.o_chatter').length, "there should be a chatter widget"); assert.ok(form.$('.o_mail_thread').length, "there should be a mail thread"); - assert.strictEqual(form.$('.o_chatter_button_attachment').length, 1, "should have one attachment button"); + assert.containsOnce(form, '.o_chatter_button_attachment', "should have one attachment button"); assert.ok(!form.$('.o_chatter_topbar .o_chatter_button_log_note').length, "log note button should not be available"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(count, 0, "should have done no read_followers rpc as there are no followers"); assert.strictEqual(unwanted_read_count, 0, "followers should only be fetched with read_followers route"); form.destroy(); @@ -234,7 +234,7 @@ QUnit.test('Activity Done keep feedback on blur', function (assert) { var shownDef = $.Deferred(); var hiddenDef = $.Deferred(); - testUtils.patch(Activity, { + testUtils.mock.patch(Activity, { _bindPopoverFocusout: function () { this._super.apply(this, arguments); shownDef.resolve(); @@ -265,7 +265,7 @@ QUnit.test('Activity Done keep feedback on blur', function (assert) { $popoverEl.on('hidden.bs.popover', hiddenDef.resolve.bind(hiddenDef)); // open popover - $popoverEl.click(); + testUtils.dom.click($popoverEl); shownDef.then(function () { // write a feedback and focusout @@ -276,7 +276,7 @@ QUnit.test('Activity Done keep feedback on blur', function (assert) { shownDef = $.Deferred(); // re-open popover - $popoverEl.click(); + testUtils.dom.click($popoverEl); shownDef.then(function () { var $feedbackPopover = $($popoverEl.data('bs.popover').tip); @@ -284,7 +284,7 @@ QUnit.test('Activity Done keep feedback on blur', function (assert) { "feedback should have been kept"); form.destroy(); - testUtils.unpatch(Activity); + testUtils.mock.unpatch(Activity); done(); }); }); @@ -308,18 +308,32 @@ QUnit.test('attachmentBox basic rendering', function (assert) { '' + '' + '
' + + '' + '
' + '', res_id: 7, + mockRPC: function (route, args) { + var result = this._super.apply(this, arguments); + if (args.method === 'read' && args.model === 'partner') { + return result.then(function (records) { + // here we force the attachment_count to 1 (which is correct + // actually), so that the attachment button is visible + // FIXME: this could be handled by an extension of mockRead + records[0].message_attachment_count = 1; + return records; + }); + } + return result; + }, }); var $button = form.$('.o_chatter_button_attachment'); assert.strictEqual($button.length, 1, "should have one attachment button"); - $button.click(); - assert.strictEqual(form.$('.o_mail_chatter_attachments').length, 1, + testUtils.dom.click($button); + assert.containsOnce(form, '.o_mail_chatter_attachments', "attachment widget should exist after a first click on the button"); - assert.strictEqual(form.$('.o_attachment_image').length, 1, "there should be an image preview"); - assert.strictEqual(form.$('.o_attachments_previews').length, 1, "there should be a list of previews"); - assert.strictEqual(form.$('.o_attachments_list').length, 1, "there should be a list of non previewable attachments"); + assert.containsOnce(form, '.o_attachment_image', "there should be an image preview"); + assert.containsOnce(form, '.o_attachments_previews', "there should be a list of previews"); + assert.containsOnce(form, '.o_attachments_list', "there should be a list of non previewable attachments"); assert.strictEqual(form.$('.o_attachment_title').text(), 'name1', "the image name should be correct"); // since there are two elements "Download name2"; one "name" and the other "txt" as text content, the following test @@ -328,13 +342,12 @@ QUnit.test('attachmentBox basic rendering', function (assert) { "the attachment name should be correct"); assert.ok(form.$('.o_attachment_image').css('background-image').indexOf('/web/image/1/160x160/?crop=true') >= 0, "the attachment image URL should be correct"); - assert.strictEqual(form.$('.o_attachment_download').eq(0).attr('href'), '/web/content/1?download=true', + assert.hasAttrValue(form.$('.o_attachment_download').eq(0), 'href', '/web/content/1?download=true', "the download URL of name1 must be correct"); - assert.strictEqual(form.$('.o_attachment_download').eq(1).attr('href'), '/web/content/2?download=true', + assert.hasAttrValue(form.$('.o_attachment_download').eq(1), 'href', '/web/content/2?download=true', "the download URL of name2 must be correct"); - $button.click(); - assert.strictEqual(form.$('.o_mail_chatter_attachments').length, 0, - "attachment widget should de destroyed after we reclick the button"); + testUtils.dom.click($button); + assert.containsNone(form, '.o_mail_chatter_attachments') form.destroy(); }); @@ -363,14 +376,14 @@ QUnit.test('chatter in create mode', function (assert) { }, }); - assert.strictEqual(form.$('.o_chatter').length, 1, + assert.containsOnce(form, '.o_chatter', "chatter should be displayed"); // entering create mode - form.$buttons.find('.o_form_button_create').click(); - assert.ok(form.$el.find('.o_form_view').hasClass('o_form_editable'), + testUtils.form.clickCreate(form); + assert.hasClass(form.$el.find('.o_form_view'),'o_form_editable', "we should be in create mode"); - assert.strictEqual(form.$('.o_chatter').length, 1, + assert.containsOnce(form, '.o_chatter', "chatter should still be displayed in create mode"); // topbar buttons disabled in create mode (e.g. 'send message') @@ -378,24 +391,24 @@ QUnit.test('chatter in create mode', function (assert) { "button should be disabled in create mode"); // chatter containing a single message with 'Creating a record...' - assert.strictEqual(form.$('.o_mail_thread').length, 1, + assert.containsOnce(form, '.o_mail_thread', "there should be a mail thread"); - assert.strictEqual(form.$('.o_thread_message').length, 1, + assert.containsOnce(form, '.o_thread_message', "there should be a single thread message"); assert.strictEqual(form.$('.o_thread_message_content').text().trim(), "Creating a new record...", "the content of the message should be 'Creating a new record...'"); // getting out of create mode by saving - form.$('.o_field_char').val('coucou').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('.o_field_char'), 'coucou'); + testUtils.form.clickSave(form); - assert.strictEqual(form.$('.o_chatter').length, 1, + assert.containsOnce(form, '.o_chatter', "chatter should still be displayed after saving from create mode"); // check if chatter buttons still work - form.$('.o_chatter_button_new_message').click(); - assert.strictEqual(form.$('.o_thread_composer:visible').length, 1, + testUtils.dom.click(form.$('.o_chatter_button_new_message')); + assert.containsOnce(form, '.o_thread_composer:visible', "chatter should be opened"); form.destroy(); @@ -430,25 +443,25 @@ QUnit.test('chatter rendering inside the sheet', function (assert) { }, }); - assert.strictEqual(form.$('.o_chatter').length, 1, + assert.containsOnce(form, '.o_chatter', "chatter should be displayed"); - form.$buttons.find('.o_form_button_create').click(); - assert.ok(form.$el.find('.o_form_view').hasClass('o_form_editable'), + testUtils.form.clickCreate(form); + assert.hasClass(form.$el.find('.o_form_view'),'o_form_editable', "we should be in create mode"); - assert.strictEqual(form.$('.o_chatter').length, 1, + assert.containsOnce(form, '.o_chatter', "chatter should be displayed"); - form.$('.o_field_char').val('coucou').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('.o_field_char'), 'coucou'); + testUtils.form.clickSave(form); - assert.strictEqual(form.$('.o_chatter').length, 1, + assert.containsOnce(form, '.o_chatter', "chatter should be displayed"); // check if chatter buttons still work - form.$('.o_chatter_button_new_message').click(); - assert.strictEqual(form.$('.o_thread_composer:visible').length, 1, + testUtils.dom.click(form.$('.o_chatter_button_new_message')); + assert.containsOnce(form, '.o_thread_composer:visible', "chatter should be opened"); form.destroy(); @@ -481,7 +494,7 @@ QUnit.test('kanban activity widget with no activity', function (assert) { assert.strictEqual(rpcCount, 1, '1 RPC (search_read) should have been done'); // click on the activity button - $record.find('.o_activity_btn').click(); + testUtils.dom.click($record.find('.o_activity_btn')); assert.strictEqual(rpcCount, 1, 'no RPC should have been done as there is no activity'); assert.strictEqual($record.find('.o_no_activity').length, 1, "should have no activity scheduled"); @@ -535,7 +548,7 @@ QUnit.test('kanban activity widget with an activity', function (assert) { assert.strictEqual(rpcCount, 1, '1 RPC (search_read) should have been done'); // click on the activity button - $record.find('.o_activity_btn').click(); + testUtils.dom.click($record.find('.o_activity_btn')); assert.strictEqual(rpcCount, 2, 'a read should have been done to fetch the activity details'); assert.strictEqual($record.find('.o_activity_title').length, 1, "should have an activity scheduled"); var label = $record.find('.o_activity_log .o_activity_color_today'); @@ -543,16 +556,16 @@ QUnit.test('kanban activity widget with an activity', function (assert) { assert.strictEqual(label.find('.badge-warning').text(), "1", "should display the correct count"); // click on the activity button to close the dropdown - $record.find('.o_activity_btn').click(); + testUtils.dom.click($record.find('.o_activity_btn')); assert.strictEqual(rpcCount, 2, 'no RPC should be done when closing the dropdown'); // click on the activity button to re-open dropdown - $record.find('.o_activity_btn').click(); + testUtils.dom.click($record.find('.o_activity_btn')); assert.strictEqual(rpcCount, 3, 'should have reloaded the activities'); // mark activity as done - $record.find('.o_mark_as_done').click(); - $record.find('.o_activity_popover_done').click(); + testUtils.dom.click($record.find('.o_mark_as_done')); + testUtils.dom.click($record.find('.o_activity_popover_done')); $record = kanban.$('.o_kanban_record').first(); // the record widget has been reset assert.strictEqual(rpcCount, 5, 'should have done an RPC to mark activity as done, and a read'); assert.ok($record.find('.o_mail_activity .o_activity_color_default:not(.o_activity_color_today)').length, @@ -605,17 +618,17 @@ QUnit.test('kanban activity widget popover test', function (assert) { var $record = kanban.$('.o_kanban_record').first(); - $record.find('.o_activity_btn').click(); + testUtils.dom.click($record.find('.o_activity_btn')); // Click on button and see popover no RPC call - $record.find('.o_mark_as_done').click(); + testUtils.dom.click($record.find('.o_mark_as_done')); assert.equal(rpcCount, 0, ""); // Click on discard no RPC call - $record.find('.o_activity_popover_discard').click(); + testUtils.dom.click($record.find('.o_activity_popover_discard')); assert.equal(rpcCount, 0, ""); // Click on button and then on done and schedule next // RPC call - $record.find('.o_activity_popover_done_next').click(); + testUtils.dom.click($record.find('.o_activity_popover_done_next')); assert.equal(rpcCount, 1, ""); kanban.destroy(); @@ -708,7 +721,7 @@ QUnit.test('chatter: post, receive and star messages', function (assert) { assert.ok(form.$('.o_chatter_topbar .o_chatter_button_log_note').length, "log note button should be available"); - assert.strictEqual(form.$('.o_thread_message').length, 1, "thread should contain one message"); + assert.containsOnce(form, '.o_thread_message', "thread should contain one message"); assert.ok(form.$('.o_thread_message:first().o_mail_discussion').length, "the message should be a discussion"); assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('A message') >= 0, @@ -717,12 +730,12 @@ QUnit.test('chatter: post, receive and star messages', function (assert) { "the message's author should be correct"); // send a message - form.$('.o_chatter_button_new_message').click(); - assert.ok(!$('.oe_chatter .o_thread_composer').hasClass('o_hidden'), "chatter should be opened"); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); + assert.isVisible($('.oe_chatter .o_thread_composer'), "chatter should be opened"); form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); - assert.ok($('.oe_chatter .o_thread_composer').hasClass('o_hidden'), "chatter should be closed"); - assert.strictEqual(form.$('.o_thread_message').length, 2, "thread should contain two messages"); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); + assert.isNotVisible($('.oe_chatter .o_thread_composer'), "chatter should be closed"); + assert.containsN(form, '.o_thread_message', 2, "thread should contain two messages"); assert.ok(form.$('.o_thread_message:first().o_mail_discussion').length, "the last message should be a discussion"); assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first message') >= 0, @@ -731,12 +744,12 @@ QUnit.test('chatter: post, receive and star messages', function (assert) { "the message's author should be correct"); // log a note - form.$('.o_chatter_button_log_note').click(); - assert.ok(!$('.oe_chatter .o_thread_composer').hasClass('o_hidden'), "chatter should be opened"); + testUtils.dom.click(form.$('.o_chatter_button_log_note')); + assert.isVisible($('.oe_chatter .o_thread_composer'), "chatter should be opened"); form.$('.oe_chatter .o_composer_text_field:first()').val("My first note"); - form.$('.oe_chatter .o_composer_button_send').click(); - assert.ok($('.oe_chatter .o_thread_composer').hasClass('o_hidden'), "chatter should be closed"); - assert.strictEqual(form.$('.o_thread_message').length, 3, "thread should contain three messages"); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); + assert.isNotVisible($('.oe_chatter .o_thread_composer'), "chatter should be closed"); + assert.containsN(form, '.o_thread_message', 3, "thread should contain three messages"); assert.ok(!form.$('.o_thread_message:first().o_mail_discussion').length, "the last message should not be a discussion"); assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first note') >= 0, @@ -747,17 +760,17 @@ QUnit.test('chatter: post, receive and star messages', function (assert) { // star message 2 assert.ok(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star.fa-star-o').length, "message 2 should not be starred"); - form.$('.o_thread_message[data-message-id=2] .o_thread_message_star').click(); + testUtils.dom.click(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star')); assert.ok(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star.fa-star').length, "message 2 should be starred"); // unstar message 2 - form.$('.o_thread_message[data-message-id=2] .o_thread_message_star').click(); + testUtils.dom.click(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star')); assert.ok(form.$('.o_thread_message[data-message-id=2] .o_thread_message_star.fa-star-o').length, "message 2 should not be starred"); // very basic test of mention - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); var $input = form.$('.oe_chatter .o_composer_text_field:first()'); $input.val('@'); // the cursor position must be set for the mention manager to detect that we are mentionning @@ -771,7 +784,7 @@ QUnit.test('chatter: post, receive and star messages', function (assert) { getSuggestionsDef .then(concurrency.delay.bind(concurrency, 0)) .then(function () { - assert.strictEqual(form.$('.o_mention_proposition:visible').length, 1, + assert.containsOnce(form, '.o_mention_proposition:visible', "there should be one mention suggestion"); assert.strictEqual(form.$('.o_mention_proposition').data('id'), 1, "suggestion's id should be correct"); @@ -822,12 +835,12 @@ QUnit.test('chatter: post a message disable the send button', function(assert) { }, }); - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); assert.notOk(form.$('.o_composer_button_send').prop('disabled'), "Send button should be enabled when posting a message"); form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); assert.notOk(form.$('.o_composer_button_send').prop('disabled'), "Send button should be enabled when posting another message"); form.destroy(); @@ -867,11 +880,11 @@ QUnit.test('chatter: post message failure keep message', function(assert) { }, }); - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); assert.notOk(form.$('.o_composer_button_send').prop('disabled'), "Send button should be enabled initially"); form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); assert.strictEqual(form.$('.o_composer_text_field').val(), "My first message", "Should keep unsent message in the composer on failure"); assert.notOk(form.$('.o_composer_button_send').prop('disabled'), @@ -1019,19 +1032,19 @@ QUnit.test('chatter: post a message and switch in edit mode', function (assert) }, }); - assert.strictEqual(form.$('.o_thread_message').length, 0, "thread should not contain messages"); + assert.containsNone(form, '.o_thread_message', "thread should not contain messages"); // send a message - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); - assert.strictEqual(form.$('.o_thread_message').length, 1, "thread should contain a message"); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); + assert.containsOnce(form, '.o_thread_message', "thread should contain a message"); assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first message') >= 0, "the message's body should be correct"); // switch in edit mode - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_thread_message').length, 1, "thread should contain a message"); + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_thread_message', "thread should contain a message"); assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('My first message') >= 0, "the message's body should be correct"); @@ -1072,12 +1085,12 @@ QUnit.test('chatter: discard changes on message post with post_refresh "always"' }); // Make record dirty - form.$('.o_form_sheet input').val('trululu').trigger('input'); + testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu'); // Send a message - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); var $modal = $('.modal-dialog'); assert.strictEqual($modal.length, 1, "should have a modal opened"); @@ -1149,12 +1162,12 @@ QUnit.test('chatter: discard changes on message post without post_refresh', func }); // Make record dirty - form.$('.o_form_sheet input').val('trululu').trigger('input'); + testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu'); // Send a message - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); var $modal = $('.modal-dialog'); assert.strictEqual($modal.length, 0, "should have no modal opened"); @@ -1227,10 +1240,10 @@ QUnit.test('chatter: discard changes on message post with post_refresh "recipien }); // Make record dirty - form.$('.o_form_sheet input').val('trululu').trigger('input'); + testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu'); // create a new message - form.$('.o_chatter_button_new_message').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); // Add a user as mention form.$('.oe_chatter .o_composer_text_field:first()').val("@"); @@ -1252,7 +1265,7 @@ QUnit.test('chatter: discard changes on message post with post_refresh "recipien form.$('input[type="checkbox"]').prop('checked', false); // send message - form.$('.oe_chatter .o_composer_button_send').click(); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); var $modal = $('.modal-dialog'); assert.strictEqual($modal.length, 1, "should have a modal opened"); @@ -1301,11 +1314,11 @@ QUnit.test('chatter: discard changes on opening full-composer', function (assert }); // Make record dirty - form.$('.o_form_sheet input').val('trululu').trigger('input'); + testUtils.fields.editInput(form.$('.o_form_sheet input'), 'trululu'); // Open full-composer - form.$('.o_chatter_button_new_message').click(); - form.$('.o_composer_button_full_composer').click(); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); + testUtils.dom.click(form.$('.o_composer_button_full_composer')); var $modal = $('.modal-dialog'); assert.strictEqual($modal.length, 1, "should have a modal opened"); @@ -1350,7 +1363,7 @@ QUnit.test('chatter in x2many form view', function (assert) { }, }); - form.$('.o_data_row:first').click(); + testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .o_form_view').length, 1, "should have open a form view in a modal"); @@ -1426,28 +1439,28 @@ QUnit.test('chatter: Attachment viewer', function (assert) { return this._super.apply(this, arguments); }, }); - assert.strictEqual(form.$('.o_thread_message .o_attachment').length, 4, + assert.containsN(form, '.o_thread_message .o_attachment', 4, "there should be three attachment on message"); - assert.strictEqual(form.$('.o_thread_message .o_attachment a').first().attr('href'), '/web/content/1?download=true', + assert.hasAttrValue(form.$('.o_thread_message .o_attachment a').first(), 'href', '/web/content/1?download=true', "image caption should have correct download link"); // click on first image attachement - form.$('.o_thread_message .o_attachment .o_image_box .o_image_overlay').first().click(); + testUtils.dom.click(form.$('.o_thread_message .o_attachment .o_image_box .o_image_overlay').first()); assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/1?unique=1&signature=999"]').length, 1, "Modal popup should open with first image src"); // click on next button - $('.modal .arrow.arrow-right.move_next span').click(); + testUtils.dom.click($('.modal .arrow.arrow-right.move_next span')); assert.strictEqual($('.o_modal_fullscreen img.o_viewer_img[data-src="/web/image/2?unique=1&signature=999"]').length, 1, "Modal popup should have now second image src"); assert.strictEqual($('.o_modal_fullscreen .o_viewer_toolbar .o_download_btn').length, 1, "Modal popup should have download button"); // close attachment popup - $('.o_modal_fullscreen .o_viewer-header .o_close_btn').click(); + testUtils.dom.click($('.o_modal_fullscreen .o_viewer-header .o_close_btn')); // click on pdf attachement - form.$('span:contains(Test PDF 1)').click(); + testUtils.dom.click(form.$('span:contains(Test PDF 1)')); assert.strictEqual($('.o_modal_fullscreen iframe[data-src*="/web/content/4"]').length, 1, "Modal popup should open with the pdf preview"); // close attachment popup - $('.o_modal_fullscreen .o_viewer-header .o_close_btn').click(); + testUtils.dom.click($('.o_modal_fullscreen .o_viewer-header .o_close_btn')); form.destroy(); }); @@ -1491,13 +1504,13 @@ QUnit.test('form activity widget: read RPCs', function (assert) { }); assert.strictEqual(nbReads, 1, "should have read the activities"); - assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1, + assert.containsOnce(form, '.o_mail_activity .o_thread_message', "should display an activity"); assert.strictEqual(form.$('.o_mail_activity .o_thread_message .o_activity_date').text(), 'Today', "the activity should be today"); - form.$buttons.find('.o_form_button_edit').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.form.clickSave(form); assert.strictEqual(nbReads, 1, "should not have re-read the activities"); @@ -1569,7 +1582,7 @@ QUnit.test('form activity widget with another x2many field in view', function (a res_id: 2, }); - assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1, + assert.containsOnce(form, '.o_mail_activity .o_thread_message', "should display an activity"); form.destroy(); @@ -1621,11 +1634,11 @@ QUnit.test('form activity widget: schedule next activity', function (assert) { }, }); //Schedule next activity - form.$('.o_mail_activity .o_mark_as_done[data-activity-id=1]').click(); - assert.strictEqual(form.$('.o_mail_activity_feedback.popover').length, 1, + testUtils.dom.click(form.$('.o_mail_activity .o_mark_as_done[data-activity-id=1]')); + assert.containsOnce(form, '.o_mail_activity_feedback.popover', "a feedback popover should be visible"); $('.o_mail_activity_feedback.popover textarea').val('everything is ok'); // write a feedback - form.$('.o_activity_popover_done_next').click(); // schedule next activity + testUtils.dom.click(form.$('.o_activity_popover_done_next')); form.destroy(); }); @@ -1686,10 +1699,10 @@ QUnit.test('form activity widget: edit next activity', function (assert) { }, }, }); - assert.strictEqual(form.$('.o_mail_activity .o_mail_info strong:eq(1)').text(), " Type 2", + assert.strictEqual(form.$('.o_mail_activity .o_mail_info strong:eq(1)').text(), " Type 2", "Initial type should be Type 2"); - form.$('.o_mail_activity .o_edit_activity[data-activity-id=1]').click(); - assert.strictEqual(form.$('.o_mail_activity .o_mail_info strong:eq(1)').text(), " Type 1", + testUtils.dom.click(form.$('.o_mail_activity .o_edit_activity[data-activity-id=1]')); + assert.strictEqual(form.$('.o_mail_activity .o_mail_info strong:eq(1)').text(), " Type 1", "After edit type should be Type 1"); form.destroy(); }); @@ -1752,12 +1765,12 @@ QUnit.test('form activity widget: clic mail template', function (assert) { }, }, }); - assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1, + assert.containsOnce(form, '.o_mail_activity .o_thread_message', "we should have one activity"); - assert.strictEqual(form.$('.o_activity_template_preview').length, 1, + assert.containsOnce(form, '.o_activity_template_preview', "Activity should contains one mail template"); - form.$('.o_activity_template_preview[data-template-id=100]').click(); - assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1, + testUtils.dom.click(form.$('.o_activity_template_preview[data-template-id=100]')); + assert.containsOnce(form, '.o_mail_activity .o_thread_message', "activity should still be there"); form.destroy(); }); @@ -1797,13 +1810,13 @@ QUnit.test('form activity widget: schedule activity does not discard changes', f }); // update value of foo field - form.$('.o_field_widget[name=foo]').val('new value').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'new value'); // schedule an activity (this triggers a do_action) - form.$('.o_chatter_button_schedule_activity').click(); + testUtils.dom.click(form.$('.o_chatter_button_schedule_activity')); // save the record - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -1887,12 +1900,12 @@ QUnit.test('form activity widget: mark as done and remove', function (assert) { }, }); - assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 2, + assert.containsN(form, '.o_mail_activity .o_thread_message', 2, "there should be two activities"); // remove activity 1 - form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]').click(); - assert.strictEqual(form.$('.o_mail_activity .o_thread_message').length, 1, + testUtils.dom.click(form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]')); + assert.containsOnce(form, '.o_mail_activity .o_thread_message', "there should be one remaining activity"); assert.ok(!form.$('.o_mail_activity .o_unlink_activity[data-activity-id=1]').length, "activity 1 should have been removed"); @@ -1900,16 +1913,15 @@ QUnit.test('form activity widget: mark as done and remove', function (assert) { // mark activity done assert.ok(!form.$('.o_mail_thread .o_thread_message').length, "there should be no chatter message"); - form.$('.o_mail_activity .o_mark_as_done[data-activity-id=2]').click(); - assert.strictEqual(form.$('.o_mail_activity_feedback.popover').length, 1, + testUtils.dom.click(form.$('.o_mail_activity .o_mark_as_done[data-activity-id=2]')); + assert.containsOnce(form, '.o_mail_activity_feedback.popover', "a feedback popover should be visible"); $('.o_mail_activity_feedback.popover textarea').val('everything is ok'); // write a feedback - form.$('.o_activity_popover_done').click(); // send feedback - assert.strictEqual(form.$('.o_mail_activity_feedback.popover').length, 0, - "the feedback popover should be closed"); + testUtils.dom.click(form.$('.o_activity_popover_done')); + assert.containsNone(form, '.o_mail_activity_feedback.popover') assert.ok(!form.$('.o_mail_activity .o_thread_message').length, "there should be no more activity"); - assert.strictEqual(form.$('.o_mail_thread .o_thread_message').length, 1, + assert.containsOnce(form, '.o_mail_thread .o_thread_message', "a chatter message should have been generated"); assert.strictEqual(form.$('.o_thread_message:contains(The activity has been done)').length, 1, "the message's body should be correct"); @@ -2002,29 +2014,29 @@ QUnit.test('followers widget: follow/unfollow, edit subtypes', function (assert) 'should display the "Follow" button'); // click to follow the document - form.$('.o_followers_follow_button').click(); + testUtils.dom.click(form.$('.o_followers_follow_button')); assert.strictEqual(form.$('.o_followers_count').text(), "1", 'should have one follower'); assert.ok(form.$('.o_followers_follow_button.o_followers_following').length, 'should display the "Following/Unfollow" button'); - assert.strictEqual(form.$('.o_followers_list .o_partner').length, 1, + assert.containsOnce(form, '.o_followers_list .o_partner', "there should be one follower in the follower dropdown"); // edit the subtypes - assert.strictEqual(form.$('.o_subtypes_list .o_subtype').length, 3, + assert.containsN(form, '.o_subtypes_list .o_subtype', 3, 'subtype list should contain 3 subtypes'); - assert.strictEqual(form.$('.o_subtypes_list .o_subtype_checkbox:checked').length, 2, + assert.containsN(form, '.o_subtypes_list .o_subtype_checkbox:checked', 2, 'two subtypes should be checked by default'); - form.$('.o_subtypes_list .dropdown-toggle').click(); // click to open the dropdown + testUtils.dom.click(form.$('.o_subtypes_list .dropdown-toggle')); assert.ok(form.$('.o_subtypes_list.show').length, 'dropdown should be opened'); - form.$('.o_subtypes_list .o_subtype input[data-id=2]').click(); // uncheck second subtype + testUtils.dom.click(form.$('.o_subtypes_list .o_subtype input[data-id=2]')); assert.ok(form.$('.o_subtypes_list.show').length, 'dropdown should remain opened'); assert.ok(!form.$('.o_subtypes_list .o_subtype_checkbox[data-id=2]:checked').length, 'second subtype should now be unchecked'); // click to unfollow - form.$('.o_followers_follow_button').click(); // click to open the dropdown + testUtils.dom.click(form.$('.o_followers_follow_button')); assert.ok($('.modal').length, 'a confirm modal should be opened'); - $('.modal .modal-footer .btn-primary').click(); // click on 'OK' + testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_followers_count').text(), "0", 'should have no followers'); assert.ok(form.$('.o_followers_follow_button.o_followers_notfollow').length, 'should display the "Follow" button'); @@ -2093,7 +2105,7 @@ QUnit.test('followers widget: do not display follower duplications', function (a assert.strictEqual(form.$('.o_followers_count').text(), '2', "should have 2 followers"); - assert.strictEqual(form.$('.o_followers_list .o_partner').length, 2, + assert.containsN(form, '.o_followers_list .o_partner', 2, "there should be 2 followers in the follower dropdown"); form.destroy(); @@ -2209,19 +2221,19 @@ QUnit.test('chatter: do not duplicate messages on (un)star message', function (a session: {}, }); - assert.strictEqual(form.$('.o_thread_message').length, 1, + assert.containsOnce(form, '.o_thread_message', "there should be a single message in the chatter"); assert.ok(form.$('.o_thread_message .o_thread_message_star.fa-star-o').length, "message should not be starred"); // star message - form.$('.o_thread_message .o_thread_message_star').click(); - assert.strictEqual(form.$('.o_thread_message').length, 1, + testUtils.dom.click(form.$('.o_thread_message .o_thread_message_star')); + assert.containsOnce(form, '.o_thread_message', "there should still be a single message in the chatter after starring the message"); // unstar message - form.$('.o_thread_message .o_thread_message_star').click(); - assert.strictEqual(form.$('.o_thread_message').length, 1, + testUtils.dom.click(form.$('.o_thread_message .o_thread_message_star')); + assert.containsOnce(form, '.o_thread_message', "there should still be a single message in the chatter after unstarring the message"); //cleanup @@ -2263,9 +2275,9 @@ QUnit.test('chatter: new messages on document without any "display_name"', funct session: {}, }); - assert.strictEqual(form.$('.o_thread_message').length, 1, + assert.containsOnce(form, '.o_thread_message', "should have a single message in the chatter"); - assert.strictEqual(form.$('.o_thread_message[data-message-id="1"]').length, 1, + assert.containsOnce(form, '.o_thread_message[data-message-id="1"]', "single message should have ID 1"); // Simulate a new message in the chatter @@ -2285,11 +2297,11 @@ QUnit.test('chatter: new messages on document without any "display_name"', funct form.reload(); - assert.strictEqual(form.$('.o_thread_message').length, 2, + assert.containsN(form, '.o_thread_message', 2, "should have a two messages in the chatter after reload"); - assert.strictEqual(form.$('.o_thread_message[data-message-id="1"]').length, 1, + assert.containsOnce(form, '.o_thread_message[data-message-id="1"]', "one of the message should have ID 1"); - assert.strictEqual(form.$('.o_thread_message[data-message-id="2"]').length, 1, + assert.containsOnce(form, '.o_thread_message[data-message-id="2"]', "the other message should have ID 2"); //cleanup @@ -2399,25 +2411,25 @@ QUnit.test('chatter: suggested partner auto-follow on message post', function (a session: {}, }); - assert.strictEqual(form.$('.o_thread_message').length, 1, "thread should contain one message"); + assert.containsOnce(form, '.o_thread_message', "thread should contain one message"); assert.ok(form.$('.o_thread_message:first().o_mail_discussion').length, "the message should be a discussion"); assert.ok(form.$('.o_thread_message:first() .o_thread_message_core').text().indexOf('A message') >= 0, "the message's body should be correct"); assert.ok(form.$('.o_thread_message:first() .o_mail_info').text().indexOf('John Doe') >= 0, "the message's author should be correct"); - assert.strictEqual(form.$('.o_followers').length, 1, + assert.containsOnce(form, '.o_followers', "should display follower widget"); assert.strictEqual(form.$('.o_followers_count').text(), "1", "should have a single follower (widget counter)"); - assert.strictEqual(form.$('.o_followers_list > div.o_partner').length, 1, + assert.containsOnce(form, '.o_followers_list > div.o_partner', "should have a single follower (listed partners)"); assert.strictEqual(form.$('.o_followers_list > div.o_partner > a').text(), "Admin", "should have 'Admin' as follower"); // open composer - form.$('.o_chatter_button_new_message').click(); - assert.ok(!$('.oe_chatter .o_thread_composer').hasClass('o_hidden'), "chatter should be opened"); + testUtils.dom.click(form.$('.o_chatter_button_new_message')); + assert.isVisible($('.oe_chatter .o_thread_composer'), "chatter should be opened"); assert.strictEqual($('.o_composer_suggested_partners').length, 1, "should display suggested partners"); assert.strictEqual($('.o_composer_suggested_partners > div').length, 1, @@ -2433,11 +2445,11 @@ QUnit.test('chatter: suggested partner auto-follow on message post', function (a // send message form.$('.oe_chatter .o_composer_text_field:first()').val("My first message"); - form.$('.oe_chatter .o_composer_button_send').click(); + testUtils.dom.click(form.$('.oe_chatter .o_composer_button_send')); assert.strictEqual(form.$('.o_followers_count').text(), "2", "should have a two followers (widget counter)"); - assert.strictEqual(form.$('.o_followers_list > div.o_partner').length, 2, + assert.containsN(form, '.o_followers_list > div.o_partner', 2, "should have two followers (listed partners)"); assert.strictEqual(form.$('.o_followers_list > div.o_partner > a[data-oe-id="5"]').text(), "Admin", @@ -2630,12 +2642,12 @@ QUnit.test('fieldmany2many tags email', function (assert) { }).then(function (form) { // should read it 3 times (1 with the form view, one with the form dialog and one after save) assert.verifySteps([[12, 14], [14], [14]]); - assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0').length, 2, + assert.containsN(form, '.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0', 2, "two tags should be present"); var firstTag = form.$('.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0').first(); assert.strictEqual(firstTag.find('.o_badge_text').text(), "gold", "tag should only show display_name"); - assert.strictEqual(firstTag.find('.o_badge_text').attr('title'), "coucou@petite.perruche", + assert.hasAttrValue(firstTag.find('.o_badge_text'), 'title', "coucou@petite.perruche", "tag should show email address on mouse hover"); form.destroy(); done(); @@ -2649,8 +2661,8 @@ QUnit.test('fieldmany2many tags email', function (assert) { "there should be an email field in the modal"); // set the email and save the modal (will render the form view) - $('.modal-body.o_act_window input[name="email"]').val('coucou@petite.perruche').trigger('input'); - $('.modal-footer .btn-primary').click(); + testUtils.fields.editInput($('.modal-body.o_act_window input[name="email"]'), 'coucou@petite.perruche'); + testUtils.dom.click($('.modal-footer .btn-primary')); }); QUnit.test('fieldmany2many tags email (edition)', function (assert) { @@ -2685,13 +2697,12 @@ QUnit.test('fieldmany2many tags email (edition)', function (assert) { }); assert.verifySteps([[12]]); - assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0').length, 1, + assert.containsOnce(form, '.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0', "should contain one tag"); // add an other existing tag - var $input = form.$('.o_field_many2manytags input'); - $input.click(); // opens the dropdown - $input.autocomplete('widget').find('li:first').click(); // add 'silver' + testUtils.fields.many2one.clickOpenDropdown('timmy'); + testUtils.fields.many2one.clickHighlightedItem('timmy'); assert.strictEqual($('.modal-body.o_act_window').length, 1, "there should be one modal opened to edit the empty email"); @@ -2701,10 +2712,10 @@ QUnit.test('fieldmany2many tags email (edition)', function (assert) { "there should be an email field in the modal"); // set the email and save the modal (will rerender the form view) - $('.modal-body.o_act_window input[name="email"]').val('coucou@petite.perruche').trigger('input'); - $('.modal-footer .btn-primary').click(); + testUtils.fields.editInput($('.modal-body.o_act_window input[name="email"]'), 'coucou@petite.perruche'); + testUtils.dom.click($('.modal-footer .btn-primary')); - assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0').length, 2, + assert.containsN(form, '.o_field_many2manytags[name="timmy"] .badge.o_tag_color_0', 2, "should contain the second tag"); // should have read [14] three times: when opening the dropdown, when opening the modal, and // after the save diff --git a/addons/mail/static/tests/discuss_mobile_tests.js b/addons/mail/static/tests/discuss_mobile_tests.js index 2f0fd5de647..498c3fb42ef 100644 --- a/addons/mail/static/tests/discuss_mobile_tests.js +++ b/addons/mail/static/tests/discuss_mobile_tests.js @@ -3,6 +3,8 @@ odoo.define('mail.discuss_mobile_tests', function (require) { var mailTestUtils = require('mail.testUtils'); +var testUtils = require('web.test_utils'); + var createDiscuss = mailTestUtils.createDiscuss; QUnit.module('mail', {}, function () { @@ -35,55 +37,55 @@ QUnit.test('mobile basic rendering', function (assert) { services: this.services, }).then(function (discuss) { // test basic rendering in mobile - assert.strictEqual(discuss.$('.o_mail_discuss_content .o_mail_no_content').length, 1, + assert.containsOnce(discuss, '.o_mail_discuss_content .o_mail_no_content', "should display the no content message"); - assert.strictEqual(discuss.$('.o_mail_mobile_tabs').length, 1, + assert.containsOnce(discuss, '.o_mail_mobile_tabs', "should have rendered the tabs"); - assert.ok(discuss.$('.o_mail_mobile_tab[data-type=mailbox_inbox]').hasClass('active'), + assert.hasClass(discuss.$('.o_mail_mobile_tab[data-type=mailbox_inbox]'),'active', "should be in inbox tab"); - assert.strictEqual(discuss.$('.o_mail_discuss_mobile_mailboxes_buttons:visible').length, 1, + assert.containsOnce(discuss, '.o_mail_discuss_mobile_mailboxes_buttons:visible', "inbox/starred buttons should be visible"); - assert.ok(discuss.$('.o_mail_discuss_mobile_mailboxes_buttons .o_mailbox_inbox_item[data-type=mailbox_inbox]').hasClass('btn-primary'), + assert.hasClass(discuss.$('.o_mail_discuss_mobile_mailboxes_buttons .o_mailbox_inbox_item[data-type=mailbox_inbox]'),'btn-primary', "should be in inbox"); - assert.ok($('.o_mail_discuss_button_dm_chat').hasClass('d-none'), + assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none', "should have invisible button 'New Message'"); - assert.ok($('.o_mail_discuss_button_public').hasClass('d-none'), + assert.hasClass($('.o_mail_discuss_button_public'),'d-none', "should have invisible button 'New Channel'"); // move to 'Chat' tab - discuss.$('.o_mail_mobile_tab[data-type=dm_chat]').click(); - assert.ok(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]').hasClass('active'), + testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]')); + assert.hasClass(discuss.$('.o_mail_mobile_tab[data-type=dm_chat]'),'active', "should be in 'Chat' tab"); - assert.strictEqual(discuss.$('.o_mail_discuss_content .o_mail_no_content').length, 0, + assert.containsNone(discuss, '.o_mail_discuss_content .o_mail_no_content', "should display the no content message"); assert.strictEqual($('.o_mail_discuss_button_dm_chat').length, 1, "should have a button to open DM chat in 'Chat' tab"); - assert.notOk($('.o_mail_discuss_button_dm_chat').hasClass('d-none'), + assert.doesNotHaveClass($('.o_mail_discuss_button_dm_chat'), 'd-none', "should be visible in 'Chat' tab"); - assert.ok($('.o_mail_discuss_button_public').hasClass('d-none'), + assert.hasClass($('.o_mail_discuss_button_public'),'d-none', "should have invisible button 'New Channel' in 'Chat' tab"); - $('.o_mail_discuss_button_dm_chat').click(); // click to open a chat - assert.strictEqual(discuss.$('.o_mail_add_thread input:visible').length, 1, + testUtils.dom.click($('.o_mail_discuss_button_dm_chat')); + assert.containsOnce(discuss, '.o_mail_add_thread input:visible', "should display the input to add a channel"); // move to 'Channels' tab - discuss.$('.o_mail_mobile_tab[data-type=public]').click(); - assert.ok($('.o_mail_discuss_button_dm_chat').hasClass('d-none'), + testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=public]')); + assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none', "should have invisible button 'New Message' in 'Channels' tab"); - assert.notOk($('.o_mail_discuss_button_public').hasClass('d-none'), + assert.doesNotHaveClass($('.o_mail_discuss_button_public'), 'd-none', "should have visible button 'New Channel' in 'Channels' tab"); - $('.o_mail_discuss_button_public').click(); // click to open a chat - assert.strictEqual(discuss.$('.o_mail_add_thread input:visible').length, 1, + testUtils.dom.click($('.o_mail_discuss_button_public')); + assert.containsOnce(discuss, '.o_mail_add_thread input:visible', "should display the input to add a channel"); // move to Private Channels tab - discuss.$('.o_mail_mobile_tab[data-type=private]').click(); - assert.ok($('.o_mail_discuss_button_dm_chat').hasClass('d-none'), + testUtils.dom.click(discuss.$('.o_mail_mobile_tab[data-type=private]')); + assert.hasClass($('.o_mail_discuss_button_dm_chat'),'d-none', "should have invisible button 'New Message' in 'Private Channels' tab"); - assert.notOk($('.o_mail_discuss_button_private').hasClass('d-none'), + assert.doesNotHaveClass($('.o_mail_discuss_button_private'), 'd-none', "should have invisible button 'New Channel' in 'Private Channels' tab"); - $('.o_mail_discuss_button_private').click(); // click to open a chat - assert.strictEqual(discuss.$('.o_mail_add_thread input:visible').length, 1, + testUtils.dom.click($('.o_mail_discuss_button_private')); + assert.containsOnce(discuss, '.o_mail_add_thread input:visible', "should display the input to add a channel"); discuss.destroy(); diff --git a/addons/mail/static/tests/discuss_moderation_tests.js b/addons/mail/static/tests/discuss_moderation_tests.js index 4d8e48b4dcb..9c3807527ce 100644 --- a/addons/mail/static/tests/discuss_moderation_tests.js +++ b/addons/mail/static/tests/discuss_moderation_tests.js @@ -4,6 +4,8 @@ odoo.define('mail.discuss_moderation_tests', function (require) { var Thread = require('mail.model.Thread'); var mailTestUtils = require('mail.testUtils'); +var testUtils = require('web.test_utils'); + var createDiscuss = mailTestUtils.createDiscuss; QUnit.module('mail', {}, function () { @@ -102,7 +104,7 @@ QUnit.test('moderator: display moderation box', function (assert) { .then(function (discuss) { var moderationBoxSelector = '.o_mail_discuss_item' + '[data-thread-id="mailbox_moderation"]'; - assert.strictEqual(discuss.$(moderationBoxSelector).length, 1, + assert.containsOnce(discuss, moderationBoxSelector, "there should be a moderation mailbox"); discuss.destroy(); done(); @@ -154,7 +156,7 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct "the mailbox counter of the moderation mailbox should display '1'"); // 1. go to moderation mailbox - $moderationBox.click(); + testUtils.dom.click($moderationBox); var $message = discuss.$('.o_thread_message'); // check message assert.strictEqual($message.length, 1, @@ -168,27 +170,27 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct assert.notOk($message.find('.moderation_checkbox').prop('checked'), false, "the moderation checkbox should be unchecked by default"); // check moderation actions next to message - assert.strictEqual(discuss.$('.o_thread_message_moderation').length, 5, + assert.containsN(discuss, '.o_thread_message_moderation', 5, "there should be 5 contextual moderation decisions next to the message"); - assert.strictEqual(discuss.$('.o_thread_message_moderation[data-decision="accept"]').length, 1, + assert.containsOnce(discuss, '.o_thread_message_moderation[data-decision="accept"]', "there should be a contextual moderation decision to accept the message"); - assert.strictEqual(discuss.$('.o_thread_message_moderation[data-decision="reject"]').length, 1, + assert.containsOnce(discuss, '.o_thread_message_moderation[data-decision="reject"]', "there should be a contextual moderation decision to reject the message"); - assert.strictEqual(discuss.$('.o_thread_message_moderation[data-decision="discard"]').length, 1, + assert.containsOnce(discuss, '.o_thread_message_moderation[data-decision="discard"]', "there should be a contextual moderation decision to discard the message"); - assert.strictEqual(discuss.$('.o_thread_message_moderation[data-decision="allow"]').length, 1, + assert.containsOnce(discuss, '.o_thread_message_moderation[data-decision="allow"]', "there should be a contextual moderation decision to allow the user of the message)"); - assert.strictEqual(discuss.$('.o_thread_message_moderation[data-decision="ban"]').length, 1, + assert.containsOnce(discuss, '.o_thread_message_moderation[data-decision="ban"]', "there should be a contextual moderation decision to ban the user of the message"); // check select all (enabled) / unselect all (disabled) buttons assert.strictEqual($('.o_mail_discuss_button_select_all').length, 1, "there should be a 'Select All' button in the control panel"); - assert.notOk($('.o_mail_discuss_button_select_all').hasClass('disabled'), + assert.doesNotHaveClass($('.o_mail_discuss_button_select_all'), 'disabled', "the 'Select All' button should not be disabled"); assert.strictEqual($('.o_mail_discuss_button_unselect_all').length, 1, "there should be a 'Unselect All' button in the control panel"); - assert.ok($('.o_mail_discuss_button_unselect_all').hasClass('disabled'), + assert.hasClass($('.o_mail_discuss_button_unselect_all'),'disabled', "the 'Unselect All' button should be disabled"); // check moderate all buttons (invisible) var moderateAllSelector = '.o_mail_discuss_button_moderate_all'; @@ -196,36 +198,36 @@ QUnit.test('moderator: moderated channel with pending moderation message', funct "there should be 3 buttons to moderate selected messages in the control panel"); assert.strictEqual($(moderateAllSelector + '[data-decision="accept"]').length, 1, "there should one moderate button to accept messages pending moderation"); - assert.ok($(moderateAllSelector + '[data-decision="accept"]').hasClass('d-none'), + assert.hasClass($(moderateAllSelector + '[data-decision="accept"]'),'d-none', 'the moderate button "Accept" should be invisible by default'); assert.strictEqual($(moderateAllSelector + '[data-decision="reject"]').length, 1, "there should one moderate button to reject messages pending moderation"); - assert.ok($(moderateAllSelector + '[data-decision="reject"]').hasClass('d-none'), + assert.hasClass($(moderateAllSelector + '[data-decision="reject"]'),'d-none', 'the moderate button "Reject" should be invisible by default'); assert.strictEqual($(moderateAllSelector + '[data-decision="discard"]').length, 1, "there should one moderate button to discard messages pending moderation"); - assert.ok($(moderateAllSelector + '[data-decision="discard"]').hasClass('d-none'), + assert.hasClass($(moderateAllSelector + '[data-decision="discard"]'),'d-none', 'the moderate button "Discard" should be invisible by default'); // click on message moderation checkbox - $message.find('.moderation_checkbox').click(); + testUtils.dom.click($message.find('.moderation_checkbox')); assert.ok($message.find('.moderation_checkbox').prop('checked'), "the moderation checkbox should become checked after click"); // check select all (disabled) / unselect all buttons (enabled) - assert.ok($('.o_mail_discuss_button_select_all').hasClass('disabled'), + assert.hasClass($('.o_mail_discuss_button_select_all'),'disabled', "the 'Select All' button should be disabled"); - assert.notOk($('.o_mail_discuss_button_unselect_all').hasClass('disabled'), + assert.doesNotHaveClass($('.o_mail_discuss_button_unselect_all'), 'disabled', "the 'Unselect All' button should not be disabled"); // check moderate all buttons updated (visible) - assert.notOk($(moderateAllSelector + '[data-decision="accept"]').hasClass('d-none'), + assert.doesNotHaveClass($(moderateAllSelector + '[data-decision="accept"]'), 'd-none', 'the moderate button "Accept" should become visible'); - assert.notOk($(moderateAllSelector + '[data-decision="reject"]').hasClass('d-none'), + assert.doesNotHaveClass($(moderateAllSelector + '[data-decision="reject"]'), 'd-none', 'the moderate button "Reject" should become visible'); - assert.notOk($(moderateAllSelector + '[data-decision="discard"]').hasClass('d-none'), + assert.doesNotHaveClass($(moderateAllSelector + '[data-decision="discard"]'), 'd-none', 'the moderate button "Discard" should become visible'); // 2. go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); $message = discuss.$('.o_thread_message'); // check correct message assert.strictEqual($message.length, 1, @@ -292,7 +294,7 @@ QUnit.test('moderator: accept pending moderation message', function (assert) { var $moderationBox = discuss.$( '.o_mail_discuss_item' + '[data-thread-id="mailbox_moderation"]'); - $moderationBox.click(); + testUtils.dom.click($moderationBox); // check there is a message to moderate var $message = discuss.$('.o_thread_message'); assert.strictEqual($message.length, 1, @@ -302,16 +304,16 @@ QUnit.test('moderator: accept pending moderation message', function (assert) { assert.strictEqual($message.find('.moderation_checkbox').length, 1, "the message should have a moderation checkbox"); // accept the message pending moderation - discuss.$('.o_thread_message_moderation[data-decision="accept"]').click(); + testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="accept"]')); assert.verifySteps(['moderate']); // stop the fadeout animation and immediately remove the element discuss.$('.o_thread_message').stop(false, true); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, + assert.containsNone(discuss, '.o_thread_message', "should now have no message displayed in moderation box"); // 2. go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); $message = discuss.$('.o_thread_message'); // check message is there and has no moderate checkbox assert.strictEqual($message.length, 1, @@ -382,7 +384,7 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio var $moderationBox = discuss.$( '.o_mail_discuss_item' + '[data-thread-id="mailbox_moderation"]'); - $moderationBox.click(); + testUtils.dom.click($moderationBox); // check there is a message to moderate var $message = discuss.$('.o_thread_message'); assert.strictEqual($message.length, 1, @@ -392,7 +394,7 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio assert.strictEqual($message.find('.moderation_checkbox').length, 1, "the message should have a moderation checkbox"); // reject the message pending moderation - discuss.$('.o_thread_message_moderation[data-decision="reject"]').click(); + testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="reject"]')); // check reject dialog prompt assert.strictEqual($('.modal-dialog').length, 1, @@ -402,14 +404,14 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio var $messageTitle = $('.modal-body input[id="message_title"]'); assert.strictEqual($messageTitle.length, 1, "should have a title of message for rejecting the message"); - assert.strictEqual($messageTitle.attr('placeholder'), "Subject", + assert.hasAttrValue($messageTitle, 'placeholder', "Subject", "message title for reject reason should have correct placeholder"); assert.strictEqual($messageTitle.val(), "Message Rejected", "message title for reject reason should have correct default value"); var $messageBody = $('.modal-body textarea[id="reject_message"]'); assert.strictEqual($messageBody.length, 1, "should have a body of message for rejecting the message"); - assert.strictEqual($messageBody.attr('placeholder'), "Mail Body", + assert.hasAttrValue($messageBody, 'placeholder', "Mail Body", "message body for reject reason should have correct placeholder"); assert.strictEqual($messageBody.text(), "Your message was rejected by moderator.", "message body for reject reason should have correct default text content"); @@ -417,18 +419,17 @@ QUnit.test('moderator: reject pending moderation message (reject with explanatio "should have a send button on the reject dialog"); // send mesage - $('.modal-footer button').click(); + testUtils.dom.click($('.modal-footer button')); assert.verifySteps(['moderate']); // // stop the fadeout animation and immediately remove the element discuss.$('.o_thread_message').stop(false, true); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, + assert.containsNone(discuss, '.o_thread_message', "should now have no message displayed in moderation box"); // 2. go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, - "should now have no message displayed in moderated channel"); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); + assert.containsNone(discuss, '.o_thread_message') discuss.destroy(); done(); @@ -486,7 +487,7 @@ QUnit.test('moderator: discard pending moderation message (reject without explan var $moderationBox = discuss.$( '.o_mail_discuss_item' + '[data-thread-id="mailbox_moderation"]'); - $moderationBox.click(); + testUtils.dom.click($moderationBox); // check there is a message to moderate var $message = discuss.$('.o_thread_message'); assert.strictEqual($message.length, 1, @@ -496,7 +497,7 @@ QUnit.test('moderator: discard pending moderation message (reject without explan assert.strictEqual($message.find('.moderation_checkbox').length, 1, "the message should have a moderation checkbox"); // discard the message pending moderation - discuss.$('.o_thread_message_moderation[data-decision="discard"]').click(); + testUtils.dom.click(discuss.$('.o_thread_message_moderation[data-decision="discard"]')); // check discard dialog prompt assert.strictEqual($('.modal-dialog').length, 1, @@ -512,18 +513,17 @@ QUnit.test('moderator: discard pending moderation message (reject without explan "should have a cancel button in the dialog for discard"); // discard mesage - $('.modal-footer button.btn-primary').click(); + testUtils.dom.click($('.modal-footer button.btn-primary')); assert.verifySteps(['moderate']); // stop the fadeout animation and immediately remove the element discuss.$('.o_thread_message').stop(false, true); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, + assert.containsNone(discuss, '.o_thread_message', "should now have no message displayed in moderation box"); // 2. go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, - "should now have no message displayed in moderated channel"); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); + assert.containsNone(discuss, '.o_thread_message') discuss.destroy(); done(); @@ -586,10 +586,10 @@ QUnit.test('author: send message in moderated channel', function (assert) { objectDiscuss = discuss; // go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); // post a message discuss.$('.o_composer_input textarea').first().val("some text"); - discuss.$('.o_composer_send button').click(); + testUtils.dom.click(discuss.$('.o_composer_send button')); messagePostDef .then(function () { @@ -649,7 +649,7 @@ QUnit.test('author: sent message accepted in moderated channel', function (asser .then(function (discuss) { // go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); // check message is pending var $message = discuss.$('.o_thread_message'); assert.strictEqual($message.length, 1, @@ -683,7 +683,7 @@ QUnit.test('author: sent message accepted in moderated channel', function (asser "message should still have ID returned from 'message_post'"); assert.strictEqual($message.find('.o_thread_author').text().trim(), "Someone", "message should still have correct author displayed name"); - assert.strictEqual(discuss.$('.o_thread_icons i.text-danger').length, 0, + assert.containsNone(discuss, '.o_thread_icons i.text-danger', "the message should not be in pending moderation anymore"); discuss.destroy(); @@ -730,7 +730,7 @@ QUnit.test('author: sent message rejected in moderated channel', function (asser .then(function (discuss) { // go to channel 'general' - discuss.$('.o_mail_discuss_item[data-thread-id="1"]').click(); + testUtils.dom.click(discuss.$('.o_mail_discuss_item[data-thread-id="1"]')); // check message is pending var $message = discuss.$('.o_thread_message'); assert.strictEqual($message.length, 1, @@ -753,7 +753,7 @@ QUnit.test('author: sent message rejected in moderated channel', function (asser discuss.call('bus_service', 'trigger', 'notification', [notification]); // // check no message - assert.strictEqual(discuss.$('.o_thread_message').length, 0, + assert.containsNone(discuss, '.o_thread_message', "message should be removed from channel after reject"); discuss.destroy(); diff --git a/addons/mail/static/tests/discuss_tests.js b/addons/mail/static/tests/discuss_tests.js index 68aee02ded6..1684ad821df 100644 --- a/addons/mail/static/tests/discuss_tests.js +++ b/addons/mail/static/tests/discuss_tests.js @@ -90,9 +90,9 @@ QUnit.test('basic rendering', function (assert) { assert.strictEqual($sidebar.length, 1, "should have rendered a sidebar"); - assert.strictEqual(discuss.$('.o_mail_discuss_content').length, 1, + assert.containsOnce(discuss, '.o_mail_discuss_content', "should have rendered the content"); - assert.strictEqual(discuss.$('.o_mail_no_content').length, 1, + assert.containsOnce(discuss, '.o_mail_no_content', "should display no content message"); var $inbox = $sidebar.find('.o_mail_discuss_item[data-thread-id=mailbox_inbox]'); @@ -128,7 +128,7 @@ QUnit.test('searchview options visibility', function (assert) { assert.strictEqual($searchviewOptions.css('display'), 'block', "search options should be visible by default"); - $searchviewOptionsToggler.click(); + testUtils.dom.click($searchviewOptionsToggler); assert.strictEqual($searchviewOptions.css('display'), 'none', "search options should be hidden after clicking on search option toggler"); @@ -172,7 +172,7 @@ QUnit.test('searchview filter messages', function (assert) { }, }) .then(function (discuss) { - assert.strictEqual(discuss.$('.o_thread_message').length, 2, + assert.containsN(discuss, '.o_thread_message', 2, "there should be two messages in the inbox mailbox"); assert.strictEqual($('.o_searchview_input').length, 1, "there should be a searchview on discuss"); @@ -187,11 +187,11 @@ QUnit.test('searchview filter messages', function (assert) { "the searchview should have a facet"); assert.strictEqual($('.o_facet_values').text().trim(), 'ab', "the facet should be a search on 'ab'"); - assert.strictEqual(discuss.$('.o_thread_message').length, 1, + assert.containsOnce(discuss, '.o_thread_message', "there should be a single message after filter"); // interact with search view so that there are no matching messages - $('.o_facet_remove').click(); + testUtils.dom.click($('.o_facet_remove')); $('.o_searchview_input').val("abcd").trigger('keyup'); $('.o_searchview').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER })); @@ -199,7 +199,7 @@ QUnit.test('searchview filter messages', function (assert) { "the searchview should have a facet"); assert.strictEqual($('.o_facet_values').text().trim(), 'abcd', "the facet should be a search on 'abcd'"); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, + assert.containsNone(discuss, '.o_thread_message', "there should be no message after 2nd filter"); assert.strictEqual(discuss.$('.o_thread_title').text().trim(), "No matches found", @@ -304,11 +304,11 @@ QUnit.test('@ mention in channel', function (assert) { .find('.o_mail_discuss_item[data-thread-id=1]'); assert.strictEqual($general.length, 1, "should have the channel item with id 1"); - assert.strictEqual($general.attr('title'), 'general', + assert.hasAttrValue($general, 'title', 'general', "should have the title 'general'"); // click on general - $general.click(); + testUtils.dom.click($general); var $input = discuss.$('textarea.o_composer_text_field').first(); assert.ok($input.length, "should display a composer input"); @@ -320,7 +320,7 @@ QUnit.test('@ mention in channel', function (assert) { fetchListenersDef .then(concurrency.delay.bind(concurrency, 0)) .then(function () { - assert.strictEqual(discuss.$('.dropup.o_composer_mention_dropdown.show').length, 1, + assert.containsOnce(discuss, '.dropup.o_composer_mention_dropdown.show', "dropup menu for partner mentions should be open"); var $mentionPropositions = discuss.$('.o_mention_proposition'); @@ -332,21 +332,21 @@ QUnit.test('@ mention in channel', function (assert) { var $mention3 = $mentionPropositions.first().next().next(); // correct 1st mention proposition - assert.ok($mention1.hasClass('active'), + assert.hasClass($mention1,'active', "first partner mention should be active"); assert.strictEqual($mention1.data('id'), 1, "first partner mention should link to the correct partner id"); assert.strictEqual($mention1.find('.o_mention_name').text(), "Admin", "first partner mention should display the correct partner name"); // correct 2nd mention proposition - assert.notOk($mention2.hasClass('active'), + assert.doesNotHaveClass($mention2, 'active', "second partner mention should not be active"); assert.strictEqual($mention2.data('id'), 2, "second partner mention should link to the correct partner id"); assert.strictEqual($mention2.find('.o_mention_name').text(), "TestUser", "second partner mention should display the correct partner name"); // correct 3rd mention proposition - assert.notOk($mention3.hasClass('active'), + assert.doesNotHaveClass($mention3, 'active', "third partner mention should not be active"); assert.strictEqual($mention3.data('id'), 3, "third partner mention should link to the correct partner id"); @@ -355,50 +355,50 @@ QUnit.test('@ mention in channel', function (assert) { // check DOWN event $input.trigger($.Event('keyup', {which: $.ui.keyCode.DOWN})); - assert.notOk($mention1.hasClass('active'), + assert.doesNotHaveClass($mention1, 'active', "first partner mention should not be active"); - assert.ok($mention2.hasClass('active'), + assert.hasClass($mention2,'active', "second partner mention should be active"); - assert.notOk($mention3.hasClass('active'), + assert.doesNotHaveClass($mention3, 'active', "third partner mention should not be active"); // check UP event $input.trigger($.Event('keyup', {which: $.ui.keyCode.UP})); - assert.ok($mention1.hasClass('active'), + assert.hasClass($mention1,'active', "first partner mention should be active"); - assert.notOk($mention2.hasClass('active'), + assert.doesNotHaveClass($mention2, 'active', "second partner mention should not be active"); - assert.notOk($mention3.hasClass('active'), + assert.doesNotHaveClass($mention3, 'active', "third partner mention should not be active"); // check TAB event (full cycle, hence 3 TABs) $input.trigger($.Event('keyup', {which: $.ui.keyCode.TAB})); - assert.notOk($mention1.hasClass('active'), + assert.doesNotHaveClass($mention1, 'active', "first partner mention should not be active"); - assert.ok($mention2.hasClass('active'), + assert.hasClass($mention2,'active', "second partner mention should be active"); - assert.notOk($mention3.hasClass('active'), + assert.doesNotHaveClass($mention3, 'active', "third partner mention should not be active"); $input.trigger($.Event('keyup', {which: $.ui.keyCode.TAB})); - assert.notOk($mention1.hasClass('active'), + assert.doesNotHaveClass($mention1, 'active', "first partner mention should not be active"); - assert.notOk($mention2.hasClass('active'), + assert.doesNotHaveClass($mention2, 'active', "second partner mention should not be active"); - assert.ok($mention3.hasClass('active'), + assert.hasClass($mention3,'active', "third partner mention should be active"); $input.trigger($.Event('keyup', {which: $.ui.keyCode.TAB})); - assert.ok($mention1.hasClass('active'), + assert.hasClass($mention1,'active', "first partner mention should be active"); - assert.notOk($mention2.hasClass('active'), + assert.doesNotHaveClass($mention2, 'active', "second partner mention should not be active"); - assert.notOk($mention3.hasClass('active'), + assert.doesNotHaveClass($mention3, 'active', "third partner mention should not be active"); - // equivalent to $mentionPropositions.find('active').click(); +// testUtils.dom.click( equivalent to $mentionPropositions.find('active')); $input.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER})); - assert.strictEqual(discuss.$('.o_mention_proposition').length, 0, + assert.containsNone(discuss, '.o_mention_proposition', "should not have any partner mention proposition after ENTER"); assert.strictEqual($input.val().trim() , "@Admin", "should have the correct mention link in the composer input"); @@ -409,9 +409,9 @@ QUnit.test('@ mention in channel', function (assert) { receiveMessageDef .then(concurrency.delay.bind(concurrency, 0)) .then(function () { - assert.strictEqual(discuss.$('.o_thread_message_content').length, 1, + assert.containsOnce(discuss, '.o_thread_message_content', "should display one message with some content"); - assert.strictEqual(discuss.$('.o_thread_message_content a').length, 1, + assert.containsOnce(discuss, '.o_thread_message_content a', "should contain a link in the message content"); assert.strictEqual(discuss.$('.o_thread_message_content a').text(), "@Admin", "should have correct mention link in the message content"); @@ -449,11 +449,11 @@ QUnit.test('no crash focusout emoji button', function (assert) { .find('.o_mail_discuss_item[data-thread-id=1]'); assert.strictEqual($general.length, 1, "should have the channel item with id 1"); - assert.strictEqual($general.attr('title'), 'general', + assert.hasAttrValue($general, 'title', 'general', "should have the title 'general'"); // click on general - $general.click(); + testUtils.dom.click($general); discuss.$('.o_composer_button_emoji').focus(); try { discuss.$('.o_composer_button_emoji').focusout(); @@ -525,12 +525,12 @@ QUnit.test('older messages are loaded on scroll', function (assert) { "should have a channel item with id 1"); // switch to 'general' - $general.click(); + testUtils.dom.click($general); assert.verifySteps(['message_fetch', 'message_fetch'], "should fetch a second time for general channel messages (30 last messages)"); - assert.strictEqual(discuss.$('.o_thread_message').length, 30, + assert.containsN(discuss, '.o_thread_message', 30, "should display the 30 messages"); // simulate a scroll to top to load more messages @@ -541,7 +541,7 @@ QUnit.test('older messages are loaded on scroll', function (assert) { .then(function () { assert.verifySteps(['message_fetch', 'message_fetch', 'message_fetch'], "should fetch a third time for general channel messages (5 remaining messages)"); - assert.strictEqual(discuss.$('.o_thread_message').length, 35, + assert.containsN(discuss, '.o_thread_message', 35, "all messages should now be loaded"); discuss.destroy(); @@ -608,12 +608,12 @@ QUnit.test('"Unstar all" button should reset the starred counter', function (ass var $starredCounter = $('.o_mail_mailbox_title_starred > .o_mail_sidebar_needaction'); // Go to Starred channel - $starred.click(); + testUtils.dom.click($starred); // Test Initial Value assert.strictEqual($starredCounter.text().trim(), "40", "40 messages should be starred"); // Unstar all and wait 'update_starred' - $('.o_control_panel .o_mail_discuss_button_unstar_all').click(); + testUtils.dom.click($('.o_control_panel .o_mail_discuss_button_unstar_all')); $starredCounter = $('.o_mail_mailbox_title_starred > .o_mail_sidebar_needaction'); assert.strictEqual($starredCounter.text().trim(), "0", "All messages should be unstarred"); @@ -627,7 +627,7 @@ QUnit.test('do not crash when destroyed before start is completed', function (as assert.expect(3); var discuss; - testUtils.patch(Discuss, { + testUtils.mock.patch(Discuss, { init: function () { discuss = this; this._super.apply(this, arguments); @@ -657,14 +657,14 @@ QUnit.test('do not crash when destroyed before start is completed', function (as "message_fetch" ]); - testUtils.unpatch(Discuss); + testUtils.mock.unpatch(Discuss); }); QUnit.test('do not crash when destroyed between start en end of _renderSearchView', function (assert) { assert.expect(2); var discuss; - testUtils.patch(Discuss, { + testUtils.mock.patch(Discuss, { init: function () { discuss = this; this._super.apply(this, arguments); @@ -673,7 +673,7 @@ QUnit.test('do not crash when destroyed between start en end of _renderSearchVie var def = $.Deferred(); - testUtils.patch(SearchView, { + testUtils.mock.patch(SearchView, { willStart: function () { var result = this._super.apply(this, arguments); return def.then($.when(result)); @@ -700,8 +700,8 @@ QUnit.test('do not crash when destroyed between start en end of _renderSearchVie "load_views", ]); - testUtils.unpatch(Discuss); - testUtils.unpatch(SearchView); + testUtils.mock.unpatch(Discuss); + testUtils.mock.unpatch(SearchView); }); QUnit.test('confirm dialog when administrator leave (not chat) channel', function (assert) { @@ -731,7 +731,7 @@ QUnit.test('confirm dialog when administrator leave (not chat) channel', functio }) .then(function (discuss) { // Unsubscribe on MyChannel as administrator - discuss.$('.o_mail_partner_unpin').click(); + testUtils.dom.click(discuss.$('.o_mail_partner_unpin')); assert.strictEqual($('.modal-dialog').length, 1, "should display a dialog"); @@ -791,7 +791,7 @@ QUnit.test('convert emoji sources to unicodes on message_post', function (assert .find('.o_mail_discuss_item[data-thread-id=1]'); // click on general - $general.click(); + testUtils.dom.click($general); var $input = discuss.$('textarea.o_composer_text_field').first(); $input.focus(); @@ -868,21 +868,21 @@ QUnit.test('mark all messages as read from Inbox', function (assert) { "there should be an 'Inbox' item in Discuss sidebar"); assert.strictEqual($inbox.find('.o_mail_sidebar_needaction').text().trim(), "2", "the mailbox counter of 'Inbox' should be 2"); - assert.ok($inbox.hasClass('o_active'), + assert.hasClass($inbox,'o_active', "'Inbox' should be the currently active thread"); - assert.strictEqual(discuss.$('.o_thread_message').length, 2, + assert.containsN(discuss, '.o_thread_message', 2, "there should be 2 messages in inbox"); var $markAllReadButton = $('.o_mail_discuss_button_mark_all_read'); assert.strictEqual($markAllReadButton.length, 1, "there should be a 'Mark All As Read' button"); - assert.strictEqual($markAllReadButton.attr('style'), + assert.hasAttrValue($markAllReadButton, 'style', 'display: inline-block;', "the 'Mark All As Read' button should be visible"); assert.notOk($markAllReadButton.prop('disabled'), "the 'Mark All As Read' button should not be disabled"); - $markAllReadButton.click(); + testUtils.dom.click($markAllReadButton); markAllReadDef.then(function () { // immediately jump to end of the fadeout animation on messages @@ -890,7 +890,7 @@ QUnit.test('mark all messages as read from Inbox', function (assert) { discuss.$('.o_thread_message').stop(false, true); assert.strictEqual($inbox.find('.o_mail_sidebar_needaction').text().trim(), "0", "the mailbox counter of 'Inbox' should have reset to 0"); - assert.strictEqual(discuss.$('.o_thread_message').length, 0, + assert.containsNone(discuss, '.o_thread_message', "there should no message in inbox anymore"); discuss.destroy(); diff --git a/addons/mail/static/tests/discuss_typing_notification_tests.js b/addons/mail/static/tests/discuss_typing_notification_tests.js index 0009c3d799b..fee8040fc24 100644 --- a/addons/mail/static/tests/discuss_typing_notification_tests.js +++ b/addons/mail/static/tests/discuss_typing_notification_tests.js @@ -4,6 +4,7 @@ odoo.define('mail.discuss_typing_notification_test', function (require) { var Timer = require('mail.model.Timer'); var CCThrottleFunctionObject = require('mail.model.CCThrottleFunctionObject'); var mailTestUtils = require('mail.testUtils'); +var testUtils = require('web.test_utils'); var createDiscuss = mailTestUtils.createDiscuss; @@ -195,11 +196,11 @@ QUnit.test('notify is typing', function (assert) { .find('.o_mail_discuss_item[data-thread-id=1]'); assert.strictEqual($general.length, 1, "should have the channel item with id 1"); - assert.strictEqual($general.attr('title'), 'general', + assert.hasAttrValue($general, 'title', 'general', "should have the title 'general'"); // click on general - $general.click(); + testUtils.dom.click($general); var $input = discuss.$('textarea.o_composer_text_field').first(); assert.ok($input.length, "should display a composer input"); @@ -207,14 +208,14 @@ QUnit.test('notify is typing', function (assert) { // STEP 1: current user is typing something step = 1; $input.focus(); - $input.val("1"); - $input.trigger('input'); + testUtils.fields.editInput($input, '1'); + assert.verifySteps(['notify_typing']); // STEP 2: current user clears input step = 2; - $input.val(""); - $input.trigger('input'); + testUtils.fields.editInput($input, ''); + assert.verifySteps(['notify_typing', 'notify_typing']); discuss.destroy(); @@ -253,14 +254,14 @@ QUnit.test('receive is typing notification', function (assert) { .find('.o_mail_discuss_item[data-thread-id=1]'); assert.strictEqual($general.length, 1, "should have the channel item with id 1"); - assert.strictEqual($general.attr('title'), 'general', + assert.hasAttrValue($general, 'title', 'general', "should have the title 'general'"); // click on general - $general.click(); - assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').length, 1, + testUtils.dom.click($general); + assert.containsOnce(discuss, '.o_thread_typing_notification_bar', "there should be a typing notification bar on the thread"); - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be hidden by default"); self.simulateIsTyping({ @@ -271,7 +272,7 @@ QUnit.test('receive is typing notification', function (assert) { }); fetchListenersDef.then(function () { - assert.notOk(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be visible when someone is typing something"); assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(), "Someone is typing...", @@ -283,7 +284,7 @@ QUnit.test('receive is typing notification', function (assert) { partnerID: 42, widget: discuss, }); - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be hidden when someone stops typing something"); discuss.destroy(); @@ -320,11 +321,10 @@ QUnit.test('receive message of someone that was typing something', function (ass session: { partner_id: this.myPartnerID }, }).then(function (discuss) { // click on general channel - discuss.$('.o_mail_discuss_sidebar') - .find('.o_mail_discuss_item[data-thread-id=1]') - .click(); + var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]'); + testUtils.dom.click($general); - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be hidden by default"); self.simulateIsTyping({ @@ -335,7 +335,7 @@ QUnit.test('receive message of someone that was typing something', function (ass }); fetchListenersDef.then(function () { - assert.notOk(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be visible when someone is typing something"); assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(), "Someone is typing...", @@ -353,7 +353,7 @@ QUnit.test('receive message of someone that was typing something', function (ass var notification = [[false, 'mail.channel', self.generalChannelID], messageData]; discuss.call('bus_service', 'trigger', 'notification', [notification]); - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be hidden when receiving message from someone that was typing some text"); discuss.destroy(); @@ -391,10 +391,10 @@ QUnit.test('do not display myself as typing', function (assert) { // click on general var $general = discuss.$('.o_mail_discuss_sidebar') .find('.o_mail_discuss_item[data-thread-id=1]'); - $general.click(); - assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').length, 1, + testUtils.dom.click($general); + assert.containsOnce(discuss, '.o_thread_typing_notification_bar', "there should be a typing notification bar on the thread"); - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be hidden by default"); self.simulateIsTyping({ @@ -405,7 +405,7 @@ QUnit.test('do not display myself as typing', function (assert) { }); fetchListenersDef.then(function () { - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should still be hidden when I am typing something"); discuss.destroy(); @@ -453,14 +453,14 @@ QUnit.test('several users typing something at the same time', function (assert) .find('.o_mail_discuss_item[data-thread-id=1]'); assert.strictEqual($general.length, 1, "should have the channel item with id 1"); - assert.strictEqual($general.attr('title'), 'general', + assert.hasAttrValue($general, 'title', 'general', "should have the title 'general'"); // click on general - $general.click(); - assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').length, 1, + testUtils.dom.click($general); + assert.containsOnce(discuss, '.o_thread_typing_notification_bar', "there should be a typing notification bar on the thread"); - assert.ok(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isNotVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be hidden by default"); self.simulateIsTyping({ @@ -471,7 +471,7 @@ QUnit.test('several users typing something at the same time', function (assert) }); fetchListenersDef.then(function () { - assert.notOk(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be visible when someone is typing something"); assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(), "Someone is typing...", @@ -548,9 +548,8 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi session: { partner_id: this.myPartnerID }, }).then(function (discuss) { // click on general channel - discuss.$('.o_mail_discuss_sidebar') - .find('.o_mail_discuss_item[data-thread-id=1]') - .click(); + var $general = discuss.$('.o_mail_discuss_sidebar .o_mail_discuss_item[data-thread-id=1]'); + testUtils.dom.click($general); self.simulateIsTyping({ channelID: self.generalChannelID, @@ -560,7 +559,7 @@ QUnit.test('long typing partner A and in-between short typing partner B', functi }); fetchListenersDef.then(function () { - assert.notOk(discuss.$('.o_thread_typing_notification_bar').hasClass('o_hidden'), + assert.isVisible(discuss.$('.o_thread_typing_notification_bar'), "the typing notification bar should be visible when someone is typing something"); assert.strictEqual(discuss.$('.o_thread_typing_notification_bar').text(), "A is typing...", diff --git a/addons/mail/static/tests/document_thread_window_tests.js b/addons/mail/static/tests/document_thread_window_tests.js index d7064b8695d..811b01f62e4 100644 --- a/addons/mail/static/tests/document_thread_window_tests.js +++ b/addons/mail/static/tests/document_thread_window_tests.js @@ -91,7 +91,7 @@ QUnit.test('open a document thread in a thread window', function (assert) { assert.expect(6); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -110,10 +110,10 @@ QUnit.test('open a document thread in a thread window', function (assert) { messagingMenu.appendTo($('#qunit-fixture')); // toggle the messaging menu and open the documentThread - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display one preview"); - messagingMenu.$('.o_mail_preview').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview')); assert.strictEqual($('.o_thread_window').length, 1, "should have open the DocumentThread in a thread window"); @@ -129,7 +129,7 @@ QUnit.test('expand a document thread window', function (assert) { assert.expect(4); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -147,18 +147,18 @@ QUnit.test('expand a document thread window', function (assert) { messagingMenu.appendTo($('#qunit-fixture')); // toggle the messaging menu and open the documentThread - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display one preview"); - messagingMenu.$('.o_mail_preview').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview')); assert.strictEqual($('.o_thread_window').length, 1, "should have open the DocumentThread in a thread window"); - assert.strictEqual($('.o_thread_window .o_thread_window_expand').attr('title'), + assert.hasAttrValue($('.o_thread_window .o_thread_window_expand'), 'title', 'Open document', "button should have correct title"); // click to expand - $('.o_thread_window .o_thread_window_expand').click(); + testUtils.dom.click($('.o_thread_window .o_thread_window_expand')); messagingMenu.destroy(); }); @@ -177,7 +177,7 @@ QUnit.test('post messages in a document thread window', function (assert) { res_id: 1, }; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -198,7 +198,7 @@ QUnit.test('post messages in a document thread window', function (assert) { return this._super.apply(this, arguments); }, }); - testUtils.intercept(messagingMenu, 'call_service', function (ev) { + testUtils.mock.intercept(messagingMenu, 'call_service', function (ev) { if (ev.data.service === 'local_storage' && ev.data.method === 'setItem' && ev.data.args[0] === 'mail.document_threads_last_message') { assert.deepEqual(ev.data.args[1], newMessage, @@ -208,10 +208,10 @@ QUnit.test('post messages in a document thread window', function (assert) { messagingMenu.appendTo($('#qunit-fixture')); // toggle the messaging menu and open the documentThread - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display one preview"); - messagingMenu.$('.o_mail_preview').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview')); assert.strictEqual($('.o_thread_window').length, 1, "should have open the DocumentThread in a thread window"); assert.strictEqual($('.o_thread_window .o_thread_message').length, 2, @@ -232,12 +232,12 @@ QUnit.test('open, fold, unfold and close a document thread window', function (as assert.expect(8); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, }); - testUtils.intercept(messagingMenu, 'call_service', function (ev) { + testUtils.mock.intercept(messagingMenu, 'call_service', function (ev) { if (ev.data.service === 'local_storage' && ev.data.method === 'setItem') { assert.step(ev.data.args); } @@ -245,21 +245,21 @@ QUnit.test('open, fold, unfold and close a document thread window', function (as messagingMenu.appendTo($('#qunit-fixture')); // toggle the messaging menu and open the documentThread - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display one preview"); - messagingMenu.$('.o_mail_preview').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview')); assert.strictEqual($('.o_thread_window').length, 1, "should have open the DocumentThread in a thread window"); assert.strictEqual($('.o_thread_window .o_thread_message').length, 2, "should display 2 messages in the thread window"); // fold and unfold thread window - $('.o_thread_window .o_thread_window_title').click(); - $('.o_thread_window .o_thread_window_title').click(); + testUtils.dom.click($('.o_thread_window .o_thread_window_title')); + testUtils.dom.click($('.o_thread_window .o_thread_window_title')); // close thread window - $('.o_thread_window .o_thread_window_close').click(); + testUtils.dom.click($('.o_thread_window .o_thread_window_close')); assert.verifySteps([ ['mail.document_threads_state', {"some.res.model_1": {"name": "Some Record", "windowState": "open"}}], diff --git a/addons/mail/static/tests/document_viewer_tests.js b/addons/mail/static/tests/document_viewer_tests.js index bbd2d9a6fa1..ef825f84e2a 100644 --- a/addons/mail/static/tests/document_viewer_tests.js +++ b/addons/mail/static/tests/document_viewer_tests.js @@ -32,7 +32,7 @@ var createViewer = function (params) { return $.when(); } }; - testUtils.addMockEnvironment(parent, { + testUtils.mock.addMockEnvironment(parent, { mockRPC: function () { if (params.mockRPC) { var _super = this._super; @@ -82,19 +82,19 @@ QUnit.module('DocumentViewer', { attachments: this.attachments, }); - assert.strictEqual(viewer.$('.o_viewer_content').length, 1, + assert.containsOnce(viewer, '.o_viewer_content', "there should be a preview"); - assert.strictEqual(viewer.$('.o_close_btn').length, 1, + assert.containsOnce(viewer, '.o_close_btn', "there should be a close button"); - assert.strictEqual(viewer.$('.o_viewer-header').length, 1, + assert.containsOnce(viewer, '.o_viewer-header', "there should be a header"); - assert.strictEqual(viewer.$('.o_image_caption').length, 1, + assert.containsOnce(viewer, '.o_image_caption', "there should be an image caption"); - assert.strictEqual(viewer.$('.o_viewer_zoomer').length, 1, + assert.containsOnce(viewer, '.o_viewer_zoomer', "there should be a zoomer"); - assert.strictEqual(viewer.$('.fa-chevron-right').length, 1, + assert.containsOnce(viewer, '.fa-chevron-right', "there should be a right nav icon"); - assert.strictEqual(viewer.$('.fa-chevron-left').length, 1, + assert.containsOnce(viewer, '.fa-chevron-left', "there should be a left nav icon"); viewer.destroy(); @@ -120,14 +120,14 @@ QUnit.module('DocumentViewer', { }, }); - assert.strictEqual(viewer.$('.o_page_number_input').length, 1, + assert.containsOnce(viewer, '.o_page_number_input', "pdf should have a page input"); - assert.strictEqual(viewer.$('.o_remainder_input').length, 1, + assert.containsOnce(viewer, '.o_remainder_input', "pdf should have a remainder checkbox"); - assert.strictEqual(viewer.$('.o_split_btn').length, 1, + assert.containsOnce(viewer, '.o_split_btn', "pdf should have a split button"); - viewer.$('.o_split_btn').click(); + testUtils.dom.click(viewer.$('.o_split_btn')); assert.ok(viewer.isDestroyed(), 'viewer should be destroyed'); }); @@ -149,7 +149,7 @@ QUnit.module('DocumentViewer', { assert.strictEqual(viewer.$(".o_image_caption:contains('urlYoutubeName')").length, 1, "the viewer should be on the right attachment"); - assert.strictEqual(viewer.$('.o_viewer_text[data-src="' + youtubeURL + '"]').length, 1, + assert.containsOnce(viewer, '.o_viewer_text[data-src="' + youtubeURL + '"]', "there should be a video player"); viewer.destroy(); @@ -165,7 +165,7 @@ QUnit.module('DocumentViewer', { assert.strictEqual(viewer.$(".o_image_caption:contains('text.html')").length, 1, "the viewer be on the right attachment"); - assert.strictEqual(viewer.$('iframe[data-src="/web/content/4"]').length, 1, + assert.containsOnce(viewer, 'iframe[data-src="/web/content/4"]', "there should be an iframe with the right src"); viewer.destroy(); @@ -181,7 +181,7 @@ QUnit.module('DocumentViewer', { assert.strictEqual(viewer.$(".o_image_caption:contains('video.mp4')").length, 1, "the viewer be on the right attachment"); - assert.strictEqual(viewer.$('.o_viewer_video').length, 1, + assert.containsOnce(viewer, '.o_viewer_video', "there should be a video player"); viewer.destroy(); @@ -197,7 +197,7 @@ QUnit.module('DocumentViewer', { assert.strictEqual(viewer.$(".o_image_caption:contains('image.jpg')").length, 1, "the viewer be on the right attachment"); - assert.strictEqual(viewer.$('img[data-src="/web/image/6?unique=1&signature=999"]').length, 1, + assert.containsOnce(viewer, 'img[data-src="/web/image/6?unique=1&signature=999"]', "there should be a video player"); viewer.destroy(); @@ -211,12 +211,12 @@ QUnit.module('DocumentViewer', { attachments: this.attachments, }); - assert.strictEqual(viewer.$('.o_viewer_content').length, 1, + assert.containsOnce(viewer, '.o_viewer_content', "should have a document viewer"); - assert.strictEqual(viewer.$('.o_close_btn').length, 1, + assert.containsOnce(viewer, '.o_close_btn', "should have a close button"); - viewer.$('.o_close_btn').click(); + testUtils.dom.click(viewer.$('.o_close_btn')); assert.ok(viewer.isDestroyed(), 'viewer should be destroyed'); }); @@ -229,12 +229,12 @@ QUnit.module('DocumentViewer', { attachments: this.attachments, }); - assert.strictEqual(viewer.$('.o_viewer_content').length, 1, + assert.containsOnce(viewer, '.o_viewer_content', "should have a document viewer"); - assert.strictEqual(viewer.$('.o_viewer_img_wrapper').length, 1, + assert.containsOnce(viewer, '.o_viewer_img_wrapper', "should have a wrapper"); - viewer.$('.o_viewer_img_wrapper').click(); + testUtils.dom.click(viewer.$('.o_viewer_img_wrapper')); assert.ok(viewer.isDestroyed(), 'viewer should be destroyed'); }); diff --git a/addons/mail/static/tests/helpers/test_utils.js b/addons/mail/static/tests/helpers/test_utils.js index f2c095a77b8..3b998a88b00 100644 --- a/addons/mail/static/tests/helpers/test_utils.js +++ b/addons/mail/static/tests/helpers/test_utils.js @@ -35,7 +35,7 @@ function createDiscuss(params) { params.archs = params.archs || { 'mail.message,false,search': '', }; - testUtils.addMockEnvironment(parent, params); + testUtils.mock.addMockEnvironment(parent, params); var discuss = new Discuss(parent, params); discuss.set_cp_bus(new Widget()); var selector = params.debug ? 'body' : '#qunit-fixture'; diff --git a/addons/mail/static/tests/systray/systray_activity_menu_tests.js b/addons/mail/static/tests/systray/systray_activity_menu_tests.js index c666628624c..d9977822916 100644 --- a/addons/mail/static/tests/systray/systray_activity_menu_tests.js +++ b/addons/mail/static/tests/systray/systray_activity_menu_tests.js @@ -80,7 +80,7 @@ QUnit.test('activity menu widget: menu with no records', function (assert) { assert.expect(1); var activityMenu = new ActivityMenu(); - testUtils.addMockEnvironment(activityMenu, { + testUtils.mock.addMockEnvironment(activityMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'systray_get_activities') { @@ -90,7 +90,7 @@ QUnit.test('activity menu widget: menu with no records', function (assert) { }, }); activityMenu.appendTo($('#qunit-fixture')); - assert.ok(activityMenu.$('.o_no_activity').hasClass('o_no_activity'), "should not have instance of widget"); + assert.hasClass(activityMenu.$('.o_no_activity'),'o_no_activity', "should not have instance of widget"); activityMenu.destroy(); }); @@ -98,7 +98,7 @@ QUnit.test('activity menu widget: activity menu with 3 records', function (asser assert.expect(10); var self = this; var activityMenu = new ActivityMenu(); - testUtils.addMockEnvironment(activityMenu, { + testUtils.mock.addMockEnvironment(activityMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'systray_get_activities') { @@ -108,13 +108,14 @@ QUnit.test('activity menu widget: activity menu with 3 records', function (asser }, }); activityMenu.appendTo($('#qunit-fixture')); - assert.ok(activityMenu.$el.hasClass('o_mail_systray_item'), 'should be the instance of widget'); - assert.ok(activityMenu.$('.o_mail_preview').hasClass('o_mail_preview'), "should instance of widget"); - assert.ok(activityMenu.$('.o_notification_counter').hasClass('o_notification_counter'), "widget should have notification counter"); + assert.hasClass(activityMenu.$el, 'o_mail_systray_item', 'should be the instance of widget'); + // the assertion below has not been replace because there are includes of ActivityMenu that modify the length. + assert.ok(activityMenu.$('.o_mail_preview').length); + assert.containsOnce(activityMenu.$el, '.o_notification_counter', "widget should have notification counter"); assert.strictEqual(parseInt(activityMenu.el.innerText), 8, "widget should have 8 notification counter"); var context = {}; - testUtils.intercept(activityMenu, 'do_action', function (event) { + testUtils.mock.intercept(activityMenu, 'do_action', function (event) { assert.deepEqual(event.data.action.context, context, "wrong context value"); }, true); @@ -122,29 +123,29 @@ QUnit.test('activity menu widget: activity menu with 3 records', function (asser context = { search_default_activities_overdue: 1, }; - activityMenu.$('.dropdown-toggle').click(); - assert.strictEqual(activityMenu.$el.hasClass("show"), true, 'ActivityMenu should be open'); - activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='overdue']").click(); - assert.strictEqual(activityMenu.$el.hasClass("show"), false, 'ActivityMenu should be closed'); + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + assert.hasClass(activityMenu.$el, 'show', 'ActivityMenu should be open'); + testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='overdue']")); + assert.doesNotHaveClass(activityMenu.$el, 'show', 'ActivityMenu should be closed'); // case 2: click on "today" context = { search_default_activities_today: 1, }; - activityMenu.$('.dropdown-toggle').click(); - activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='today']").click(); + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='today']")); // case 3: click on "future" context = { search_default_activities_upcoming_all: 1, }; - activityMenu.$('.dropdown-toggle').click(); - activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='upcoming_all']").click(); + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + testUtils.dom.click(activityMenu.$(".o_activity_filter_button[data-model_name='Issue'][data-filter='upcoming_all']")); // case 4: click anywere else context = { search_default_activities_overdue: 1, search_default_activities_today: 1, }; - activityMenu.$('.dropdown-toggle').click(); - activityMenu.$(".o_mail_systray_dropdown_items > div[data-model_name='Issue']").click(); + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + testUtils.dom.click(activityMenu.$(".o_mail_systray_dropdown_items > div[data-model_name='Issue']")); activityMenu.destroy(); }); @@ -153,7 +154,7 @@ QUnit.test('activity menu widget: activity view icon', function (assert) { assert.expect(8); var self = this; var activityMenu = new ActivityMenu(); - testUtils.addMockEnvironment(activityMenu, { + testUtils.mock.addMockEnvironment(activityMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'systray_get_activities') { @@ -163,31 +164,30 @@ QUnit.test('activity menu widget: activity view icon', function (assert) { }, }); activityMenu.appendTo($('#qunit-fixture')); - assert.strictEqual(activityMenu.$('.o_mail_activity_action').length, 2, + assert.containsN(activityMenu, '.o_mail_activity_action', 2, "widget should have 2 activity view icons"); var $first = activityMenu.$('.o_mail_activity_action').eq(0); var $second = activityMenu.$('.o_mail_activity_action').eq(1); assert.strictEqual($first.data('model_name'), "Issue", "first activity action should link to 'Issue'"); - assert.ok($first.hasClass('fa-clock-o'), "should display the activity action icon"); + assert.hasClass($first,'fa-clock-o', "should display the activity action icon"); assert.strictEqual($second.data('model_name'), "Note", "Second activity action should link to 'Note'"); - assert.ok($second.hasClass('fa-clock-o'), "should display the activity action icon"); + assert.hasClass($second,'fa-clock-o', "should display the activity action icon"); - testUtils.intercept(activityMenu, 'do_action', function (event) { + testUtils.mock.intercept(activityMenu, 'do_action', function (event) { assert.step('do_action:' + (event.data.action.name ? event.data.action.name : event.data.action)); }, true); // click on the "Issue" activity icon - activityMenu.$('.dropdown-toggle').click(); - activityMenu.$(".o_mail_activity_action[data-model_name='Issue']").click(); + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='Issue']")); // click on the "Note" activity icon - activityMenu.$('.dropdown-toggle').click(); - activityMenu.$(".o_mail_activity_action[data-model_name='Note']").click(); + testUtils.dom.click(activityMenu.$(".o_mail_activity_action[data-model_name='Note']")); assert.verifySteps([ 'do_action:Issue', diff --git a/addons/mail/static/tests/systray/systray_messaging_menu_mail_failure_tests.js b/addons/mail/static/tests/systray/systray_messaging_menu_mail_failure_tests.js index c1fc1bd8dae..c03259697cd 100644 --- a/addons/mail/static/tests/systray/systray_messaging_menu_mail_failure_tests.js +++ b/addons/mail/static/tests/systray/systray_messaging_menu_mail_failure_tests.js @@ -82,14 +82,14 @@ QUnit.test('preview of mail failure', function (assert) { }]; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display one preview for the mail failure"); assert.strictEqual(messagingMenu.$('.o_mail_preview').data('document-model'), 'mail.channel', "preview should link to correct document model"); @@ -138,14 +138,14 @@ QUnit.test('preview grouped failures by document', function (assert) { }]; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2, + assert.containsN(messagingMenu, '.o_mail_preview', 2, "should have a two messaging previews for the mail failures"); var $channelPreview = messagingMenu.$('.o_mail_preview[data-document-model="mail.channel"]'); assert.strictEqual($channelPreview.data('document-id'), 100, @@ -194,14 +194,14 @@ QUnit.test('preview grouped failures by document model', function (assert) { }]; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2, + assert.containsN(messagingMenu, '.o_mail_preview', 2, "should have a two messaging previews for the mail failures"); var $channelPreview = messagingMenu.$('.o_mail_preview[data-document-model="mail.channel"]'); assert.notOk($channelPreview.data('document-id'), diff --git a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js index 1b608f5c37b..a1633ada574 100644 --- a/addons/mail/static/tests/systray/systray_messaging_menu_tests.js +++ b/addons/mail/static/tests/systray/systray_messaging_menu_tests.js @@ -105,7 +105,7 @@ QUnit.test('messaging menu widget: menu with no records', function (assert) { assert.expect(1); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'message_fetch') { @@ -115,23 +115,23 @@ QUnit.test('messaging menu widget: menu with no records', function (assert) { } }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.ok(messagingMenu.$('.o_no_activity').hasClass('o_no_activity'), "should not have instance of widget"); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.hasClass(messagingMenu.$('.o_no_activity'),'o_no_activity', "should not have instance of widget"); messagingMenu.destroy(); }); QUnit.test('messaging menu widget: messaging menu with 1 record', function (assert) { assert.expect(3); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display a preview"); assert.strictEqual(messagingMenu.$('.o_preview_name').text().trim(), "general", "should display correct name of channel in preview"); @@ -150,7 +150,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d assert.expect(4); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { @@ -174,7 +174,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d messagingMenu.call('bus_service', 'trigger', 'notification', notifications); // Open messaging menu - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); var $firstChannelPreview = messagingMenu.$('.o_mail_preview').first(); @@ -185,12 +185,12 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d 'mailbox_inbox', "should be a preview from channel inbox"); - testUtils.intercept(messagingMenu, 'do_action', function (ev) { + testUtils.mock.intercept(messagingMenu, 'do_action', function (ev) { if (ev.data.action === 'mail.action_discuss') { assert.step('do_action:' + ev.data.action + ':' + ev.data.options.active_id); } }, true); - $firstChannelPreview.click(); + testUtils.dom.click($firstChannelPreview); assert.verifySteps( ['do_action:mail.action_discuss:mailbox_inbox'], "should open Discuss with Inbox"); @@ -201,7 +201,7 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d QUnit.test("messaging menu widget: mark as read on thread preview", function ( assert ) { assert.expect(8); - testUtils.patch(DocumentThread, { + testUtils.mock.patch(DocumentThread, { markAsRead: function () { if ( this.getDocumentModel() === 'crm.lead' && @@ -225,16 +225,16 @@ QUnit.test("messaging menu widget: mark as read on thread preview", function ( a }]; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); - assert.ok(messagingMenu.$el.hasClass('o_mail_systray_item'), + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.hasClass(messagingMenu.$el,'o_mail_systray_item', 'should be the instance of widget'); - assert.ok(messagingMenu.$el.hasClass('show'), + assert.hasClass(messagingMenu.$el,'show', 'MessagingMenu should be open'); var $preview = messagingMenu.$('.o_mail_preview.o_preview_unread'); @@ -244,15 +244,15 @@ QUnit.test("messaging menu widget: mark as read on thread preview", function ( a "should preview be linked to correct document model"); assert.strictEqual($preview.data('document-id'), 126, "should preview be linked to correct document ID"); - assert.strictEqual(messagingMenu.$('.o_mail_preview_mark_as_read').length, 1, + assert.containsOnce(messagingMenu, '.o_mail_preview_mark_as_read', "should have mark as read icon next to preview"); - messagingMenu.$(".o_mail_preview_mark_as_read").click(); + testUtils.dom.click(messagingMenu.$(".o_mail_preview_mark_as_read")); assert.verifySteps(['markedAsRead'], "the document thread should be marked as read"); - testUtils.unpatch(DocumentThread); + testUtils.mock.unpatch(DocumentThread); messagingMenu.destroy(); }); @@ -288,7 +288,7 @@ QUnit.test('needaction messages in channels should appear, in addition to channe this.data['mail.message'].records = [needactionMessage, lastMessage]; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { @@ -297,9 +297,9 @@ QUnit.test('needaction messages in channels should appear, in addition to channe }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2, + assert.containsN(messagingMenu, '.o_mail_preview', 2, "should display two previews"); var $preview1 = messagingMenu.$('.o_mail_preview').eq(0); var $preview2 = messagingMenu.$('.o_mail_preview').eq(1); @@ -344,7 +344,7 @@ QUnit.test('preview of message on a document + mark as read', function (assert) this.data['mail.message'].records.push(needactionMessage); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { @@ -355,22 +355,22 @@ QUnit.test('preview of message on a document + mark as read', function (assert) assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1', "should display a counter of 1 on the messaging menu icon"); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display one preview"); assert.strictEqual(messagingMenu.$('.o_mail_preview').data('preview-id'), "some.res.model_1", "preview should be the document thread preview"); - assert.ok(messagingMenu.$('.o_mail_preview:first').hasClass('o_preview_unread'), + assert.hasClass(messagingMenu.$('.o_mail_preview:first'),'o_preview_unread', "document thread preview should be marked as unread"); assert.strictEqual(messagingMenu.$('.o_preview_unread .o_last_message_preview').text().replace(/\s/g, ''), "Demo:*MessageOnDocument*", "should correctly display the preview"); - messagingMenu.$('.o_mail_preview_mark_as_read').click(); + testUtils.dom.click(messagingMenu.$('.o_mail_preview_mark_as_read')); assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '0', "should display a counter of 0 on the messaging menu icon"); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 0, + assert.containsNone(messagingMenu, '.o_mail_preview', "should not display any preview"); messagingMenu.destroy(); @@ -380,15 +380,15 @@ QUnit.test('update messaging preview on receiving a new message in channel previ assert.expect(8); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); messagingMenu.appendTo($('#qunit-fixture')); - messagingMenu.$('.dropdown-toggle').click(); + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + assert.containsOnce(messagingMenu, '.o_mail_preview', "should display a single channel preview"); assert.strictEqual(messagingMenu.$('.o_preview_name').text().trim(), "general", "should display channel preview of 'general' channel"); @@ -411,7 +411,7 @@ QUnit.test('update messaging preview on receiving a new message in channel previ var notification = [[false, 'mail.channel', 1], data]; messagingMenu.call('bus_service', 'trigger', 'notification', [notification]); - assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, + assert.containsOnce(messagingMenu, '.o_mail_preview', "should still display a single channel preview"); assert.strictEqual(messagingMenu.$('.o_preview_name').text().trim(), "general", "should still display channel preview of 'general' channel"); @@ -451,7 +451,7 @@ QUnit.test('preview of inbox message not linked to document + mark as read', fun this.data['mail.message'].records.concat(needactionMessages); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { @@ -554,7 +554,7 @@ QUnit.test('grouped preview for needaction messages linked to same document', fu this.data.initMessaging.needaction_inbox_counter = 2; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { diff --git a/addons/mail/static/tests/thread_window/basic_thread_window_tests.js b/addons/mail/static/tests/thread_window/basic_thread_window_tests.js index 4b8935e81cf..b820972bef8 100644 --- a/addons/mail/static/tests/thread_window/basic_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/basic_thread_window_tests.js @@ -44,7 +44,7 @@ QUnit.module('Basic', { self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture'; } - testUtils.addMockEnvironment(widget, params); + testUtils.mock.addMockEnvironment(widget, params); return widget; }; }, @@ -121,7 +121,7 @@ QUnit.test('close thread window using ESCAPE key', function (assert) { "there should be a thread window that is opened"); // focus on the thread window and press ESCAPE - $('.o_thread_window .o_composer_text_field').click(); + testUtils.dom.click($('.o_thread_window .o_composer_text_field')); assert.strictEqual(document.activeElement, $('.o_thread_window .o_composer_text_field')[0], "thread window's input should now be focused"); @@ -150,7 +150,7 @@ QUnit.test('thread window\'s input can still be focused when the UI is blocked', channel.detach(); var $input = $('', {type: 'text'}).appendTo($dom); - $input.focus().click(); + testUtils.dom.click($input.focus()); assert.strictEqual(document.activeElement, $input[0], "fake input should be focused"); @@ -159,7 +159,7 @@ QUnit.test('thread window\'s input can still be focused when the UI is blocked', // makes no sense, this test is just about // making sure that the code which forces the // focus on click is not removed - $('.o_thread_window .o_composer_text_field').click(); + testUtils.dom.click($('.o_thread_window .o_composer_text_field')); assert.strictEqual(document.activeElement, $('.o_thread_window .o_composer_text_field')[0], "thread window's input should now be focused"); @@ -181,7 +181,7 @@ QUnit.test('emoji popover should open correctly in thread windows', function (as channel.detach(); var $emojiButton = $('.o_composer_button_emoji'); - $emojiButton.trigger('focusin').focus().click(); + testUtils.dom.click($emojiButton.trigger('focusin').focus()); var $popover = $('.o_mail_emoji_container'); var done = assert.async(); @@ -254,7 +254,7 @@ QUnit.test('do not increment unread counter with focus on thread window', functi "thread should have unread counter to 0 initially"); // hard focus on thread window composer - $('.o_composer_text_field').click(); + testUtils.dom.click($('.o_composer_text_field')); // simulate receiving message from someone else var messageData = { @@ -346,7 +346,7 @@ QUnit.test('do not mark as read the newly open thread window from received messa assert.strictEqual($threadWindow.find('.o_thread_window_title').text().replace(/\s/g, ''), '#DM(1)', "open DM chat window should have one unread message"); - $threadWindow.find('.o_thread_composer').click(); + testUtils.dom.click($threadWindow.find('.o_thread_composer')); assert.strictEqual($threadWindow.find('.o_thread_window_title').text().replace(/\s/g, ''), '#DM', "open DM chat window should have message marked as read on composer focus"); diff --git a/addons/mail/static/tests/thread_window/blank_thread_window_tests.js b/addons/mail/static/tests/thread_window/blank_thread_window_tests.js index 883494a4ec6..0f3c7c7bbe7 100644 --- a/addons/mail/static/tests/thread_window/blank_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/blank_thread_window_tests.js @@ -44,7 +44,7 @@ QUnit.module('Blank', { self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture'; } - testUtils.addMockEnvironment(widget, params); + testUtils.mock.addMockEnvironment(widget, params); return widget; }; @@ -125,7 +125,7 @@ QUnit.test('close blank thread window', function (assert) { // open blank thread window parent.call('mail_service', 'openBlankThreadWindow'); - $('.o_thread_window_close').click(); + testUtils.dom.click($('.o_thread_window_close')); assert.strictEqual($('.o_thread_window').length, 0, "blank thread window should be closed"); @@ -147,7 +147,7 @@ QUnit.test('fold blank thread window', function (assert) { var HEIGHT_OPEN = AbstractThreadWindow.prototype.HEIGHT_OPEN; // Make fold animation instantaneous - testUtils.patch(AbstractThreadWindow, { + testUtils.mock.patch(AbstractThreadWindow, { FOLD_ANIMATION_DURATION: 0, }); @@ -159,12 +159,12 @@ QUnit.test('fold blank thread window', function (assert) { console.warn('Assertion above may fail due to too narrow height of browser'); } - $('.o_thread_window_title').click(); + testUtils.dom.click($('.o_thread_window_title')); assert.strictEqual($('.o_thread_window').css('height'), HEIGHT_FOLDED, "blank thread window should be open"); parent.destroy(); - testUtils.unpatch(AbstractThreadWindow); + testUtils.mock.unpatch(AbstractThreadWindow); }); QUnit.test('open new DM chat from blank thread window', function (assert) { @@ -224,7 +224,7 @@ QUnit.test('open new DM chat from blank thread window', function (assert) { assert.strictEqual($('.ui-menu-item a').eq(1).text(), "DemoUser2", "second suggestion should be 'DemoUser2'"); - $('.ui-menu-item a').eq(0).click(); + testUtils.dom.click($('.ui-menu-item a').eq(0)); }); selectDef.then(function () { assert.strictEqual($('.o_thread_window').length, 1, @@ -299,7 +299,7 @@ QUnit.test('open already detached DM chat from blank thread window', function (a $('.o_thread_search_input input').val("D").trigger('keydown'); $.when(sourceDef, def).then(function () { - $('.ui-menu-item a').eq(0).click(); + testUtils.dom.click($('.ui-menu-item a').eq(0)); }); selectDef.then(function () { assert.strictEqual($('.o_thread_window').length, 1, diff --git a/addons/mail/static/tests/thread_window/hidden_thread_window_tests.js b/addons/mail/static/tests/thread_window/hidden_thread_window_tests.js index 29e05c59da9..b87dbe0f794 100644 --- a/addons/mail/static/tests/thread_window/hidden_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/hidden_thread_window_tests.js @@ -43,7 +43,7 @@ QUnit.module('Hidden', { self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture'; } - testUtils.addMockEnvironment(widget, params); + testUtils.mock.addMockEnvironment(widget, params); return widget; }; }, @@ -62,7 +62,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver // single thread window. assert.expect(13); - testUtils.patch(this.services.mail_service, { + testUtils.mock.patch(this.services.mail_service, { HIDDEN_THREAD_WINDOW_DROPDOWN_BUTTON_WIDTH: 100, THREAD_WINDOW_WIDTH: 300, _getGlobalWidth: function () { return 800; }, @@ -128,7 +128,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver 1, "should contain thread window with ID 1 in hidden dropdown menu"); parent.destroy(); - testUtils.unpatch(this.services.mail_service); + testUtils.mock.unpatch(this.services.mail_service); }); QUnit.test('hidden thread windows dropdown when not enough horizontal space (version 2)', function (assert) { @@ -146,7 +146,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver // With button: 2 thread windows (2*250px + 100px = 600px < 800px) assert.expect(16); - testUtils.patch(this.services.mail_service, { + testUtils.mock.patch(this.services.mail_service, { HIDDEN_THREAD_WINDOW_DROPDOWN_BUTTON_WIDTH: 100, THREAD_WINDOW_WIDTH: 250, _getGlobalWidth: function () { return 800; }, @@ -219,7 +219,7 @@ QUnit.test('hidden thread windows dropdown when not enough horizontal space (ver 1, "should contain thread window with ID 2 in hidden dropdown menu"); parent.destroy(); - testUtils.unpatch(this.services.mail_service); + testUtils.mock.unpatch(this.services.mail_service); }); }); diff --git a/addons/mail/static/tests/thread_window/moderation_thread_window_tests.js b/addons/mail/static/tests/thread_window/moderation_thread_window_tests.js index 4a8cc9e2af0..b35405a2243 100644 --- a/addons/mail/static/tests/thread_window/moderation_thread_window_tests.js +++ b/addons/mail/static/tests/thread_window/moderation_thread_window_tests.js @@ -74,7 +74,7 @@ QUnit.module('Moderation', { self.services.mail_service.prototype.THREAD_WINDOW_APPENDTO = '#qunit-fixture'; } - testUtils.addMockEnvironment(widget, params); + testUtils.mock.addMockEnvironment(widget, params); return widget; }; }, diff --git a/addons/mail/static/tests/tools/debug_manager_tests.js b/addons/mail/static/tests/tools/debug_manager_tests.js index 71314e244fc..fa7aecd40d1 100644 --- a/addons/mail/static/tests/tools/debug_manager_tests.js +++ b/addons/mail/static/tests/tools/debug_manager_tests.js @@ -49,7 +49,9 @@ QUnit.module('Mail DebugManager', {}, function () { assert.strictEqual($messageMenu.length, 1, "should have Manage Message menu item"); assert.strictEqual($messageMenu.text().trim(), "Manage Messages", "should have correct menu item text"); - $messageMenu.click(); + + testUtils.dom.click(debugManager.$('> a')); // open dropdown + testUtils.dom.click($messageMenu); debugManager.destroy(); }); diff --git a/addons/mail_bot/static/tests/systray_messaging_menu_tests.js b/addons/mail_bot/static/tests/systray_messaging_menu_tests.js index a04aba7056a..c248871c2c9 100644 --- a/addons/mail_bot/static/tests/systray_messaging_menu_tests.js +++ b/addons/mail_bot/static/tests/systray_messaging_menu_tests.js @@ -28,7 +28,7 @@ QUnit.module('MessagingMenu', { // the detection of push notifications permissions can be simulated in // the test cases. By default, shows 'OdooBot has a request' this.hasMailbotRequest = true; - testUtils.patch(MailBotService, { + testUtils.mock.patch(MailBotService, { /** * @override */ @@ -48,7 +48,7 @@ QUnit.module('MessagingMenu', { }, afterEach: function () { // unpatch MailBotService - testUtils.unpatch(MailBotService); + testUtils.mock.unpatch(MailBotService); } }); @@ -56,19 +56,19 @@ QUnit.test('messaging menu widget: rendering with OdooBot has a request', functi assert.expect(5); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); messagingMenu.appendTo($('#qunit-fixture')); - assert.strictEqual(messagingMenu.$('.o_notification_counter').length, 1, + assert.containsOnce(messagingMenu, '.o_notification_counter', "should display a notification counter next to the messaging menu"); assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1', "should display a counter of '1' next to the messaging menu"); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_preview_info').length, 1, + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsOnce(messagingMenu, '.o_preview_info', "should display a preview in the messaging menu"); assert.strictEqual(messagingMenu.$('.o_preview_name').text().trim(), 'OdooBot has a request', @@ -85,18 +85,18 @@ QUnit.test('messaging menu widget: rendering without OdooBot has a request', fun this.hasMailbotRequest = false; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); messagingMenu.appendTo($('#qunit-fixture')); - assert.strictEqual(messagingMenu.$('.o_notification_counter').length, 1, + assert.containsOnce(messagingMenu, '.o_notification_counter', "should display a notification counter next to the messaging menu"); assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '0', "should display a counter of '0' next to the messaging menu"); - messagingMenu.$('.dropdown-toggle').click(); - assert.strictEqual(messagingMenu.$('.o_preview_info').length, 0, + testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); + assert.containsNone(messagingMenu, '.o_preview_info', "should display no preview in the messaging menu"); messagingMenu.destroy(); diff --git a/addons/mrp/static/tests/mrp_tests.js b/addons/mrp/static/tests/mrp_tests.js index 9d4e82ede12..7e548234bb1 100644 --- a/addons/mrp/static/tests/mrp_tests.js +++ b/addons/mrp/static/tests/mrp_tests.js @@ -45,7 +45,7 @@ QUnit.module('mrp', { assert.strictEqual(form.$('.o_field_widget').text(), "Waiting Materials", "the widget should be correctly named"); - assert.strictEqual(form.$('.o_field_widget .badge-danger').length, 1, + assert.containsOnce(form, '.o_field_widget .badge-danger', "the badge should be danger"); form.destroy(); diff --git a/addons/note/static/tests/systray_activity_menu_tests.js b/addons/note/static/tests/systray_activity_menu_tests.js index 81b2c5ac198..8c4e2dde60a 100644 --- a/addons/note/static/tests/systray_activity_menu_tests.js +++ b/addons/note/static/tests/systray_activity_menu_tests.js @@ -38,7 +38,7 @@ QUnit.test('note activity menu widget: create note from activity menu', function assert.expect(15); var self = this; var activityMenu = new ActivityMenu(); - testUtils.addMockEnvironment(activityMenu, { + testUtils.mock.addMockEnvironment(activityMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'systray_get_activities') { @@ -72,52 +72,52 @@ QUnit.test('note activity menu widget: create note from activity menu', function }, }); activityMenu.appendTo($('#qunit-fixture')); - assert.ok(activityMenu.$el.hasClass('o_mail_systray_item'), + assert.hasClass(activityMenu.$el,'o_mail_systray_item', 'should be the instance of widget'); assert.strictEqual(activityMenu.$('.o_notification_counter').text(), '0', "should not have any activity notification initially"); // toggle quick create for note - activityMenu.$('.dropdown-toggle').click(); - assert.strictEqual(activityMenu.$('.o_no_activity').length, 1, + testUtils.dom.click(activityMenu.$('.dropdown-toggle')); + assert.containsOnce(activityMenu, '.o_no_activity', "should not have any activity preview"); - assert.strictEqual(activityMenu.$('.o_note_show').hasClass('d-none'), false, + assert.doesNotHaveClass(activityMenu.$('.o_note_show'), 'd-none', 'ActivityMenu should have Add new note CTA'); - activityMenu.$('.o_note_show').click(); - assert.strictEqual(activityMenu.$('.o_note_show').hasClass('d-none'), true, + testUtils.dom.click(activityMenu.$('.o_note_show')); + assert.hasClass(activityMenu.$('.o_note_show'), 'd-none', 'ActivityMenu should hide CTA when entering a new note'); - assert.strictEqual(activityMenu.$('.o_note').hasClass('d-none'), false, + assert.doesNotHaveClass(activityMenu.$('.o_note'), 'd-none', 'ActivityMenu should display input for new note'); // creating quick note without date activityMenu.$("input.o_note_input").val("New Note"); - activityMenu.$(".o_note_save").click(); + testUtils.dom.click(activityMenu.$(".o_note_save")); assert.strictEqual(activityMenu.$('.o_notification_counter').text(), '1', "should increment activity notification counter after creating a note"); - assert.strictEqual(activityMenu.$('.o_mail_preview[data-res_model="note.note"]').length, 1, + assert.containsOnce(activityMenu, '.o_mail_preview[data-res_model="note.note"]', "should have an activity preview that is a note"); assert.strictEqual(activityMenu.$('.o_activity_filter_button[data-filter="today"]').text().trim(), "1 Today", "should display one note for today"); - assert.strictEqual(activityMenu.$('.o_note_show').hasClass('d-none'), false, + assert.doesNotHaveClass(activityMenu.$('.o_note_show'), 'd-none', 'ActivityMenu add note button should be displayed'); - assert.strictEqual(activityMenu.$('.o_note').hasClass('d-none'), true, + assert.hasClass(activityMenu.$('.o_note'), 'd-none', 'ActivityMenu add note input should be hidden'); // creating quick note with date - activityMenu.$('.o_note_show').click(); + testUtils.dom.click(activityMenu.$('.o_note_show')); activityMenu.$('input.o_note_input').val("New Note"); - activityMenu.$('.o_note_set_datetime').click(); - activityMenu.$(".o_note_save").click(); + testUtils.dom.click(activityMenu.$('.o_note_set_datetime')); + testUtils.dom.click(activityMenu.$(".o_note_save")); assert.strictEqual(activityMenu.$('.o_notification_counter').text(), '2', "should increment activity notification counter after creating a second note"); assert.strictEqual(activityMenu.$('.o_activity_filter_button[data-filter="today"]').text().trim(), "2 Today", "should display 2 notes for today"); - assert.strictEqual(activityMenu.$('.o_note_show').hasClass('d-none'), false, + assert.doesNotHaveClass(activityMenu.$('.o_note_show'), 'd-none', 'ActivityMenu add note button should be displayed'); - assert.strictEqual(activityMenu.$('.o_note').hasClass('d-none'), true, + assert.hasClass(activityMenu.$('.o_note'), 'd-none', 'ActivityMenu add note input should be hidden'); activityMenu.destroy(); }); diff --git a/addons/pad/static/tests/pad_tests.js b/addons/pad/static/tests/pad_tests.js index f2ab3a42dfa..b062e39470e 100644 --- a/addons/pad/static/tests/pad_tests.js +++ b/addons/pad/static/tests/pad_tests.js @@ -60,7 +60,7 @@ QUnit.module('pad widget', { "help message should be visible"); assert.notOk(form.$('p.oe_pad_content').is(':visible'), "content should not be visible"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(form.$('p.oe_unconfigured').is(':visible'), "help message should be visible"); assert.notOk(form.$('p.oe_pad_content').is(':visible'), @@ -102,9 +102,9 @@ QUnit.module('pad widget', { assert.strictEqual(form.$('.oe_pad_content:contains(This pad will be)').length, 1, "content should display a message when not initialized"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.oe_pad_content iframe').length, 1, + assert.containsOnce(form, '.oe_pad_content iframe', "should have an iframe"); form.destroy(); @@ -152,8 +152,8 @@ QUnit.module('pad widget', { assert.strictEqual(form.$('.oe_pad_content').text(), "we should rewrite this server in haskell", "should display proper value"); - form.$buttons.find('.o_form_button_edit').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.form.clickSave(form); form.destroy(); delete FieldPad.prototype.isPadConfigured; }); @@ -218,7 +218,7 @@ QUnit.module('pad widget', { userName: "batman", }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var def = form.canBeDiscarded(); assert.strictEqual($('.modal').length, 0, @@ -255,8 +255,8 @@ QUnit.module('pad widget', { userName: "batman", }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickEdit(form); + testUtils.form.clickDiscard(form); assert.strictEqual(form.$('.oe_pad_readonly').text(), this.data.task.pad_get_content(), "pad content should not have changed"); form.destroy(); diff --git a/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js b/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js index 9a49acd846f..52dcde5370f 100644 --- a/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js +++ b/addons/partner_autocomplete/static/tests/partner_autocomplete_tests.js @@ -17,7 +17,7 @@ odoo.define('partner_autocomplete.tests', function (require) { if (fields[key]) { if (key === 'image') { if (val) val = 'data:image/png;base64,' + val; - assert.strictEqual(form.$(".o_field_image img").attr("data-src"), val, 'image value should have been updated to "' + val + '"'); + assert.hasAttrValue(form.$(".o_field_image img"), "data-src", val, 'image value should have been updated to "' + val + '"'); } else { type = fields[key].type; $fieldInput = form.$('input[name="' + key + '"]'); @@ -56,7 +56,7 @@ odoo.define('partner_autocomplete.tests', function (require) { vat: "BE0477472701", }; - testUtils.patch(AutocompleteCore, { + testUtils.mock.patch(AutocompleteCore, { _getBase64Image: function (url) { return $.when(url === "odoo.com/logo.png" ? "odoobase64" : ""); }, @@ -87,7 +87,7 @@ odoo.define('partner_autocomplete.tests', function (require) { }, }); - testUtils.patch(AutocompleteField, { + testUtils.mock.patch(AutocompleteField, { debounceSuggestions: 0, }); }, @@ -127,8 +127,8 @@ odoo.define('partner_autocomplete.tests', function (require) { }; }, after: function () { - testUtils.unpatch(AutocompleteField); - testUtils.unpatch(AutocompleteCore); + testUtils.mock.unpatch(AutocompleteField); + testUtils.mock.unpatch(AutocompleteCore); }, }); @@ -149,14 +149,14 @@ odoo.define('partner_autocomplete.tests', function (require) { }).then(function (form){ // Set company type to Individual var $company_type = form.$("select[name='company_type']"); - $company_type.val('"individual"').trigger('change'); + testUtils.fields.editSelect($company_type, '"individual"'); // Check input exists var $input = form.$(".o_field_partner_autocomplete > input:visible"); assert.strictEqual($input.length, 1, "there should be an for the Partner field"); // Change input val and assert nothing happens - $input.val("odoo").trigger("input"); + testUtils.fields.editInput($input, "odoo") var $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 0, "there should not be an opened dropdown"); @@ -205,20 +205,20 @@ odoo.define('partner_autocomplete.tests', function (require) { }).then(function (form){ // Set company type to Company var $company_type = form.$("select[name='company_type']"); - $company_type.val('"company"').trigger('change'); + testUtils.fields.editSelect($company_type, '"company"'); // Check input exists var $input = form.$(".o_field_partner_autocomplete > input:visible"); assert.strictEqual($input.length, 1, "there should be an for the field"); // Change input val and assert changes - $input.val("odoo").trigger("input"); + testUtils.fields.editInput($input, "odoo") var $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown"); assert.strictEqual($dropdown.children().length, 1, "there should be only one proposition"); - $dropdown.find("a").first().click(); + testUtils.dom.click($dropdown.find("a").first()); $input = form.$(".o_field_partner_autocomplete > input"); assert.strictEqual($input.val(), "Odoo", "Input value should have been updated to \"Odoo\""); assert.strictEqual(form.$("input.o_field_widget").val(), "odoo.com", "website value should have been updated to \"odoo.com\""); @@ -226,12 +226,12 @@ odoo.define('partner_autocomplete.tests', function (require) { _compareResultFields(assert, form, fields, AutocompleteCore._createData); // Try suggestion with bullshit query - $input.val("ZZZZZZZZZZZZZZZZZZZZZZ").trigger("input"); + testUtils.fields.editInput($input, "ZZZZZZZZZZZZZZZZZZZZZZ") $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 0, "there should be no opened dropdown when no result"); // Try autocomplete again - $input.val("odoo").trigger("input"); + testUtils.fields.editInput($input, "odoo") $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown when typing odoo letters again"); @@ -284,7 +284,7 @@ odoo.define('partner_autocomplete.tests', function (require) { }).then(function (form){ // Set company type to Company var $company_type = form.$("select[name='company_type']"); - $company_type.val('"company"').trigger('change'); + testUtils.fields.editSelect($company_type, '"company"'); // Check input exists @@ -292,19 +292,19 @@ odoo.define('partner_autocomplete.tests', function (require) { assert.strictEqual($input.length, 1, "there should be an for the field"); // Set incomplete VAT and assert changes - $input.val("BE047747270").trigger("input"); + testUtils.fields.editInput($input, "BE047747270") var $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 0, "there should be no opened dropdown no results with incomplete VAT number"); // Set complete VAT and assert changes // First suggestion (only vat result) - $input.val("BE0477472701").trigger("input"); + testUtils.fields.editInput($input, "BE0477472701") $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown"); assert.strictEqual($dropdown.children().length, 1, "there should be one proposition for complete VAT number"); - $dropdown.find("a").first().click(); + testUtils.dom.click($dropdown.find("a").first()); $input = form.$(".o_field_partner_autocomplete > input"); assert.strictEqual($input.val(), "Odoo", "Input value should have been updated to \"Odoo\""); @@ -313,12 +313,12 @@ odoo.define('partner_autocomplete.tests', function (require) { // Set complete VAT and assert changes // Second suggestion (only vat + clearbit result) - $input.val("BE0477472701").trigger("input"); + testUtils.fields.editInput($input, "BE0477472701") $dropdown = form.$(".o_field_partner_autocomplete .dropdown-menu:visible"); assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown"); assert.strictEqual($dropdown.children().length, 1, "there should be one proposition for complete VAT number"); - $dropdown.find("a").first().click(); + testUtils.dom.click($dropdown.find("a").first()); $input = form.$(".o_field_partner_autocomplete > input"); assert.strictEqual($input.val(), "Odoo", "Input value should have been updated to \"Odoo\""); @@ -356,12 +356,12 @@ odoo.define('partner_autocomplete.tests', function (require) { var $input = form.$('.o_field_many2one[name="parent_id"] input:visible'); assert.strictEqual($input.length, 1, "there should be an for the Many2one"); - $input.val('odoo').trigger('input'); + testUtils.fields.editInput($input, 'odoo'); concurrency.delay(0).then(function () { var $dropdown = $input.autocomplete('widget'); assert.strictEqual($dropdown.length, 1, "there should be an opened dropdown"); - assert.ok($dropdown.is('.o_partner_autocomplete_dropdown'), + assert.ok($dropdown.is('.o_partner_autocomplete_dropdown'), "there should be a partner_autocomplete"); PartnerField.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; diff --git a/addons/project/static/tests/project_tests.js b/addons/project/static/tests/project_tests.js index 35b41e93e9d..1e33ff2d15d 100644 --- a/addons/project/static/tests/project_tests.js +++ b/addons/project/static/tests/project_tests.js @@ -113,18 +113,24 @@ QUnit.module('project', { return this._super(route, args); }, }); - assert.strictEqual(kanban.$('img').length, 0, "Initially there is no image."); - kanban.$('.o_dropdown_kanban [data-type=set_cover]').eq(0).click(); - // single click on image - $('.modal').find("img[data-id='1']").click(); - $('.modal-footer .btn-primary').click(); - assert.strictEqual(kanban.$('img[data-src*="/web/image/1"]').length, 1, "Image inserted in record"); - $('.o_dropdown_kanban [data-type=set_cover]').eq(1).click(); + + testUtils.dom.click(kanban.$('.o_dropdown_kanban:first > a.dropdown-toggle')); + testUtils.dom.click(kanban.$('.o_dropdown_kanban:first [data-type=set_cover]')); + assert.containsNone(kanban, 'img', "Initially there is no image."); + // single click on image, and confirm + testUtils.dom.click($('.modal').find("img[data-id='1']")); + testUtils.dom.click($('.modal-footer .btn-primary')); + assert.containsOnce(kanban, 'img[data-src*="/web/image/1"]'); + + testUtils.dom.click(kanban.$('.o_dropdown_kanban:nth(1) > a.dropdown-toggle')); + testUtils.dom.click(kanban.$('.o_dropdown_kanban:nth(1) [data-type=set_cover]')); // double click on image $('.modal').find("img[data-id='2']").dblclick(); - assert.strictEqual(kanban.$('img[data-src*="/web/image/2"]').length, 1, "Image inserted after double click"); - // varify write on both kanban record - assert.verifySteps([1,2]); + assert.containsOnce(kanban, 'img[data-src*="/web/image/2"]'); + + // verify writes on both kanban records + assert.verifySteps([1, 2]); + kanban.destroy(); }); }); diff --git a/addons/sale/static/tests/product_configurator.test.js b/addons/sale/static/tests/product_configurator.test.js index 0cec92b8d3a..df7046b2a20 100644 --- a/addons/sale/static/tests/product_configurator.test.js +++ b/addons/sale/static/tests/product_configurator.test.js @@ -112,7 +112,7 @@ odoo.define('sale.product.configurator.tests', function (require) { assert.strictEqual(form.$("a:contains('Configure a product')").length, 1); - form.$("a:contains('Configure a product')").click(); + testUtils.dom.click(form.$("a:contains('Configure a product')")); }); QUnit.test('trigger_up the "add_record" event and checks that rows are correctly added to the list', function (assert) { @@ -161,8 +161,8 @@ odoo.define('sale.product.configurator.tests', function (require) { return this._super.apply(this, arguments); } }); - product_configurator_form.$('.o_input').click(); - $("ul.ui-autocomplete li a:contains('Customizable Desk')").mouseenter().click(); + testUtils.dom.click(product_configurator_form.$('.o_input')); + testUtils.dom.click($("ul.ui-autocomplete li a:contains('Customizable Desk')").mouseenter()); }); }); }); diff --git a/addons/sale/static/tests/sales_team_dashboard_tests.js b/addons/sale/static/tests/sales_team_dashboard_tests.js index b1043dd64e1..fca880dcc73 100644 --- a/addons/sale/static/tests/sales_team_dashboard_tests.js +++ b/addons/sale/static/tests/sales_team_dashboard_tests.js @@ -22,7 +22,7 @@ QUnit.module('Sales Team Dashboard', { } }); -QUnit.test('edit target with several o_kanban_primary_bottom divs', function (assert) { +QUnit.test('edit target with several o_kanban_primary_bottom divs [REQUIRE FOCUS]', function (assert) { assert.expect(4); var kanban = createView({ @@ -48,16 +48,15 @@ QUnit.test('edit target with several o_kanban_primary_bottom divs', function (as } return this._super.apply(this, arguments); }, - }); - assert.strictEqual(kanban.$('.o_kanban_view .sales_team_target_definition').length, 1, + assert.containsOnce(kanban, '.o_kanban_view .sales_team_target_definition', "should have classname 'sales_team_target_definition'"); - assert.strictEqual(kanban.$('.o_kanban_primary_bottom').length, 2, + assert.containsN(kanban, '.o_kanban_primary_bottom', 2, "should have two divs with classname 'o_kanban_primary_bottom'"); - kanban.$('a.sales_team_target_definition').click(); - assert.strictEqual(kanban.$('.o_kanban_primary_bottom:last input').length, 1, + testUtils.dom.click(kanban.$('a.sales_team_target_definition')); + assert.containsOnce(kanban, '.o_kanban_primary_bottom:last input', "should have rendered an input in the last o_kanban_primary_bottom div"); kanban.$('.o_kanban_primary_bottom:last input').focus(); diff --git a/addons/sale_timesheet/static/tests/timesheet_plan_tests.js b/addons/sale_timesheet/static/tests/timesheet_plan_tests.js index d1d71c4face..ca63776ab6b 100644 --- a/addons/sale_timesheet/static/tests/timesheet_plan_tests.js +++ b/addons/sale_timesheet/static/tests/timesheet_plan_tests.js @@ -10,7 +10,7 @@ function createPlan(params) { do_push_state: function () {}, }); var parent = new Parent(); - testUtils.addMockEnvironment(parent, params); + testUtils.mock.addMockEnvironment(parent, params); var plan = new ProjectPlan(parent, params.action); var selector = params.debug ? 'body' : '#qunit-fixture'; plan.appendTo($(selector)); diff --git a/addons/sms/static/src/tests/sms_widget_test.js b/addons/sms/static/src/tests/sms_widget_test.js index 403f2d3e560..e2e58e198a1 100644 --- a/addons/sms/static/src/tests/sms_widget_test.js +++ b/addons/sms/static/src/tests/sms_widget_test.js @@ -1,6 +1,6 @@ odoo.define('sms.sms_widget_tests', function (require) { "use strict"; - + var FormView = require('web.FormView'); var testUtils = require('web.test_utils'); @@ -21,7 +21,7 @@ QUnit.module('fields', { }; } }, function () { - + QUnit.module('SmsWidget'); QUnit.test('Sms widgets are correctly rendered', function (assert) { @@ -32,7 +32,6 @@ QUnit.module('fields', { data: this.data, arch: '
', }); - form.$buttons.find('.o_form_button_edit').click(); assert.ok(form.$('.o_sms_count').length, "Should have a sms counter"); assert.strictEqual(form.$('.o_sms_count').text(), '0 chars, fits in 0 SMS (GSM7) ', 'Should be "0 chars, fits in 0 SMS (GSM7) " by default'); // GSM-7 @@ -60,7 +59,7 @@ QUnit.module('fields', { text = Array(72).join('ê'); form.$('.o_input').val(text).trigger('input'); assert.strictEqual(form.$('.o_sms_count').text(), '71 chars, fits in 2 SMS (UNICODE) ', 'Should be "71 chars, fits in 2 SMS (UNICODE) " for 71 x "ê"'); - + form.destroy(); }); }); diff --git a/addons/web/static/src/js/tools/test_menus.js b/addons/web/static/src/js/tools/test_menus.js index e274839c48d..f7c5d61bc96 100644 --- a/addons/web/static/src/js/tools/test_menus.js +++ b/addons/web/static/src/js/tools/test_menus.js @@ -14,7 +14,7 @@ var Discuss = odoo.__DEBUG__.services['mail.Discuss']; var WebClient = odoo.__DEBUG__.services["web.WebClient"]; - WebClient.include({ + WebClient.include({ current_action_updated : function (action, controller) { this._super(action, controller); clientActionCount++; @@ -57,7 +57,7 @@ if (isEnterprise) { console.log("Odoo flavor: Enterprise") var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th"); - $homeMenu.click() + testUtils.dom.click($homeMenu); $listOfAppMenuItems = $(".o_app, .o_menuitem") } else { console.log("Odoo flavor: Community") @@ -73,10 +73,10 @@ console.log("ok"); }).always(function() { console.log("Test took ", (performance.now() - startTime)/1000, " seconds"); - }).fail(function () { + }).fail(function () { console.error("Error !") }); - } + } /** @@ -101,7 +101,7 @@ }).then(function(){ // no effect in community var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th"); - $homeMenu.click(); + testUtils.dom.click($homeMenu); }); } @@ -119,7 +119,7 @@ console.log("Testing menu", element.innerText.trim(), " ", element.dataset.menuXmlid); testedMenus.push(element.dataset.menuXmlid); var startActionCount = clientActionCount; - element.click(); + testUtils.dom.click(element); var isModal = false; return waitForCondition(function() { // sometimes, the app is just a modal that needs to be closed @@ -173,7 +173,7 @@ setTimeout(function() { var $element = $("nav.o_cp_switch_buttons > button[data-view-type=" + viewType + "]"); console.log('Clicking on: ', $element[0].dataset.viewType, ' view switcher'); - $element.click(); + testUtils.dom.click($element); },250); var waitViewSwitch = waitForCondition(function(){ return $('.o_content > .o_view_controller').data('view-type') === viewType; @@ -203,16 +203,16 @@ return $.Deferred().resolve(); }; console.log('Clicking on filter "', $filter.text().trim(), '"'); - $filter[0].click(); + testUtils.dom.click($filter[0]); setTimeout(function() { var $filterOption = $('.o_menu_item .o_item_option[data-item_id="' + filter_id + '"]:not(.selected) a'); // In case the filter is a date filter, we need to click on the first filter option (like 'today','This week' ...) if ($filterOption.length > 0) { console.log('Clicking on filter option "', $filterOption[0], '"'); - $filterOption[0].click(); + testUtils.dom.click($filterOption[0]); console.log('And now on filter again'); $filter = $('.o_menu_item[data-id="' + filter_id + '"] a'); - $filter[0].click(); // To avoid that the next view fold the options + testUtils.dom.click($filter[0]); } }, 250); return waitForCondition(function() { @@ -251,7 +251,7 @@ return def; }; - + /** * chain deferred actions * @param $elements: a list of jquery elements to be passed as arg to the function diff --git a/addons/web/static/tests/chrome/action_manager_mobile_tests.js b/addons/web/static/tests/chrome/action_manager_mobile_tests.js index 86738330add..b105c861c26 100644 --- a/addons/web/static/tests/chrome/action_manager_mobile_tests.js +++ b/addons/web/static/tests/chrome/action_manager_mobile_tests.js @@ -65,18 +65,14 @@ QUnit.module('ActionManager', { // should default on a mobile-friendly view (kanban) for action 1 actionManager.doAction(1); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, - "should not have rendered the list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, - "should have rendered the kanban view"); + assert.containsNone(actionManager, '.o_list_view'); + assert.containsOnce(actionManager, '.o_kanban_view'); // there is no mobile-friendly view for action 2, should use the first one (list) actionManager.doAction(2); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, - "should have rendered the list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, - "there should be no kanban view in the DOM"); + assert.containsOnce(actionManager, '.o_list_view'); + assert.containsNone(actionManager, '.o_kanban_view'); actionManager.destroy(); }); @@ -98,21 +94,15 @@ QUnit.module('ActionManager', { view_type: 'form', }); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, - "should not have rendered a list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, - "should not have rendered a kanban view either"); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, - "should have rendered a form view"); + assert.containsNone(actionManager, '.o_list_view'); + assert.containsNone(actionManager, '.o_kanban_view'); + assert.containsOnce(actionManager, '.o_form_view'); // go back to lazy loaded view - $('.o_control_panel .breadcrumb a').click(); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, - "should not display the form view anymore"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, - "should not display the list view either"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, - "should have lazy loaded the kanban view"); + testUtils.dom.click($('.o_control_panel .breadcrumb .breadcrumb-item:first')); + assert.containsNone(actionManager, '.o_form_view'); + assert.containsNone(actionManager, '.o_list_view'); + assert.containsOnce(actionManager, '.o_kanban_view'); assert.verifySteps([ '/web/action/load', @@ -135,12 +125,9 @@ QUnit.module('ActionManager', { actionManager.doAction(1); - assert.ok($('.o_control_panel .o_cp_switch_buttons button[data-toggle="dropdown"]').length, 1, - "view switcher button should be displayed"); - assert.ok($('.o_cp_switch_buttons .o_cp_switch_kanban').hasClass('active'), - "kanban should be the active view"); - assert.ok($('.o_cp_switch_buttons .o_switch_view_button_icon').hasClass('fa-th-large'), - "view switcher button icon should be an icon of the kanban"); + assert.containsOnce($('.o_control_panel'), '.o_cp_switch_buttons button[data-toggle="dropdown"]'); + assert.hasClass($('.o_cp_switch_buttons .o_cp_switch_kanban'), 'active'); + assert.hasClass($('.o_cp_switch_buttons .o_switch_view_button_icon'), 'fa-th-large'); actionManager.destroy(); }); diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index 7424d31f365..3eea9bda3a0 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -176,7 +176,7 @@ QUnit.module('ActionManager', { assert.expect(1); var delta = 0; - testUtils.patch(Widget, { + testUtils.mock.patch(Widget, { init: function () { delta++; this._super.apply(this, arguments); @@ -197,23 +197,23 @@ QUnit.module('ActionManager', { var n = delta; actionManager.doAction(4); // kanban view is loaded, switch to list view - $('.o_control_panel .o_cp_switch_list').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // go back to action 7 in breadcrumbs - $('.o_control_panel .breadcrumb a:first').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:first')); assert.strictEqual(delta, n, "should have properly destroyed all other widgets"); actionManager.destroy(); - testUtils.unpatch(Widget); + testUtils.mock.unpatch(Widget); }); QUnit.test('no widget memory leaks when executing actions in dialog', function (assert) { assert.expect(1); var delta = 0; - testUtils.patch(Widget, { + testUtils.mock.patch(Widget, { init: function () { delta++; this._super.apply(this, arguments); @@ -240,7 +240,7 @@ QUnit.module('ActionManager', { "should have properly destroyed all widgets"); actionManager.destroy(); - testUtils.unpatch(Widget); + testUtils.mock.unpatch(Widget); }); QUnit.test('no memory leaks when executing an action while switching view', function (assert) { @@ -248,7 +248,7 @@ QUnit.module('ActionManager', { var def; var delta = 0; - testUtils.patch(Widget, { + testUtils.mock.patch(Widget, { init: function () { delta += 1; this._super.apply(this, arguments); @@ -279,7 +279,7 @@ QUnit.module('ActionManager', { // switch to the form view (this request is blocked) def = $.Deferred(); - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // execute another action meanwhile (don't block this request) actionManager.doAction(4, {clear_breadcrumbs: true}); @@ -291,7 +291,7 @@ QUnit.module('ActionManager', { "all widgets of action 3 should have been destroyed"); actionManager.destroy(); - testUtils.unpatch(Widget); + testUtils.mock.unpatch(Widget); }); QUnit.test('no memory leaks when executing an action while loading views', function (assert) { @@ -299,7 +299,7 @@ QUnit.module('ActionManager', { var def; var delta = 0; - testUtils.patch(Widget, { + testUtils.mock.patch(Widget, { init: function () { delta += 1; this._super.apply(this, arguments); @@ -339,7 +339,7 @@ QUnit.module('ActionManager', { "all widgets of action 3 should have been destroyed"); actionManager.destroy(); - testUtils.unpatch(Widget); + testUtils.mock.unpatch(Widget); }); QUnit.test('no memory leaks when executing an action while loading data of default view', function (assert) { @@ -347,7 +347,7 @@ QUnit.module('ActionManager', { var def; var delta = 0; - testUtils.patch(Widget, { + testUtils.mock.patch(Widget, { init: function () { delta += 1; this._super.apply(this, arguments); @@ -387,7 +387,7 @@ QUnit.module('ActionManager', { "all widgets of action 3 should have been destroyed"); actionManager.destroy(); - testUtils.unpatch(Widget); + testUtils.mock.unpatch(Widget); }); QUnit.test('action with "no_breadcrumbs" set to true', function (assert) { @@ -423,11 +423,11 @@ QUnit.module('ActionManager', { // execute action 3 and open a record in form view actionManager.doAction(3); - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // execute action 4 without 'on_reverse_breadcrumb' handler, then go back actionManager.doAction(4); - $('.o_control_panel .breadcrumb a:first').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:first')); assert.verifySteps([]); // execute action 4 with an 'on_reverse_breadcrumb' handler, then go back @@ -436,7 +436,7 @@ QUnit.module('ActionManager', { assert.step('on_reverse_breadcrumb'); } }); - $('.o_control_panel .breadcrumb a:first').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:first')); assert.verifySteps(['on_reverse_breadcrumb']); actionManager.destroy(); @@ -495,7 +495,7 @@ QUnit.module('ActionManager', { // go back using the breadcrumbs assert.step('go back to action 3'); - $('.o_control_panel .breadcrumb a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a')); assert.verifySteps([ 'execute action 3', @@ -534,7 +534,7 @@ QUnit.module('ActionManager', { }); actionManager.doAction(4); actionManager.doAction(8); - actionManager.$('tr.o_data_row:first').click(); + testUtils.dom.click(actionManager.$('tr.o_data_row:first')); actionManager.destroy(); }); @@ -610,10 +610,10 @@ QUnit.module('ActionManager', { }); actionManager.doAction(8); assert.verifySteps(['push_state']); - actionManager.$('tr.o_data_row:first').click(); + testUtils.dom.click(actionManager.$('tr.o_data_row:first')); assert.verifySteps(['push_state']); // we make sure here that the list view is still in the dom - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "there should still be a list view in dom"); actionManager.destroy(); @@ -694,7 +694,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel').length, 1, "should have rendered a control panel"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should have rendered a kanban view"); assert.verifySteps([ @@ -723,7 +723,7 @@ QUnit.module('ActionManager', { model: 'partner', }); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should have rendered a form view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Second record', "should have opened the second record"); @@ -753,9 +753,9 @@ QUnit.module('ActionManager', { view_type: 'kanban', }); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not have rendered a list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should have rendered a kanban view"); assert.verifySteps([ @@ -785,9 +785,9 @@ QUnit.module('ActionManager', { view_type: 'form', }); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not have rendered a list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should have rendered a form view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); @@ -795,10 +795,10 @@ QUnit.module('ActionManager', { "breadcrumbs should contain the display_name of the opened record"); // go back to Lst - $('.o_control_panel .breadcrumb a').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click($('.o_control_panel .breadcrumb a')); + assert.containsOnce(actionManager, '.o_list_view', "should now display the list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should not display the form view anymore"); assert.verifySteps([ @@ -818,7 +818,6 @@ QUnit.module('ActionManager', { actions: this.actions, archs: this.archs, data: this.data, - debug: 1, }); actionManager.doAction(4); @@ -838,7 +837,7 @@ QUnit.module('ActionManager', { "the breadcrumb elements should be correctly ordered"); // go back to List - $('.o_control_panel .breadcrumb a:last').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:last')); assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2, "there should be two controllers in the breadcrumbs"); @@ -862,7 +861,7 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should have rendered a list view"); // switch to kanban view @@ -871,9 +870,9 @@ QUnit.module('ActionManager', { view_type: 'kanban', }); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not display the list view anymore"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should have switched to the kanban view"); // switch to form view, open record 4 @@ -883,9 +882,9 @@ QUnit.module('ActionManager', { view_type: 'form', }); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "should not display the kanban view anymore"); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should have switched to the form view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); @@ -921,9 +920,9 @@ QUnit.module('ActionManager', { // execute action 3 and open the first record in a form view actionManager.doAction(3); - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should have rendered a form view"); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record', "should have opened the first record"); @@ -935,7 +934,7 @@ QUnit.module('ActionManager', { view_type: 'form', }); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should still display the form view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); @@ -973,7 +972,7 @@ QUnit.module('ActionManager', { assert.verifySteps([], "should not push the loaded state"); - actionManager.$('tr.o_data_row:first').click(); + testUtils.dom.click(actionManager.$('tr.o_data_row:first')); assert.verifySteps(['push_state'], "should push the state of it changes afterwards"); @@ -1023,7 +1022,7 @@ QUnit.module('ActionManager', { assert.verifySteps([], "should not push the loaded state"); - actionManager.$('button').click(); + testUtils.dom.click(actionManager.$('button')); assert.verifySteps(['push_state'], "should push the state of it changes afterwards"); @@ -1104,7 +1103,7 @@ QUnit.module('ActionManager', { }, }); - testUtils.intercept(actionManager, 'call_service', function (ev) { + testUtils.mock.intercept(actionManager, 'call_service', function (ev) { if (ev.data.service === 'session_storage') { assert.step(ev.data.method); } @@ -1112,7 +1111,7 @@ QUnit.module('ActionManager', { actionManager.doAction(4); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should display a kanban view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners Action 4', "breadcrumbs should display the display_name of the action"); @@ -1124,9 +1123,9 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners Action 4', "should still be in the same action"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "should no longer display a kanban view"); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display a list view"); assert.verifySteps([ @@ -1168,7 +1167,7 @@ QUnit.module('ActionManager', { def.resolve(); // action 4 loads a kanban view first, 6 loads a list view. We want a list - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', 'there should be a list view in DOM'); assert.verifySteps([ @@ -1204,11 +1203,11 @@ QUnit.module('ActionManager', { actionManager.doAction(4); // kanban view is loaded, switch to list view - $('.o_control_panel .o_cp_switch_list').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); // here, list view is not ready yet, because def is not resolved // switch back to kanban view - $('.o_control_panel .o_cp_switch_kanban').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); // here, we want the kanban view to reload itself, regardless of list view assert.verifySteps([ @@ -1222,9 +1221,9 @@ QUnit.module('ActionManager', { // we resolve def => list view is now ready (but we want to ignore it) def.resolve(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "there should be a kanban view in dom"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "there should not be a list view in dom"); actionManager.destroy(); @@ -1278,7 +1277,7 @@ QUnit.module('ActionManager', { // create a situation with 3 breadcrumbs: kanban/form/list actionManager.doAction(4); - actionManager.$('.o_kanban_record:first').click(); + testUtils.dom.click(actionManager.$('.o_kanban_record:first')); actionManager.doAction(8); // now, the next read operations will be deferred (this is the read @@ -1287,8 +1286,8 @@ QUnit.module('ActionManager', { // click on the breadcrumbs for the form view, then on the kanban view // before the form view is fully reloaded - $('.o_control_panel .breadcrumb-item:eq(1)').click(); - $('.o_control_panel .breadcrumb-item:eq(0)').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb-item:eq(1)')); + testUtils.dom.click($('.o_control_panel .breadcrumb-item:eq(0)')); // resolve the form view read def.resolve(); @@ -1322,22 +1321,22 @@ QUnit.module('ActionManager', { view_type: 'form', }); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should display the form view of action 4"); // click to go back to Kanban (this request is blocked) def = $.Deferred(); - $('.o_control_panel .breadcrumb a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a')); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should still display the form view of action 4"); // execute another action meanwhile (don't block this request) actionManager.doAction(8, {clear_breadcrumbs: true}); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display action 8"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should no longer display the form view"); assert.verifySteps([ @@ -1353,9 +1352,9 @@ QUnit.module('ActionManager', { // unblock the switch to Kanban in action 4 def.resolve(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should still display action 8"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "should not display the kanban view of action 4"); assert.verifySteps([ @@ -1391,23 +1390,23 @@ QUnit.module('ActionManager', { // execute action 3 and open a record in form view actionManager.doAction(3); - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should display the form view of action 3"); // click on 'Call method' button (this request is blocked) - actionManager.$('.o_form_view button:contains(Call method)').click(); + testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)')); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should still display the form view of action 3"); // execute another action actionManager.doAction(8, {clear_breadcrumbs: true}); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view of action 8"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should no longer display the form view"); assert.verifySteps([ @@ -1424,9 +1423,9 @@ QUnit.module('ActionManager', { // unblock the call_button request def.resolve(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should still display the list view of action 8"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "should not display action 1"); assert.verifySteps([ @@ -1463,22 +1462,22 @@ QUnit.module('ActionManager', { actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view of action 3"); // switch to the form view (this request is blocked) def = $.Deferred(); - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should still display the list view of action 3"); // execute another action meanwhile (don't block this request) actionManager.doAction(4, {clear_breadcrumbs: true}); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should display the kanban view of action 8"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should no longer display the list view"); assert.verifySteps([ @@ -1494,9 +1493,9 @@ QUnit.module('ActionManager', { // unblock the switch to the form view in action 3 def.resolve(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should still display the kanban view of action 8"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should not display the form view of action 3"); assert.verifySteps([ @@ -1534,16 +1533,16 @@ QUnit.module('ActionManager', { def = $.Deferred(); actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not display the list view of action 3"); // execute another action meanwhile (and unlock the RPC) actionManager.doAction(4); def.resolve(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should display the kanban view of action 4"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not display the list view of action 3"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should be one controller in the breadcrumbs"); @@ -1581,16 +1580,16 @@ QUnit.module('ActionManager', { def = $.Deferred(); actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not display the list view of action 3"); // execute another action meanwhile (and unlock the RPC) actionManager.doAction(4); def.resolve(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should display the kanban view of action 4"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not display the list view of action 3"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should be one controller in the breadcrumbs"); @@ -1626,26 +1625,26 @@ QUnit.module('ActionManager', { actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); - assert.strictEqual(actionManager.$('.o_list_view .o_data_row').length, 5, + assert.containsN(actionManager, '.o_list_view .o_data_row', 5, "list view should contain 5 records"); assert.strictEqual($('.o_control_panel .o_list_buttons').length, 1, "list view buttons should be displayed in control panel"); // reload (the search_read RPC will be blocked) def = $.Deferred(); - $('.o_control_panel .o_cp_switch_list').click(); // click on the switch button + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); - assert.strictEqual(actionManager.$('.o_list_view .o_data_row').length, 5, + assert.containsN(actionManager, '.o_list_view .o_data_row', 5, "list view should still contain 5 records"); assert.strictEqual($('.o_control_panel .o_list_buttons').length, 1, "list view buttons should still be displayed in control panel"); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should display the form view"); assert.strictEqual($('.o_control_panel .o_list_buttons').length, 0, "list view buttons should no longer be displayed in control panel"); @@ -1655,9 +1654,9 @@ QUnit.module('ActionManager', { // unblock the search_read RPC def.resolve(); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should display the form view"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should not display the list view"); assert.strictEqual($('.o_control_panel .o_list_buttons').length, 0, "list view buttons should still not be displayed in control panel"); @@ -1774,7 +1773,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('ol.breadcrumb').text(), "initial title", "should have initial title as breadcrumb content"); - actionManager.$('.o_client_action_test').click(); + testUtils.dom.click(actionManager.$('.o_client_action_test')); assert.strictEqual($('ol.breadcrumb').text(), "new title", "should have updated title as breadcrumb content"); @@ -1805,7 +1804,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel:visible').length, 1, "should have rendered a control panel"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should have rendered a kanban view"); assert.verifySteps([ '/web/action/load', @@ -2013,7 +2012,7 @@ QUnit.module('ActionManager', { // usecase, using removeSRCAttribute doesn't work as the RPC is // triggered as soon as the iframe is in the DOM, even if its src // attribute is removed right after) - testUtils.patch(ReportClientAction, { + testUtils.mock.patch(ReportClientAction, { start: function () { var self = this; return this._super.apply(this, arguments).then(function () { @@ -2053,7 +2052,7 @@ QUnit.module('ActionManager', { }); actionManager.doAction(7); - assert.strictEqual(actionManager.$('.o_report_iframe').length, 1, + assert.containsOnce(actionManager, '.o_report_iframe', "should have opened the report client action"); assert.verifySteps([ @@ -2064,7 +2063,7 @@ QUnit.module('ActionManager', { ]); actionManager.destroy(); - testUtils.unpatch(ReportClientAction); + testUtils.mock.unpatch(ReportClientAction); }); QUnit.module('Window Actions'); @@ -2085,7 +2084,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel').length, 1, "should have rendered a control panel"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should have rendered a kanban view"); assert.verifySteps([ '/web/action/load', @@ -2110,37 +2109,37 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); // switch to kanban view - $('.o_control_panel .o_cp_switch_kanban').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + assert.containsNone(actionManager, '.o_list_view', "should no longer display the list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should display the kanban view"); // switch back to list view - $('.o_control_panel .o_cp_switch_list').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "should no longer display the kanban view"); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); + assert.containsNone(actionManager, '.o_list_view', "should no longer display the list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should display the form view"); assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop', "should have opened the correct record"); // go back to list view using the breadcrumbs - $('.o_control_panel .breadcrumb a').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click($('.o_control_panel .breadcrumb a')); + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should no longer display the form view"); assert.verifySteps([ @@ -2172,28 +2171,28 @@ QUnit.module('ActionManager', { "breadcrumbs should display the display_name of the action"); // switch to kanban view - $('.o_control_panel .o_cp_switch_kanban').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should still be one controller in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners', "breadcrumbs should still display the display_name of the action"); // switch back to list view - $('.o_control_panel .o_cp_switch_list').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should still be one controller in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners', "breadcrumbs should still display the display_name of the action"); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record', "breadcrumbs should contain the display_name of the opened record"); // go back to list view using the breadcrumbs - $('.o_control_panel .breadcrumb a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should be one controller in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners', @@ -2216,39 +2215,39 @@ QUnit.module('ActionManager', { "should have two switch buttons (list and kanban)"); assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1, "should have only one active button"); - assert.ok($('.o_control_panel .o_cp_switch_buttons button:first').hasClass('o_cp_switch_list'), + assert.hasClass($('.o_control_panel .o_cp_switch_buttons button:first'),'o_cp_switch_list', "list switch button should be the first one"); - assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'), + assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', "list should be the active view"); // switch to kanban view - $('.o_control_panel .o_cp_switch_kanban').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, "should still have two switch buttons (list and kanban)"); assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1, "should still have only one active button"); - assert.ok($('.o_control_panel .o_cp_switch_buttons button:first').hasClass('o_cp_switch_list'), + assert.hasClass($('.o_control_panel .o_cp_switch_buttons button:first'),'o_cp_switch_list', "list switch button should still be the first one"); - assert.ok($('.o_control_panel .o_cp_switch_kanban').hasClass('active'), + assert.hasClass($('.o_control_panel .o_cp_switch_kanban'),'active', "kanban should now be the active view"); // switch back to list view - $('.o_control_panel .o_cp_switch_list').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, "should still have two switch buttons (list and kanban)"); - assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'), + assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', "list should now be the active view"); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 0, "should not have any switch buttons"); // go back to list view using the breadcrumbs - $('.o_control_panel .breadcrumb a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a')); assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, "should have two switch buttons (list and kanban)"); - assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'), + assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', "list should be the active view"); actionManager.destroy(); @@ -2270,28 +2269,28 @@ QUnit.module('ActionManager', { "limit should be correct for kanban"); // switch to list view - $('.o_control_panel .o_cp_switch_list').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-3', "value should be correct for list"); assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5', "limit should be correct for list"); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1', "value should be correct for form"); assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '3', "limit should be correct for form"); // go back to list view using the breadcrumbs - $('.o_control_panel .breadcrumb a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a')); assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-3', "value should be correct for list"); assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5', "limit should be correct for list"); // switch back to kanban view - $('.o_control_panel .o_cp_switch_kanban').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-5', "value should be correct for kanban"); assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5', @@ -2317,60 +2316,60 @@ QUnit.module('ActionManager', { // switch to kanban view def = $.Deferred(); - $('.o_control_panel .o_cp_switch_kanban').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + assert.containsOnce(actionManager, '.o_list_view', "should still display the list view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "shouldn't display the kanban view yet"); def.resolve(); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "shouldn't display the list view anymore"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should now display the kanban view"); // switch back to list view def = $.Deferred(); - $('.o_control_panel .o_cp_switch_list').click(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + assert.containsOnce(actionManager, '.o_kanban_view', "should still display the kanban view"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "shouldn't display the list view yet"); def.resolve(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 0, + assert.containsNone(actionManager, '.o_kanban_view', "shouldn't display the kanban view anymore"); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should now display the list view"); // open a record in form view def = $.Deferred(); - actionManager.$('.o_list_view .o_data_row:first').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); + assert.containsOnce(actionManager, '.o_list_view', "should still display the list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "shouldn't display the form view yet"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should still be one controller in the breadcrumbs"); def.resolve(); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "should no longer display the list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should display the form view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); // go back to list view using the breadcrumbs def = $.Deferred(); - $('.o_control_panel .breadcrumb a').click(); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + testUtils.dom.click($('.o_control_panel .breadcrumb a')); + assert.containsOnce(actionManager, '.o_form_view', "should still display the form view"); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "shouldn't display the list view yet"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should still be two controllers in the breadcrumbs"); def.resolve(); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should no longer display the form view"); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should be one controller in the breadcrumbs"); @@ -2389,16 +2388,16 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record', "breadcrumbs should contain the display_name of the opened record"); // switch to edit mode and change the display_name - $('.o_control_panel .o_form_button_edit').click(); - actionManager.$('.o_field_widget[name=display_name]').val('New name').trigger('input'); - $('.o_control_panel .o_form_button_save').click(); + testUtils.dom.click($('.o_control_panel .o_form_button_edit')); + testUtils.fields.editInput(actionManager.$('.o_field_widget[name=display_name]'), 'New name'); + testUtils.dom.click($('.o_control_panel .o_form_button_save')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should still be two controllers in the breadcrumbs"); @@ -2423,13 +2422,13 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // create a new record - $('.o_control_panel .o_list_button_add').click(); - assert.strictEqual(actionManager.$('.o_form_view.o_form_editable').length, 1, + testUtils.dom.click($('.o_control_panel .o_list_button_add')); + assert.containsOnce(actionManager, '.o_form_view.o_form_editable', "should have opened the form view in edit mode"); // discard - $('.o_control_panel .o_form_button_cancel').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click($('.o_control_panel .o_form_button_cancel')); + assert.containsOnce(actionManager, '.o_list_view', "should have switched back to the list view"); assert.verifySteps([ @@ -2472,12 +2471,12 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop', "check initial value of 'yop' field"); // click on 'Call method' button (should call an Object method) - actionManager.$('.o_form_view button:contains(Call method)').click(); + testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)')); assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'value changed', "'yop' has been changed by the server, and should be updated in the UI"); @@ -2508,15 +2507,15 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // click on 'Execute action' button (should execute an action) assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two parts in the breadcrumbs"); - actionManager.$('.o_form_view button:contains(Execute action)').click(); + testUtils.dom.click(actionManager.$('.o_form_view button:contains(Execute action)')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 3, "the returned action should have been stacked over the previous one"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "the returned action should have been executed"); assert.verifySteps([ @@ -2555,11 +2554,11 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // click on 'Call method' button (should call an Object method) def = $.Deferred(); - actionManager.$('.o_form_view button:contains(Call method)').click(); + testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)')); // Buttons should be disabled assert.strictEqual( @@ -2592,17 +2591,17 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open the first record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record', "breadcrumbs should contain the display_name of the opened record"); assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop', "should have opened the correct record"); // go back to list view using the breadcrumbs - $('.o_control_panel .breadcrumb a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a')); // open the second record in form view - actionManager.$('.o_list_view .o_data_row:nth(1)').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:nth(1)')); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Second record', "breadcrumbs should contain the display_name of the opened record"); assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'blip', @@ -2633,23 +2632,23 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.ok($('.o_control_panel .fa-bar-chart-o').hasClass('active'), + assert.hasClass($('.o_control_panel .fa-bar-chart-o'),'active', "bar chart button is active"); - assert.ok(!$('.o_control_panel .fa-area-chart').hasClass('active'), + assert.doesNotHaveClass($('.o_control_panel .fa-area-chart'), 'active', "line chart button is not active"); // display line chart - $('.o_control_panel .fa-area-chart').click(); - assert.ok($('.o_control_panel .fa-area-chart').hasClass('active'), + testUtils.dom.click($('.o_control_panel .fa-area-chart')); + assert.hasClass($('.o_control_panel .fa-area-chart'),'active', "line chart button is now active"); // switch to kanban and back to graph view - $('.o_control_panel .o_cp_switch_kanban').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); assert.strictEqual($('.o_control_panel .fa-area-chart').length, 0, "graph buttons are no longer in control panel"); - $('.o_control_panel .o_cp_switch_graph').click(); - assert.ok($('.o_control_panel .fa-area-chart').hasClass('active'), + testUtils.dom.click($('.o_control_panel .o_cp_switch_graph')); + assert.hasClass($('.o_control_panel .fa-area-chart'),'active', "line chart button is still active"); actionManager.destroy(); }); @@ -2669,16 +2668,16 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'), + assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', "list button in control panel is active"); - assert.ok(!$('.o_control_panel .o_cp_switch_graph').hasClass('active'), + assert.doesNotHaveClass($('.o_control_panel .o_cp_switch_graph'), 'active', "graph button in control panel is not active"); // switch to graph view - $('.o_control_panel .o_cp_switch_graph').click(); - assert.ok(!$('.o_control_panel .o_cp_switch_list').hasClass('active'), + testUtils.dom.click($('.o_control_panel .o_cp_switch_graph')); + assert.doesNotHaveClass($('.o_control_panel .o_cp_switch_list'), 'active', "list button in control panel is not active"); - assert.ok($('.o_control_panel .o_cp_switch_graph').hasClass('active'), + assert.hasClass($('.o_control_panel .o_cp_switch_graph'),'active', "graph button in control panel is active"); actionManager.destroy(); }); @@ -2698,18 +2697,16 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.ok(!actionManager.$('.o_list_view').hasClass('o_list_view_grouped'), + assert.doesNotHaveClass(actionManager.$('.o_list_view'), 'o_list_view_grouped', "list view is not grouped"); - // open search view sub menus - $('.o_control_panel .o_searchview_more').click(); // open group by dropdown - $('.o_control_panel .o_cp_right button:contains(Group By)').click(); + testUtils.dom.click($('.o_control_panel .o_cp_right button:contains(Group By)')); // click on first link - $('.o_control_panel .o_group_by_menu a:first').click(); + testUtils.dom.click($('.o_control_panel .o_group_by_menu a:first')); - assert.ok(actionManager.$('.o_list_view').hasClass('o_list_view_grouped'), + assert.hasClass(actionManager.$('.o_list_view'),'o_list_view_grouped', 'list view is now grouped'); actionManager.destroy(); @@ -2747,12 +2744,12 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open first record in form view - actionManager.$('.o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_data_row:first')); // click on edit - $('.o_control_panel .o_form_button_edit').click(); + testUtils.dom.click($('.o_control_panel .o_form_button_edit')); // click on external button for m2o - actionManager.$('.o_external_button').click(); + testUtils.dom.click(actionManager.$('.o_external_button')); assert.verifySteps([ '/web/action/load', // initial load action '/web/dataset/call_kw/partner', // load views @@ -2776,34 +2773,34 @@ QUnit.module('ActionManager', { actionManager.doAction(4); // open record in form view - actionManager.$('.o_kanban_record:first').click(); + testUtils.dom.click(actionManager.$('.o_kanban_record:first')); // edit record - $('.o_control_panel button.o_form_button_edit').click(); - actionManager.$('input[name="foo"]').val('pinkypie').trigger('input'); + testUtils.dom.click($('.o_control_panel button.o_form_button_edit')); + testUtils.fields.editInput(actionManager.$('input[name="foo"]'), 'pinkypie'); // go back to kanban view - $('.o_control_panel .breadcrumb-item:first a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb-item:first a')); assert.strictEqual($('.modal .modal-body').text(), "The record has been modified, your changes will be discarded. Do you want to proceed?", "should display a modal dialog to confirm discard action"); // cancel - $('.modal .modal-footer button.btn-secondary').click(); + testUtils.dom.click($('.modal .modal-footer button.btn-secondary')); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "should still be in form view"); // go back again to kanban view - $('.o_control_panel .breadcrumb-item:first a').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb-item:first a')); // confirm discard - $('.modal .modal-footer button.btn-primary').click(); + testUtils.dom.click($('.modal .modal-footer button.btn-primary')); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should no longer be in form view"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should be in kanban view"); actionManager.destroy(); @@ -2820,11 +2817,11 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_data_row').length, 2, + assert.containsN(actionManager, '.o_data_row', 2, "should only display 2 record"); // switch to kanban view - $('.o_control_panel .o_cp_switch_kanban').click(); + testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); assert.strictEqual(actionManager.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, "should only display 2 record"); @@ -2843,7 +2840,7 @@ QUnit.module('ActionManager', { actionManager.doAction(3); // open a record in form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record', @@ -2856,7 +2853,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Partners Action 4', "breadcrumbs should contain the name of the current action"); // go back using the breadcrumbs - $('.o_control_panel .breadcrumb a:nth(1)').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:nth(1)')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2, "there should be two controllers in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record', @@ -2869,7 +2866,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Partners Action 4', "breadcrumbs should contain the name of the current action"); // go back using the breadcrumbs - $('.o_control_panel .breadcrumb a:first').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:first')); assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1, "there should be one controller in the breadcrumbs"); assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Partners', @@ -2920,25 +2917,24 @@ QUnit.module('ActionManager', { }); actionManager.doAction(3); - assert.strictEqual(actionManager.$('.o_list_view_grouped').length, 1, + assert.containsOnce(actionManager, '.o_list_view_grouped', "should be grouped"); - assert.strictEqual(actionManager.$('.o_group_header').length, 2, + assert.containsN(actionManager, '.o_group_header', 2, "should be grouped by 'bar' (two groups) at first load"); // groupby 'bar' using the searchview - $('.o_control_panel .o_searchview_more').click(); // open search view sub menus - $('.o_control_panel .o_cp_right button:contains(Group By)').click(); // open groupby dropdown - $('.o_control_panel .o_group_by_menu a:first').click(); // click on 'Foo' + testUtils.dom.click($('.o_control_panel .o_cp_right button:contains(Group By)')); + testUtils.dom.click($('.o_control_panel .o_group_by_menu a:first')); - assert.strictEqual(actionManager.$('.o_group_header').length, 5, + assert.containsN(actionManager, '.o_group_header', 5, "should be grouped by 'foo' (five groups)"); // remove the groupby in the searchview - $('.o_control_panel .o_searchview .o_facet_remove').click(); + testUtils.dom.click($('.o_control_panel .o_searchview .o_facet_remove')); - assert.strictEqual(actionManager.$('.o_list_view_grouped').length, 1, + assert.containsOnce(actionManager, '.o_list_view_grouped', "should still be grouped"); - assert.strictEqual(actionManager.$('.o_group_header').length, 2, + assert.containsN(actionManager, '.o_group_header', 2, "should be grouped by 'bar' (two groups) at reload"); actionManager.destroy(); @@ -2966,14 +2962,14 @@ QUnit.module('ActionManager', { }); actionManager.doAction(33); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); // try to open a record in a form view - actionManager.$('.o_list_view .o_data_row:first').click(); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); + assert.containsOnce(actionManager, '.o_list_view', "should still display the list view"); - assert.strictEqual(actionManager.$('.o_form_view').length, 0, + assert.containsNone(actionManager, '.o_form_view', "should not display the form view"); assert.verifySteps([ @@ -2988,7 +2984,7 @@ QUnit.module('ActionManager', { QUnit.test('save current search', function (assert) { assert.expect(4); - testUtils.patch(ListController, { + testUtils.mock.patch(ListController, { getContext: function () { return { shouldBeInFilterContext: true, @@ -3024,21 +3020,22 @@ QUnit.module('ActionManager', { }); actionManager.doAction(33); - assert.strictEqual(actionManager.$('.o_data_row').length, 5, + assert.containsN(actionManager, '.o_data_row', 5, "should contain 5 records"); // filter on bar - $('.o_control_panel .o_filters_menu a:contains(Bar)').click(); + testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Filters)')); + testUtils.dom.click($('.o_control_panel .o_filters_menu a:contains(Bar)')); - assert.strictEqual(actionManager.$('.o_data_row').length, 2, - "should contain 2 records"); + assert.containsN(actionManager, '.o_data_row', 2); // save filter - $('.o_control_panel .o_save_search a').click(); // toggle 'Save current search' + testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Favorites)')); + testUtils.dom.click($('.o_control_panel .o_save_search')); $('.o_control_panel .o_save_name input[type=text]').val('some name'); // name the filter - $('.o_control_panel .o_save_name button').click(); // click on 'Save' + testUtils.dom.click($('.o_control_panel .o_save_name button')); - testUtils.unpatch(ListController); + testUtils.mock.unpatch(ListController); actionManager.destroy(); }); @@ -3060,7 +3057,7 @@ QUnit.module('ActionManager', { "the search options should be available"); // go back using the breadcrumbs - $('.o_control_panel .breadcrumb a:first').click(); + testUtils.dom.click($('.o_control_panel .breadcrumb a:first')); assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1, "the search options should be available"); @@ -3096,7 +3093,8 @@ QUnit.module('ActionManager', { actionManager.doAction(33); checkRPC = true; - $('.o_control_panel .o_filters_menu a:contains(Bar)').click(); // filter on bar + testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Filters)')); + testUtils.dom.click($('.o_control_panel .o_filters_menu a:contains(Bar)')); assert.strictEqual($('.o_control_panel .o_facet_values').text().trim(), 'Bar', "the filter on Bar should appear in the search view"); @@ -3164,11 +3162,11 @@ QUnit.module('ActionManager', { // execute an action and open a record in form view actionManager.doAction(3); - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // click on 'Execute action' button (it executes an action with a CompoundContext as context) checkSessionStorage = true; - actionManager.$('.o_form_view button:contains(Execute action)').click(); + testUtils.dom.click(actionManager.$('.o_form_view button:contains(Execute action)')); actionManager.destroy(); }); @@ -3191,9 +3189,9 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_technical_modal .o_form_view').length, 1, "should have rendered a form view in a modal"); - assert.ok($('.o_technical_modal .modal-body').hasClass('o_act_window'), + assert.hasClass($('.o_technical_modal .modal-body'),'o_act_window', "dialog main element should have classname 'o_act_window'"); - assert.ok($('.o_technical_modal .o_form_view').hasClass('o_form_editable'), + assert.hasClass($('.o_technical_modal .o_form_view'),'o_form_editable', "form view should be in edit mode"); assert.verifySteps([ @@ -3305,7 +3303,7 @@ QUnit.module('ActionManager', { }); actionManager.doAction(6); - assert.strictEqual(actionManager.$('.o_form_view.o_form_editable').length, 1, + assert.containsOnce(actionManager, '.o_form_view.o_form_editable', "should have rendered a form view in edit mode"); assert.verifySteps([ @@ -3341,7 +3339,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('.o_control_panel').length, 1, "should have rendered a control panel"); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', "should have rendered a kanban view"); assert.verifySteps([ '/web/action/load', @@ -3503,7 +3501,7 @@ QUnit.module('ActionManager', { actionManager.doAction('slowAction'); actionManager.doAction(4); slowWillStartDef.resolve(); - assert.strictEqual(actionManager.$('.o_kanban_view').length, 1, + assert.containsOnce(actionManager, '.o_kanban_view', 'should have loaded a kanban view'); actionManager.destroy(); @@ -3602,20 +3600,20 @@ QUnit.module('ActionManager', { // open first record in form view. this will crash and will not // display a form view - actionManager.$('.o_list_view .o_data_row:first').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); readOnFirstRecordDef.reject("not working as intended"); - assert.strictEqual(actionManager.$('.o_list_view').length, 1, + assert.containsOnce(actionManager, '.o_list_view', "there should still be a list view in dom"); // open another record, the read will not crash - actionManager.$('.o_list_view .o_data_row:eq(2)').click(); + testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:eq(2)')); - assert.strictEqual(actionManager.$('.o_list_view').length, 0, + assert.containsNone(actionManager, '.o_list_view', "there should not be a list view in dom"); - assert.strictEqual(actionManager.$('.o_form_view').length, 1, + assert.containsOnce(actionManager, '.o_form_view', "there should be a form view in dom"); actionManager.destroy(); diff --git a/addons/web/static/tests/chrome/pager_tests.js b/addons/web/static/tests/chrome/pager_tests.js index 48c4ce6ed89..e089929abbc 100644 --- a/addons/web/static/tests/chrome/pager_tests.js +++ b/addons/web/static/tests/chrome/pager_tests.js @@ -3,6 +3,7 @@ odoo.define('web.pager_tests', function (require) { var Pager = require('web.Pager'); var concurrency = require('web.concurrency'); +var testUtils = require('web.test_utils'); QUnit.module('chrome', {}, function () { @@ -18,7 +19,7 @@ QUnit.module('chrome', {}, function () { "current_min should be set to 1"); // click on next - pager.$('.o_pager_next').click(); + testUtils.dom.click(pager.$('.o_pager_next')); assert.strictEqual(pager.state.current_min, 5, "current_min should now be 5"); @@ -32,8 +33,8 @@ QUnit.module('chrome', {}, function () { pager.appendTo($('#qunit-fixture')); // enter edition - pager.$('.o_pager_value').click(); - assert.strictEqual(pager.$('input').length, 1, + testUtils.dom.click(pager.$('.o_pager_value')); + assert.containsOnce(pager, 'input', "the pager should contain an input"); assert.strictEqual(pager.$('input').val(), '1-4', "the input should have correct value"); @@ -62,16 +63,16 @@ QUnit.module('chrome', {}, function () { pager.disable(); // try to go to the next or previous pages - pager.$('.o_pager_next').click(); + testUtils.dom.click(pager.$('.o_pager_next')); assert.strictEqual(pager.state.current_min, 1, "current_min should still be 1"); - pager.$('.o_pager_previous').click(); + testUtils.dom.click(pager.$('.o_pager_previous')); assert.strictEqual(pager.state.current_min, 1, "current_min should still be 1"); // try to change the limit - pager.$('.o_pager_value').click(); - assert.strictEqual(pager.$('input').length, 0, + testUtils.dom.click(pager.$('.o_pager_value')); + assert.containsNone(pager, 'input', "the pager should not contain an input"); // a common use is to disable the pager before reloading the data, and @@ -86,7 +87,7 @@ QUnit.module('chrome', {}, function () { }); }); pager.enable(); - pager.$('.o_pager_next').click(); + testUtils.dom.click(pager.$('.o_pager_next')); }); }); diff --git a/addons/web/static/tests/chrome/search_view_mobile_tests.js b/addons/web/static/tests/chrome/search_view_mobile_tests.js index 1508f45952c..05e2cd09a73 100644 --- a/addons/web/static/tests/chrome/search_view_mobile_tests.js +++ b/addons/web/static/tests/chrome/search_view_mobile_tests.js @@ -62,18 +62,18 @@ QUnit.module('Mobile Search view Screen', { assert.ok(!$('.o_mobile_search').is(':visible'), 'mobile search view is not visible'); // open the search view - $('button.o_enable_searchview').click(); + testUtils.dom.click($('button.o_enable_searchview')); assert.ok($('.o_mobile_search').is(':visible'), 'mobile search view is visible'); // open filter sub menu - $('button.o_dropdown_toggler_btn').first().click(); + testUtils.dom.click($('button.o_dropdown_toggler_btn').first()); filterActiveFlag = true; // click on Active filter - $('.o_filters_menu a:contains(Active)').click(); + testUtils.dom.click($('.o_filters_menu a:contains(Active)')); actionManager.destroy(); }); diff --git a/addons/web/static/tests/chrome/user_menu_tests.js b/addons/web/static/tests/chrome/user_menu_tests.js index f05a8a48120..600ac125dd4 100644 --- a/addons/web/static/tests/chrome/user_menu_tests.js +++ b/addons/web/static/tests/chrome/user_menu_tests.js @@ -13,15 +13,15 @@ QUnit.module('chrome', {}, function () { var parent = new Widget(); - testUtils.addMockEnvironment(parent, {}); + testUtils.mock.addMockEnvironment(parent, {}); var userMenu = new UserMenu(parent); userMenu.appendTo($('body')); assert.strictEqual($('.o_user_menu').length, 1, "should have a user menu in the DOM"); - assert.ok(userMenu.$el.hasClass('o_user_menu'), + assert.hasClass(userMenu.$el,'o_user_menu', "user menu in DOM should be from user menu widget instantiation"); - assert.strictEqual(userMenu.$('.dropdown-item[data-menu="shortcuts"]').length, 1, + assert.containsOnce(userMenu, '.dropdown-item[data-menu="shortcuts"]', "should have a 'Shortcuts' item"); userMenu.destroy(); diff --git a/addons/web/static/tests/core/dom_tests.js b/addons/web/static/tests/core/dom_tests.js index 08966cd484a..ab10bbb78f8 100644 --- a/addons/web/static/tests/core/dom_tests.js +++ b/addons/web/static/tests/core/dom_tests.js @@ -2,6 +2,7 @@ odoo.define('web.dom_tests', function (require) { "use strict"; var dom = require('web.dom'); +var testUtils = require('web.test_utils'); /** * Create an autoresize text area with 'border-box' as box sizing rule. @@ -43,7 +44,7 @@ QUnit.module('dom', {}, function () { $fixedTextarea[0].scrollHeight + 'px', "autoresized textarea should have height of fixed textarea + padding (0 line)"); - $textarea.val('a\nb\nc\nd').trigger('input'); + testUtils.fields.editInput($textarea, 'a\nb\nc\nd'); assert.strictEqual($textarea.css('height'), $fixedTextarea[0].scrollHeight + 'px', "autoresized textarea should have height of fixed textarea + padding (4 lines)"); @@ -63,7 +64,7 @@ QUnit.module('dom', {}, function () { expectedTextAreaHeight + 'px', "autoresized textarea should have height of fixed textarea + padding (0 line)"); - $textarea.val('a\nb\nc\nd').trigger('input'); + testUtils.fields.editInput($textarea, 'a\nb\nc\nd'); // twice the padding of 10px expectedTextAreaHeight = $fixedTextarea[0].scrollHeight + 2*10; assert.strictEqual($textarea.css('height'), @@ -88,7 +89,7 @@ QUnit.module('dom', {}, function () { expectedTextAreaHeight + 'px', "autoresized textarea should have height of fixed textarea + border (0 line)"); - $textarea.val('a\nb\nc\nd').trigger('input'); + testUtils.fields.editInput($textarea, 'a\nb\nc\nd'); // top (2px) + bottom (3px) borders expectedTextAreaHeight = $fixedTextarea[0].scrollHeight + (2 + 3); assert.strictEqual($textarea.css('height'), @@ -114,7 +115,7 @@ QUnit.module('dom', {}, function () { expectedTextAreaHeight + 'px', "autoresized textarea should have height of fixed textarea + border (0 line)"); - $textarea.val('a\nb\nc\nd').trigger('input'); + testUtils.fields.editInput($textarea, 'a\nb\nc\nd'); // twice padding (10px) + top (2px) + bottom (3px) borders expectedTextAreaHeight = $fixedTextarea[0].scrollHeight + (2*10 + 2 + 3); assert.strictEqual($textarea.css('height'), diff --git a/addons/web/static/tests/core/mixins_tests.js b/addons/web/static/tests/core/mixins_tests.js index c49c33ec648..27c87870876 100644 --- a/addons/web/static/tests/core/mixins_tests.js +++ b/addons/web/static/tests/core/mixins_tests.js @@ -13,7 +13,7 @@ QUnit.module('core', {}, function () { var widget = new Widget(); - testUtils.intercept(widget, 'do_action', function (event) { + testUtils.mock.intercept(widget, 'do_action', function (event) { assert.strictEqual(event.data.action, 'test.some_action_id', "should have sent proper action name"); assert.deepEqual(event.data.options, {clear_breadcrumbs: true}, diff --git a/addons/web/static/tests/core/widget_tests.js b/addons/web/static/tests/core/widget_tests.js index f61d4a18f9b..834033a1769 100644 --- a/addons/web/static/tests/core/widget_tests.js +++ b/addons/web/static/tests/core/widget_tests.js @@ -122,7 +122,7 @@ QUnit.module('core', {}, function () { widget.renderElement(); assert.strictEqual(widget.el.attributes.length, 1, "should have one attribute"); - assert.strictEqual(widget.$el.attr('id'), 'foo', "should have generated the id attribute"); + assert.hasAttrValue(widget.$el, 'id', 'foo', "should have generated the id attribute"); assert.strictEqual(widget.el.id, 'foo', "should also be available via property"); }); @@ -135,7 +135,7 @@ QUnit.module('core', {}, function () { widget.renderElement(); assert.strictEqual(widget.el.className, 'oe_some_class', "should have the right property"); - assert.strictEqual(widget.$el.attr('class'), 'oe_some_class', "should have the right attribute"); + assert.hasAttrValue(widget.$el, 'class', 'oe_some_class', "should have the right attribute"); }); QUnit.test('no template, bunch of attributes', function (assert) { @@ -156,16 +156,16 @@ QUnit.module('core', {}, function () { assert.strictEqual(widget.el.attributes.length, 5, "should have all the specified attributes"); assert.strictEqual(widget.el.id, 'some_id'); - assert.strictEqual(widget.$el.attr('id'), 'some_id'); + assert.hasAttrValue(widget.$el, 'id', 'some_id'); assert.strictEqual(widget.el.className, 'some_class'); - assert.strictEqual(widget.$el.attr('class'), 'some_class'); + assert.hasAttrValue(widget.$el, 'class', 'some_class'); - assert.strictEqual(widget.$el.attr('data-foo'), 'data attribute'); + assert.hasAttrValue(widget.$el, 'data-foo', 'data attribute'); assert.strictEqual(widget.$el.data('foo'), 'data attribute'); - assert.strictEqual(widget.$el.attr('clark'), 'gable'); - assert.strictEqual(widget.$el.attr('spoiler'), 'snape kills dumbledore'); + assert.hasAttrValue(widget.$el, 'clark', 'gable'); + assert.hasAttrValue(widget.$el, 'spoiler', 'snape kills dumbledore'); }); QUnit.test('template', function (assert) { @@ -383,7 +383,7 @@ QUnit.module('core', {}, function () { var def; var parent = new Widget(); - testUtils.addMockEnvironment(parent, { + testUtils.mock.addMockEnvironment(parent, { session: { rpc: function () { def = $.Deferred(); diff --git a/addons/web/static/tests/fields/basic_fields_mobile_tests.js b/addons/web/static/tests/fields/basic_fields_mobile_tests.js index acd9cebc989..05f1b93226e 100644 --- a/addons/web/static/tests/fields/basic_fields_mobile_tests.js +++ b/addons/web/static/tests/fields/basic_fields_mobile_tests.js @@ -75,25 +75,25 @@ QUnit.module('basic_fields', { "should have a anchor with correct classes"); assert.strictEqual($phoneLink.text(), 'yop', "value should be displayed properly"); - assert.strictEqual($phoneLink.attr('href'), 'tel:yop', + assert.hasAttrValue($phoneLink, 'href', 'tel:yop', "should have proper tel prefix"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'input[type="text"].o_field_widget', "should have an int for the phone field"); assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', "input should contain field value in edit mode"); // change value in edit mode - form.$('input[type="text"].o_field_widget').val('new').trigger('input'); + testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); $phoneLink = form.$('a.o_form_uri.o_field_widget'); assert.strictEqual($phoneLink.text(), 'new', "new value should be displayed properly"); - assert.strictEqual($phoneLink.attr('href'), 'tel:new', + assert.hasAttrValue($phoneLink, 'href', 'tel:new', "should still have proper tel prefix"); form.destroy(); @@ -109,7 +109,7 @@ QUnit.module('basic_fields', { arch: '', }); - assert.strictEqual(list.$('.o_data_row').length, 3, + assert.containsN(list, '.o_data_row', 3, "should have 3 record"); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop', "value should be displayed properly"); @@ -117,27 +117,27 @@ QUnit.module('basic_fields', { var $phoneLink = list.$('a.o_form_uri.o_field_widget'); assert.strictEqual($phoneLink.length, 3, "should have anchors with correct classes"); - assert.strictEqual($phoneLink.first().attr('href'), 'tel:yop', + assert.hasAttrValue($phoneLink.first(), 'href', 'tel:yop', "should have proper tel prefix"); // Edit a line and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); + testUtils.dom.click($cell); + assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode'); assert.strictEqual($cell.find('input').val(), 'yop', 'should have the corect value in internal input'); - $cell.find('input').val('new').trigger('input'); + testUtils.fields.editInput($cell.find('input'), 'new'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); + assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore'); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new', "value should be properly updated"); $phoneLink = list.$('a.o_form_uri.o_field_widget'); assert.strictEqual($phoneLink.length, 3, "should still have anchors with correct classes"); - assert.strictEqual($phoneLink.first().attr('href'), 'tel:new', + assert.hasAttrValue($phoneLink.first(), 'href', 'tel:new', "should still have proper tel prefix"); list.destroy(); @@ -164,10 +164,10 @@ QUnit.module('basic_fields', { }); var val = ''; - form.$('input').val(val).trigger('input'); + testUtils.fields.editInput(form.$('input'), val); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), val, "value should have been correctly escaped"); diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index f1640b06c82..b4998b01712 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -18,6 +18,9 @@ var DebouncedField = basicFields.DebouncedField; var JournalDashboardGraph = basicFields.JournalDashboardGraph; var _t = core._t; +var DOM = testUtils.DOM; +var mock = testUtils.mock; + QUnit.module('fields', {}, function () { QUnit.module('basic_fields', { @@ -163,11 +166,11 @@ QUnit.module('basic_fields', { }); // change the value - form.$('input').val('new value').trigger('input'); + testUtils.fields.editInput(form.$('input'), 'new value'); assert.verifySteps([], "_setValue shouldn't have been called yet"); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.verifySteps(['_setValue'], "_setValue should have been called once"); // destroy the form view @@ -199,47 +202,47 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, + assert.containsOnce(form, '.o_field_boolean input:checked', "checkbox should be checked"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_field_boolean input:checked', "checkbox should still be checked"); // uncheck the checkbox - form.$('.o_field_boolean input:checked').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, + testUtils.dom.click(form.$('.o_field_boolean input:checked')); + assert.containsNone(form, '.o_field_boolean input:checked', "checkbox should no longer be checked"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, + testUtils.form.clickSave(form); + assert.containsNone(form, '.o_field_boolean input:checked', "checkbox should still no longer be checked"); // switch to edit mode and test the opposite change - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, + testUtils.form.clickEdit(form); + assert.containsNone(form, '.o_field_boolean input:checked', "checkbox should still be unchecked"); // check the checkbox - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, + testUtils.dom.click(form.$('.o_field_boolean input')); + assert.containsOnce(form, '.o_field_boolean input:checked', "checkbox should now be checked"); // uncheck it back - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, + testUtils.dom.click(form.$('.o_field_boolean input')); + assert.containsNone(form, '.o_field_boolean input:checked', "checkbox should now be unchecked"); // check the checkbox by clicking on label - form.$('label:first').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, + testUtils.dom.click(form.$('label:first')); + assert.containsOnce(form, '.o_field_boolean input:checked', "checkbox should now be checked"); // uncheck it back - form.$('label:first').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, + testUtils.dom.click(form.$('label:first')); + assert.containsNone(form, '.o_field_boolean input:checked', "checkbox should now be unchecked"); // check the checkbox by hitting the "enter" key after focusing it @@ -247,18 +250,18 @@ QUnit.module('basic_fields', { .trigger("focusin") .trigger({type: "keydown", which: $.ui.keyCode.ENTER}) .trigger({type: "keyup", which: $.ui.keyCode.ENTER}); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, + assert.containsOnce(form, '.o_field_boolean input:checked', "checkbox should now be checked"); // blindly press enter again, it should uncheck the checkbox $(document.activeElement).trigger({type: "keydown", which: $.ui.keyCode.ENTER}); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 0, + assert.containsNone(form, '.o_field_boolean input:checked', "checkbox should not be checked"); // blindly press enter again, it should check the checkbox back $(document.activeElement).trigger({type: "keydown", which: $.ui.keyCode.ENTER}); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_boolean input:checked').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.o_field_boolean input:checked', "checkbox should still be checked"); form.destroy(); }); @@ -282,13 +285,13 @@ QUnit.module('basic_fields', { var $cell = list.$('tr.o_data_row:has(.custom-checkbox input:checked) td:not(.o_list_record_selector)').first(); assert.ok($cell.find('.custom-checkbox input:checked').prop('disabled'), "input should be disabled in readonly mode"); - $cell.click(); + testUtils.dom.click($cell); assert.ok(!$cell.find('.custom-checkbox input:checked').prop('disabled'), "input should not have the disabled property in edit mode"); - $cell.find('.custom-checkbox input:checked').click(); + testUtils.dom.click($cell.find('.custom-checkbox input:checked')); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tr.o_data_row:has(.custom-checkbox input:not(:checked)) td:not(.o_list_record_selector)').first(); assert.ok($cell.find('.custom-checkbox input:not(:checked)').prop('disabled'), "input should be disabled again"); @@ -298,12 +301,12 @@ QUnit.module('basic_fields', { "should now have only 3 checked input"); // Re-Edit the line and fake-check the checkbox - $cell.click(); - $cell.find('.custom-checkbox input').click(); // Change the checkbox - $cell.find('.custom-checkbox input').click(); // Undo the change + testUtils.dom.click($cell); + testUtils.dom.click($cell.find('.custom-checkbox input')); + testUtils.dom.click($cell.find('.custom-checkbox input')); // Save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5, "should still have 5 checkboxes"); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 3, @@ -312,10 +315,8 @@ QUnit.module('basic_fields', { // Re-Edit the line to check the checkbox back but this time click on // the checkbox directly in readonly mode ! $cell = list.$('tr.o_data_row:has(.custom-checkbox input:not(:checked)) td:not(.o_list_record_selector)').first(); - $cell.find('.custom-checkbox .custom-control-label').click(); + testUtils.dom.click($cell.find('.custom-checkbox .custom-control-label')); - // save - list.$buttons.find('.o_form_button_save').click(); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5, "should still have 5 checkboxes"); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 4, @@ -328,7 +329,6 @@ QUnit.module('basic_fields', { QUnit.test('use custom terminology in form view', function (assert) { assert.expect(2); - var terminology = { string_true: "Production Environment", hover_true: "Switch to test environment", @@ -370,7 +370,7 @@ QUnit.module('basic_fields', { res_id: 2, }); - assert.strictEqual(form.$(".custom-checkbox.o_boolean_toggle").length, 1, "Boolean toggle widget applied to boolean field"); + assert.containsOnce(form, ".custom-checkbox.o_boolean_toggle", "Boolean toggle widget applied to boolean field"); form.destroy(); }); @@ -389,23 +389,23 @@ QUnit.module('basic_fields', { '', }); - assert.strictEqual(list.$('button i.fa.fa-circle.o_toggle_button_success').length, 4, + assert.containsN(list, 'button i.fa.fa-circle.o_toggle_button_success', 4, "should have 4 green buttons"); - assert.strictEqual(list.$('button i.fa.fa-circle.text-muted').length, 1, + assert.containsOnce(list, 'button i.fa.fa-circle.text-muted', "should have 1 muted button"); - assert.strictEqual(list.$('button').first().attr('title'), "Reported in last payslips", + assert.hasAttrValue(list.$('button').first(), 'title', "Reported in last payslips", "active buttons should have proper tooltip"); - assert.strictEqual(list.$('button').last().attr('title'), "To Report in Payslip", + assert.hasAttrValue(list.$('button').last(), 'title', "To Report in Payslip", "inactive buttons should have proper tooltip"); // clicking on first button to check the state is properly changed - list.$('button').first().click(); - assert.strictEqual(list.$('button i.fa.fa-circle.o_toggle_button_success').length, 3, + testUtils.dom.click(list.$('button').first()); + assert.containsN(list, 'button i.fa.fa-circle.o_toggle_button_success', 3, "should have 3 green buttons"); - list.$('button').first().click(); - assert.strictEqual(list.$('button i.fa.fa-circle.o_toggle_button_success').length, 4, + testUtils.dom.click(list.$('button').first()); + assert.containsN(list, 'button i.fa.fa-circle.o_toggle_button_success', 4, "should have 4 green buttons"); list.destroy(); }); @@ -437,14 +437,14 @@ QUnit.module('basic_fields', { 1, "should be green"); // click on the button to toggle the value - form.$('.o_field_widget[name=bar]').click(); + testUtils.dom.click(form.$('.o_field_widget[name=bar]')); assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length, 1, "should be gray"); assert.verifySteps([]); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length, 1, "should still be gray"); @@ -477,7 +477,7 @@ QUnit.module('basic_fields', { 1, "should be green"); // click on the button to toggle the value - form.$('.o_field_widget[name=bar]').click(); + testUtils.dom.click(form.$('.o_field_widget[name=bar]')); assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length, 1, "should be gray"); @@ -503,7 +503,7 @@ QUnit.module('basic_fields', { res_id: 4, }); - assert.notOk(form.$('.o_field_widget').hasClass('o_field_empty'), + assert.doesNotHaveClass(form.$('.o_field_widget'), 'o_field_empty', 'Non-set float field should be considered as 0.'); assert.strictEqual(form.$('.o_field_widget').text(), "0.000", 'Non-set float field should be considered as 0.'); @@ -547,21 +547,21 @@ QUnit.module('basic_fields', { res_id: 2, }); - assert.ok(!form.$('.o_field_widget').hasClass('o_field_empty'), + assert.doesNotHaveClass(form.$('.o_field_widget'), 'o_field_empty', 'Float field should be considered set for value 0.'); assert.strictEqual(form.$('.o_field_widget').first().text(), '0.000', 'The value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), '0.000', 'The value should be rendered with correct precision.'); - form.$('input').val('108.2458938598598').trigger('input'); + testUtils.fields.editInput(form.$('input'), '108.2458938598598'); assert.strictEqual(form.$('input').val(), '108.2458938598598', 'The value should not be formated yet.'); - form.$('input').val('18.8958938598598').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('input'), '18.8958938598598'); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').first().text(), '18.896', 'The new value should be rounded properly.'); @@ -586,17 +586,17 @@ QUnit.module('basic_fields', { // switch to edit mode var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first(); - $cell.click(); + testUtils.dom.click($cell); - assert.strictEqual(list.$('input[name="qux"]').length, 1, + assert.containsOnce(list, 'input[name="qux"]', 'The view should have 1 input for editable float.'); - list.$('input[name="qux"]').val('108.2458938598598').trigger('input'); + testUtils.fields.editInput(list.$('input[name="qux"]'), '108.2458938598598'); assert.strictEqual(list.$('input[name="qux"]').val(), '108.2458938598598', 'The value should not be formated yet.'); - list.$('input[name="qux"]').val('18.8958938598598').trigger('input'); - list.$buttons.find('.o_list_button_save').click(); + testUtils.fields.editInput(list.$('input[name="qux"]'), '18.8958938598598'); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('.o_field_widget').first().text(), '18.896', 'The new value should be rounded properly.'); @@ -625,8 +625,8 @@ QUnit.module('basic_fields', { } }); - form.$buttons.find('.o_form_button_edit').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.form.clickSave(form); assert.verifySteps(['read']); // should not have save as nothing changed @@ -669,7 +669,7 @@ QUnit.module('basic_fields', { id: 1, qux: -8.89859, currency_id: 1, - }] + }]; var form = createView({ View: FormView, model: 'partner', @@ -690,17 +690,17 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0-8.9', 'The value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), '-8.9', 'The input should be rendered without the currency symbol.'); assert.strictEqual(form.$('input').parent().children().first().text(), '$', 'The input should be preceded by a span containing the currency symbol.'); - form.$('input').val('109.2458938598598').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_monetary input'), '109.2458938598598'); assert.strictEqual(form.$('input').val(), '109.2458938598598', 'The value should not be formated yet.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // Non-breaking space between the currency and the amount assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0109.2', 'The new value should be rounded properly.'); @@ -725,17 +725,17 @@ QUnit.module('basic_fields', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'), 'Float field with option type must have a type attribute.'); - assert.strictEqual(form.$('.o_field_widget').attr('type'), 'number', + assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'number', 'Float field with option type must have a type attribute equals to "number".'); - form.$('input').val('123456.7890').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.fields.editInput(form.$('input'), '123456.7890'); + testUtils.form.clickSave(form); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget').val(), '123456.789', 'Float value must be not formatted if input type is number.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), '123,456.8', 'Float value must be formatted in readonly view even if the input type is number.'); @@ -759,13 +759,13 @@ QUnit.module('basic_fields', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_widget').attr('type'), 'text', + testUtils.form.clickEdit(form); + assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'text', 'Float field with option type must have a text type (default type).'); - form.$('input').val('123456.7890').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.fields.editInput(form.$('input'), '123456.7890'); + testUtils.form.clickSave(form); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget').val(), '123,456.8', 'Float value must be formatted if input type isn\'t number.'); @@ -797,25 +797,25 @@ QUnit.module('basic_fields', { "should have a anchor with correct classes"); assert.strictEqual($mailtoLink.text(), 'yop', "the value should be displayed properly"); - assert.strictEqual($mailtoLink.attr('href'), 'mailto:yop', + assert.hasAttrValue($mailtoLink, 'href', 'mailto:yop', "should have proper mailto prefix"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'input[type="text"].o_field_widget', "should have an input for the email field"); assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', "input should contain field value in edit mode"); // change value in edit mode - form.$('input[type="text"].o_field_widget').val('new').trigger('input'); + testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); $mailtoLink = form.$('a.o_form_uri.o_field_widget.o_text_overflow'); assert.strictEqual($mailtoLink.text(), 'new', "new value should be displayed properly"); - assert.strictEqual($mailtoLink.attr('href'), 'mailto:new', + assert.hasAttrValue($mailtoLink, 'href', 'mailto:new', "should still have proper mailto prefix"); form.destroy(); @@ -839,27 +839,27 @@ QUnit.module('basic_fields', { var $mailtoLink = list.$('a.o_form_uri.o_field_widget.o_text_overflow'); assert.strictEqual($mailtoLink.length, 5, "should have anchors with correct classes"); - assert.strictEqual($mailtoLink.first().attr('href'), 'mailto:yop', + assert.hasAttrValue($mailtoLink.first(), 'href', 'mailto:yop', "should have proper mailto prefix"); // Edit a line and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); + testUtils.dom.click($cell); + assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode'); assert.strictEqual($cell.find('input').val(), 'yop', 'should have the corect value in internal input'); - $cell.find('input').val('new').trigger('input'); + testUtils.fields.editInput($cell.find('input'), 'new'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); + assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore'); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new', "value should be properly updated"); $mailtoLink = list.$('a.o_form_uri.o_field_widget.o_text_overflow'); assert.strictEqual($mailtoLink.length, 5, "should still have anchors with correct classes"); - assert.strictEqual($mailtoLink.first().attr('href'), 'mailto:new', + assert.hasAttrValue($mailtoLink.first(), 'href', 'mailto:new', "should still have proper mailto prefix"); list.destroy(); @@ -908,17 +908,17 @@ QUnit.module('basic_fields', { "the value should be displayed properly"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'input[type="text"].o_field_widget', "should have an input for the char field"); assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', "input should contain field value in edit mode"); // change value in edit mode - form.$('input[type="text"].o_field_widget').val('limbo').trigger('input'); + testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'limbo'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), 'limbo', 'the new value should be displayed'); form.destroy(); @@ -949,10 +949,10 @@ QUnit.module('basic_fields', { } }); - form.$('input[type="text"].o_field_widget').val('').trigger('input'); + testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), ''); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -975,7 +975,7 @@ QUnit.module('basic_fields', { }, }); - assert.strictEqual(form.$('input.o_field_widget').attr('maxlength'), '5', + assert.hasAttrValue(form.$('input.o_field_widget'), 'maxlength', '5', "maxlength attribute should have been set correctly on the input"); form.destroy(); @@ -998,16 +998,16 @@ QUnit.module('basic_fields', { // Edit a line and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); + testUtils.dom.click($cell); + assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode'); assert.strictEqual($cell.find('input').val(), 'yop', 'should have the corect value in internal input'); - $cell.find('input').val('brolo').trigger('input'); + testUtils.fields.editInput($cell.find('input'), 'brolo'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); + assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore'); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'brolo', "value should be properly updated"); list.destroy(); @@ -1041,10 +1041,10 @@ QUnit.module('basic_fields', { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $button = form.$('input[type="text"].o_field_char + .o_field_translate'); assert.strictEqual($button.length, 1, "should have a translate button"); - $button.click(); + testUtils.dom.click($button); form.destroy(); form = createView({ @@ -1086,8 +1086,8 @@ QUnit.module('basic_fields', { }, }); - form.$('input').val('').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('input'), ''); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), '', 'the value should have been properly escaped'); @@ -1117,13 +1117,13 @@ QUnit.module('basic_fields', { }, }); - form.$('input[name="foo"]').val(' abc ').trigger('input'); - form.$('input[name="foo2"]').val(' def ').trigger('input'); + testUtils.fields.editInput(form.$('input[name="foo"]'), ' abc '); + testUtils.fields.editInput(form.$('input[name="foo2"]'), ' def '); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input[name="foo"]').val(), 'abc', 'Foo value should have been trimmed'); assert.strictEqual(form.$('input[name="foo2"]').val(), ' def ', 'Foo2 value should not have been trimmed'); @@ -1169,17 +1169,17 @@ QUnit.module('basic_fields', { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('input[name="foo"]').val(), 'My little Foo Value', 'should contain the default value'); def = $.Deferred(); - form.$('.o_field_many2one input').click(); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - $dropdown.find('li:first()').click(); + + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickHighlightedItem('product_id'); // set foo before onchange - form.$('input[name="foo"]').val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input[name="foo"]'), "tralala"); assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala', 'input should contain tralala'); @@ -1230,12 +1230,11 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('input[name="foo"]').val(), 'yop', 'should contain the correct value'); - form.$('.o_field_many2one input').click(); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - $dropdown.find('li:first()').click(); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickHighlightedItem('product_id'); // set foo before onchange - form.$('input[name="foo"]').val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input[name="foo"]'), "tralala"); assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala', 'input should contain tralala'); @@ -1265,9 +1264,9 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_char').text(), "***", "password field value should be hidden with '*' in read mode"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('input.o_field_char').attr('type'), 'password', + assert.hasAttrValue(form.$('input.o_field_char'), 'type', 'password', "password field input should be with type 'password' in edit mode"); assert.strictEqual(form.$('input.o_field_char').val(), 'yop', "password field input value should be the (non-hidden) password value"); @@ -1293,9 +1292,9 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_char').text(), "", "password field value should be empty in read mode"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('input.o_field_char').attr('type'), 'password', + assert.hasAttrValue(form.$('input.o_field_char'), 'type', 'password', "password field input should be with type 'password' in edit mode"); assert.strictEqual(form.$('input.o_field_char').val(), '', "password field input value should be the (non-hidden, empty) password value"); @@ -1322,30 +1321,30 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 1, + assert.containsOnce(form, 'a.o_form_uri.o_field_widget.o_text_overflow', "should have a anchor with correct classes"); - assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').attr('href'), 'yop', + assert.hasAttrValue(form.$('a.o_form_uri.o_field_widget.o_text_overflow'), 'href', 'yop', "should have proper href link"); - assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').attr('target'), '_blank', + assert.hasAttrValue(form.$('a.o_form_uri.o_field_widget.o_text_overflow'), 'target', '_blank', "should have target attribute set to _blank"); assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').text(), 'yop', "the value should be displayed properly"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'input[type="text"].o_field_widget', "should have an input for the char field"); assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', "input should contain field value in edit mode"); // change value in edit mode - form.$('input[type="text"].o_field_widget').val('limbo').trigger('input'); + testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'limbo'); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, 'a.o_form_uri.o_field_widget.o_text_overflow', "should still have a anchor with correct classes"); - assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').attr('href'), 'limbo', + assert.hasAttrValue(form.$('a.o_form_uri.o_field_widget.o_text_overflow'), 'href', 'limbo', "should have proper new href link"); assert.strictEqual(form.$('a.o_form_uri.o_field_widget.o_text_overflow').text(), 'limbo', 'the new value should be displayed'); @@ -1383,28 +1382,28 @@ QUnit.module('basic_fields', { assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').length, 5, "should have 5 cells"); - assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 5, + assert.containsN(list, 'a.o_form_uri.o_field_widget.o_text_overflow', 5, "should have 5 anchors with correct classes"); - assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first().attr('href'), 'yop', + assert.hasAttrValue(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first(), 'href', 'yop', "should have proper href link"); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop', "value should be displayed properly as text"); // Edit a line and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); + testUtils.dom.click($cell); + assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode'); assert.strictEqual($cell.find('input').val(), 'yop', 'should have the corect value in internal input'); - $cell.find('input').val('brolo').trigger('input'); + testUtils.fields.editInput($cell.find('input'), 'brolo'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); - assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').length, 5, + assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore'); + assert.containsN(list, 'a.o_form_uri.o_field_widget.o_text_overflow', 5, "should still have 5 anchors with correct classes"); - assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first().attr('href'), 'brolo', + assert.hasAttrValue(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first(), 'href', 'brolo', "should have proper new href link"); assert.strictEqual(list.$('a.o_form_uri.o_field_widget.o_text_overflow').first().text(), 'brolo', "value should be properly updated"); @@ -1446,8 +1445,8 @@ QUnit.module('basic_fields', { '' + '', }).then(function (form) { - assert.strictEqual(form.$('.o_clipboard_button.o_btn_text_copy').length, 1,"Should have copy button on text type field"); - assert.strictEqual(form.$('.o_clipboard_button.o_btn_char_copy').length, 1,"Should have copy button on char type field"); + assert.containsOnce(form, '.o_clipboard_button.o_btn_text_copy',"Should have copy button on text type field"); + assert.containsOnce(form, '.o_clipboard_button.o_btn_char_copy',"Should have copy button on char type field"); form.destroy(); done(); }); @@ -1473,19 +1472,19 @@ QUnit.module('basic_fields', { assert.ok(form.$('.o_field_text').length, "should have a text area"); assert.strictEqual(form.$('.o_field_text').text(), 'yop', 'should be "yop" in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $textarea = form.$('textarea.o_field_text'); assert.ok($textarea.length, "should have a text area"); assert.strictEqual($textarea.val(), 'yop', 'should still be "yop" in edit'); - $textarea.val('hello').trigger('input'); + testUtils.fields.editInput($textarea, 'hello'); assert.strictEqual($textarea.val(), 'hello', 'should be "hello" after first edition'); - $textarea.val('hello world').trigger('input'); + testUtils.fields.editInput($textarea, 'hello world'); assert.strictEqual($textarea.val(), 'hello world', 'should be "hello world" after second edition'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_text').text(), 'hello world', 'should be "hello world" after save'); @@ -1512,7 +1511,7 @@ QUnit.module('basic_fields', { assert.strictEqual($field.outerHeight(), $field[0].scrollHeight, "text field should not have a scroll bar"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $textarea = form.$('textarea:first'); @@ -1535,7 +1534,7 @@ QUnit.module('basic_fields', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $textarea = form.$('textarea:first'); @@ -1564,7 +1563,7 @@ QUnit.module('basic_fields', { // the focus on the textarea by clicking on another column. // The main goal is to test the resize is actually triggered in this // particular case. - list.$('.o_data_cell:first').click(); + testUtils.dom.click(list.$('.o_data_cell:first')); var $textarea = list.$('textarea:first'); // make sure the correct data is there @@ -1602,9 +1601,9 @@ QUnit.module('basic_fields', { // edit the form // trigger a textarea reset (through onchange) by clicking the box // then check there is no scroll bar - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('div[name="bar"] input').click(); + testUtils.dom.click(form.$('div[name="bar"] input')); var $textarea = form.$('textarea:first'); assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight, @@ -1641,10 +1640,10 @@ QUnit.module('basic_fields', { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $button = form.$('textarea + .o_field_translate'); assert.strictEqual($button.length, 1, "should have a translate button"); - $button.click(); + testUtils.dom.click($button); form.destroy(); form = createView({ @@ -1681,7 +1680,7 @@ QUnit.module('basic_fields', { '', }); - list.$('tbody tr:first .o_list_text').click(); + testUtils.dom.click(list.$('tbody tr:first .o_list_text')); var $textarea = list.$('textarea.o_field_text'); assert.strictEqual($textarea.length, 1, "should have a text area"); assert.strictEqual($textarea.val(), 'yop', 'should still be "yop" in edit'); @@ -1755,40 +1754,40 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 1, + assert.containsOnce(form, 'a.o_field_widget[name="document"] > .fa-download', "the binary field should be rendered as a downloadable link in readonly"); assert.strictEqual(form.$('a.o_field_widget[name="document"]').text().trim(), 'coucou.txt', "the binary field should display the name of the file in the link"); assert.strictEqual(form.$('.o_field_char').text(), 'coucou.txt', "the filename field should have the file name as value"); - form.$('a.o_field_widget[name="document"]').click(); + testUtils.dom.click(form.$('a.o_field_widget[name="document"]')); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 0, + assert.containsNone(form, 'a.o_field_widget[name="document"] > .fa-download', "the binary field should not be rendered as a downloadable link in edit"); assert.strictEqual(form.$('div.o_field_binary_file[name="document"] > input').val(), 'coucou.txt', "the binary field should display the file name in the input edit mode"); - assert.strictEqual(form.$('.o_field_binary_file > input').attr('readonly'), 'readonly', + assert.hasAttrValue(form.$('.o_field_binary_file > input'), 'readonly', 'readonly', "the input should be readonly"); - assert.strictEqual(form.$('.o_field_binary_file > .o_clear_file_button').length, 1, + assert.containsOnce(form, '.o_field_binary_file > .o_clear_file_button', "there shoud be a button to clear the file"); assert.strictEqual(form.$('input.o_field_char').val(), 'coucou.txt', "the filename field should have the file name as value"); - form.$('.o_field_binary_file > .o_clear_file_button').click(); + testUtils.dom.click(form.$('.o_field_binary_file > .o_clear_file_button')); - assert.ok(form.$('.o_field_binary_file > input').hasClass('o_hidden'), + assert.isNotVisible(form.$('.o_field_binary_file > input'), "the input should be hidden"); assert.strictEqual(form.$('.o_field_binary_file > .o_select_file_button:not(.o_hidden)').length, 1, "there shoud be a button to upload the file"); assert.strictEqual(form.$('input.o_field_char').val(), '', "the filename field should be empty since we removed the file"); - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 0, + testUtils.form.clickSave(form); + assert.containsNone(form, 'a.o_field_widget[name="document"] > .fa-download', "the binary field should not render as a downloadable link since we removed the file"); assert.strictEqual(form.$('a.o_field_widget[name="document"]').text().trim(), '', "the binary field should not display a filename in the link since we removed the file"); @@ -1830,16 +1829,14 @@ QUnit.module('basic_fields', { res_id: 1, }); - form.$buttons.find('.o_form_button_create').click(); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); + testUtils.form.clickCreate(form); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickHighlightedItem('product_id'); - form.$('.o_field_many2one input').click(); - $dropdown.find('li:not(.o_m2o_dropdown_option):contains(xphone)').click(); - - assert.strictEqual(form.$('a.o_field_widget[name="document"] > .fa-download').length, 1, + assert.containsOnce(form, 'a.o_field_widget[name="document"] > .fa-download', 'The link to download the binary should be present'); - form.$('a.o_field_widget[name="document"]').click(); + testUtils.dom.click(form.$('a.o_field_widget[name="document"]')); assert.verifySteps([]); // We shoudln't have passed through steps @@ -1862,12 +1859,12 @@ QUnit.module('basic_fields', { '', }); - assert.ok(form.$('.o_field_widget').hasClass('o_field_pdfviewer')); + assert.hasClass(form.$('.o_field_widget'), 'o_field_pdfviewer'); assert.strictEqual(form.$('.o_select_file_button:not(.o_hidden)').length, 1, "there should be a visible 'Upload' button"); - assert.ok(form.$('.o_field_widget iframe.o_pdfview_iframe').hasClass('o_hidden'), + assert.isNotVisible(form.$('.o_field_widget iframe.o_pdfview_iframe'), "there should be an invisible iframe"); - assert.strictEqual(form.$('input[type="file"]').length, 1, + assert.containsOnce(form, 'input[type="file"]', "there should be one input"); form.destroy(); @@ -1893,12 +1890,12 @@ QUnit.module('basic_fields', { } }); - assert.ok(form.$('.o_field_widget').hasClass('o_field_pdfviewer')); + assert.hasClass(form.$('.o_field_widget'), 'o_field_pdfviewer'); assert.strictEqual(form.$('.o_select_file_button:not(.o_hidden)').length, 0, "there should not be a any visible 'Upload' button"); - assert.notOk(form.$('.o_field_widget iframe.o_pdfview_iframe').hasClass('o_hidden'), + assert.isVisible(form.$('.o_field_widget iframe.o_pdfview_iframe'), "there should be an visible iframe"); - assert.strictEqual(form.$('.o_field_widget iframe.o_pdfview_iframe').attr('data-src'), + assert.hasAttrValue(form.$('.o_field_widget iframe.o_pdfview_iframe'), 'data-src', '/web/static/lib/pdfjs/web/viewer.html?file=%2Fweb%2Fimage%3Fmodel%3Dpartner%26field%3Ddocument%26id%3D1#page=1', "the src attribute should be correctly set on the iframe"); @@ -1908,7 +1905,7 @@ QUnit.module('basic_fields', { QUnit.test("pdf_viewer: upload rendering", function (assert) { assert.expect(6); - testUtils.patch(field_registry.map.pdf_viewer, { + testUtils.mock.patch(field_registry.map.pdf_viewer, { on_file_change: function (ev) { ev.target = {files: [new Blob()]}; this._super.apply(this, arguments); @@ -1944,7 +1941,7 @@ QUnit.module('basic_fields', { form.$('input[type="file"]').trigger('change'); assert.verifySteps(['_getURI', 'open']); - testUtils.unpatch(field_registry.map.pdf_viewer); + testUtils.mock.unpatch(field_registry.map.pdf_viewer); form.destroy(); }); @@ -1983,7 +1980,7 @@ QUnit.module('basic_fields', { '', }); - list.$buttons.find('.o_list_button_add').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_add')); assert.strictEqual(list.$('textarea').first().get(0), document.activeElement, "text area should have the focus"); @@ -2016,12 +2013,12 @@ QUnit.module('basic_fields', { def.resolve(); }; - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('textarea').val("1").trigger('input'); + testUtils.fields.editInput(form.$('textarea').first(), "1"); assert.strictEqual(nbNotifyChanges, 0, "no event should have been triggered"); - form.$('textarea').val("12").trigger('input'); + testUtils.fields.editInput(form.$('textarea').first(), "12"); assert.strictEqual(nbNotifyChanges, 0, "no event should have been triggered"); @@ -2030,7 +2027,7 @@ QUnit.module('basic_fields', { "one event should have been triggered"); // add something in the textarea, then focus another input - form.$('textarea').first().val("123").trigger('input'); + testUtils.fields.editInput(form.$('textarea').first(), "123"); form.$('textarea').first().change(); assert.strictEqual(nbNotifyChanges, 2, "one event should have been triggered immediately"); @@ -2080,13 +2077,13 @@ QUnit.module('basic_fields', { }, }); - assert.ok(form.$('div[name="document"]').hasClass('o_field_image'), + assert.hasClass(form.$('div[name="document"]'),'o_field_image', "the widget should have the correct class"); - assert.strictEqual(form.$('div[name="document"] > img').length, 1, + assert.containsOnce(form, 'div[name="document"] > img', "the widget should contain an image"); - assert.ok(form.$('div[name="document"] > img').hasClass('img-fluid'), + assert.hasClass(form.$('div[name="document"] > img'),'img-fluid', "the image should have the correct class"); - assert.strictEqual(form.$('div[name="document"] > img').attr('width'), "90", + assert.hasAttrValue(form.$('div[name="document"] > img'), 'width', "90", "the image should correctly set its attributes"); assert.strictEqual(form.$('div[name="document"] > img').css('max-width'), "90px", "the image should correctly set its attributes"); @@ -2132,11 +2129,11 @@ QUnit.module('basic_fields', { }); assert.verifySteps(["The view's image should have been fetched"]); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + assert.containsOnce(form, 'tr.o_data_row', 'There should be one record in the many2many'); // Actual flow: click on an element of the m2m to get its form view - form.$('tbody td:contains(gold)').click(); + testUtils.dom.click(form.$('tbody td:contains(gold)')); assert.strictEqual($('.modal').length, 1, 'The modal should have opened'); assert.verifySteps([ @@ -2175,7 +2172,7 @@ QUnit.module('basic_fields', { }, }); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + assert.containsOnce(form, 'tr.o_data_row', 'There should be one record in the many2many'); form.destroy(); @@ -2199,11 +2196,11 @@ QUnit.module('basic_fields', { }, }); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); - assert.ok(form.$('.o_form_view').hasClass('o_form_editable'), + assert.hasClass(form.$('.o_form_view'),'o_form_editable', "form view should still be editable"); - assert.ok(form.$('.o_field_widget').hasClass('o_field_invalid'), + assert.hasClass(form.$('.o_field_widget'),'o_field_invalid', "image field should be displayed as invalid"); form.destroy(); @@ -2251,7 +2248,7 @@ QUnit.module('basic_fields', { var done = assert.async(); assert.expect(6); - testUtils.patch(JournalDashboardGraph, { + testUtils.mock.patch(JournalDashboardGraph, { on_attach_callback: function () { assert.step('on_attach_callback'); }, @@ -2289,7 +2286,7 @@ QUnit.module('basic_fields', { ]); kanban.destroy(); - testUtils.unpatch(JournalDashboardGraph); + testUtils.mock.unpatch(JournalDashboardGraph); done(); }); }); @@ -2354,7 +2351,7 @@ QUnit.module('basic_fields', { // when being destroyed before nv has been loaded assert.expect(2); - testUtils.patch(basicFields.JournalDashboardGraph, { + testUtils.mock.patch(basicFields.JournalDashboardGraph, { destroy: function () { assert.step('destroy'); var nv = window.nv; @@ -2380,7 +2377,7 @@ QUnit.module('basic_fields', { }); kanban.destroy(); - testUtils.unpatch(basicFields.JournalDashboardGraph); + testUtils.mock.unpatch(basicFields.JournalDashboardGraph); assert.verifySteps(['destroy']); @@ -2393,7 +2390,7 @@ QUnit.module('basic_fields', { // when being destroyed before nv has been completely loaded assert.expect(2); - testUtils.patch(basicFields.JournalDashboardGraph, { + testUtils.mock.patch(basicFields.JournalDashboardGraph, { destroy: function () { assert.step('destroy'); // nv is fully loaded only when nvd3.js has been loaded @@ -2422,7 +2419,7 @@ QUnit.module('basic_fields', { }); kanban.destroy(); - testUtils.unpatch(basicFields.JournalDashboardGraph); + testUtils.mock.unpatch(basicFields.JournalDashboardGraph); assert.verifySteps(['destroy']); @@ -2452,14 +2449,14 @@ QUnit.module('basic_fields', { concurrency.delay(0).then(function () { return concurrency.delay(0); }).then(function () { - assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 2, "there should be two graph rendered"); + assert.containsN(kanban, '.o_dashboard_graph svg', 2, "there should be two graph rendered"); return kanban.update({}); }).then(function () { return concurrency.delay(0); // one graph is re-rendered }).then(function () { return concurrency.delay(0); // one graph is re-rendered }).then(function () { - assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 2, "there should be one graph rendered"); + assert.containsN(kanban, '.o_dashboard_graph svg', 2, "there should be one graph rendered"); kanban.destroy(); done(); }); @@ -2488,12 +2485,12 @@ QUnit.module('basic_fields', { concurrency.delay(0).then(function () { return concurrency.delay(0); }).then(function () { - assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 2, "there should be two graph rendered"); + assert.containsN(kanban, '.o_dashboard_graph svg', 2, "there should be two graph rendered"); return kanban.update({groupBy: ['selection'], domain: [['int_field', '=', 10]]}); }).then(function () { return concurrency.delay(0); }).then(function () { - assert.strictEqual(kanban.$('.o_dashboard_graph svg').length, 1, "there should be one graph rendered"); + assert.containsOnce(kanban, '.o_dashboard_graph svg', "there should be one graph rendered"); kanban.destroy(); done(); }); @@ -2550,18 +2547,18 @@ QUnit.module('basic_fields', { assert.notOk(form.$('td span.o_row_handle').is(':visible'), "handle should be invisible in readonly mode"); - assert.strictEqual(form.$('span.o_row_handle').length, 2, "should have 2 handles"); + assert.containsN(form, 'span.o_row_handle', 2, "should have 2 handles"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.ok(form.$('td:first').hasClass('o_handle_cell'), + assert.hasClass(form.$('td:first'),'o_handle_cell', "column widget should be displayed in css class"); assert.ok(form.$('td span.o_row_handle').is(':visible'), "handle should be visible in readonly mode"); - form.$('td').eq(1).click(); - assert.strictEqual(form.$('td:first span.o_row_handle').length, 1, + testUtils.dom.click(form.$('td').eq(1)); + assert.containsOnce(form, 'td:first span.o_row_handle', "content of the cell should have been replaced"); form.destroy(); }); @@ -2579,7 +2576,7 @@ QUnit.module('basic_fields', { '', }); - assert.strictEqual(list.$('.o_row_handle:visible').length, this.data.partner.records.length, + assert.containsN(list, '.o_row_handle:visible', this.data.partner.records.length, 'there should be a visible handle for each record'); list.destroy(); }); @@ -2603,13 +2600,13 @@ QUnit.module('basic_fields', { assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0, "datepicker should be closed initially"); - testUtils.openDatepicker(form.$('.o_datepicker')); + testUtils.dom.openDatepicker(form.$('.o_datepicker')); assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 1, "datepicker should be opened"); // focus another field - form.$('.o_field_widget[name=foo]').click().focus(); + testUtils.dom.click(form.$('.o_field_widget[name=foo]').focus().mouseenter()); assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0, "datepicker should close itself when the user clicks outside"); @@ -2644,15 +2641,15 @@ QUnit.module('basic_fields', { res_id: 4, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // open datepicker and select a date - testUtils.openDatepicker(form.$('.o_datepicker')); + testUtils.dom.openDatepicker(form.$('.o_datepicker')); assert.strictEqual(form.$('.o_datepicker_input').val(), '', "date field's input should be empty on first click"); - $('.day:contains(22)').click(); + testUtils.dom.click($('.day:contains(22)')); // re-open datepicker - testUtils.openDatepicker(form.$('.o_datepicker')); + testUtils.dom.openDatepicker(form.$('.o_datepicker')); assert.strictEqual($('.day.active').text(), '22', "datepicker should be highlight with 22nd day of month"); @@ -2688,25 +2685,25 @@ QUnit.module('basic_fields', { 'the date should be correctly displayed in readonly'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017', 'the date should be correct in edit mode'); // open datepicker and select another value - testUtils.openDatepicker(form.$('.o_datepicker')); + testUtils.dom.openDatepicker(form.$('.o_datepicker')); assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open'); assert.strictEqual($('.day.active').data('day'), '02/03/2017', 'datepicker should be highlight February 3'); - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection - $('.bootstrap-datetimepicker-widget .year:contains(2017)').click(); - $('.bootstrap-datetimepicker-widget .month').eq(1).click(); // February - $('.day:contains(22)').click(); // select the 22 February + testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first()); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)').first()); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1)); + testUtils.dom.click($('.day:contains(22)')); assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed'); assert.strictEqual(form.$('.o_datepicker_input').val(), '02/22/2017', 'the selected date should be displayed in the input'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_date').text(), '02/22/2017', 'the selected date should be displayed after saving'); form.destroy(); @@ -2735,7 +2732,7 @@ QUnit.module('basic_fields', { 'the date should be correctly displayed in readonly'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017', 'the date should be correct in edit mode'); @@ -2756,19 +2753,19 @@ QUnit.module('basic_fields', { }); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // open datepicker and select another value - testUtils.openDatepicker(form.$('.o_datepicker')); - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection - $('.bootstrap-datetimepicker-widget .year').eq(11).click(); // last year - $('.bootstrap-datetimepicker-widget .month').eq(11).click(); // December - $('.day:contains(31)').click(); // select the 31 December + testUtils.dom.openDatepicker(form.$('.o_datepicker')); + 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').eq(11)); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(11)); + testUtils.dom.click($('.day:contains(31)')); var $warn = form.$('.o_datepicker_warning:visible'); assert.strictEqual($warn.length, 1, "should have a warning in the form view"); - form.$('.o_field_widget[name=date] input').val('').trigger('change'); // remove the value + testUtils.fields.editSelect(form.$('.o_field_widget[name=date] input'), ''); // remove the value $warn = form.$('.o_datepicker_warning:visible'); assert.strictEqual($warn.length, 0, "the warning in the form view should be hidden"); @@ -2799,9 +2796,9 @@ QUnit.module('basic_fields', { var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first(); assert.strictEqual($cell.text(), '02/03/2017', 'the date should be displayed correctly in readonly'); - $cell.click(); + testUtils.dom.click($cell); - assert.strictEqual(list.$('input.o_datepicker_input').length, 1, + assert.containsOnce(list, 'input.o_datepicker_input', "the view should have a date input for editable mode"); assert.strictEqual(list.$('input.o_datepicker_input').get(0), document.activeElement, @@ -2811,19 +2808,19 @@ QUnit.module('basic_fields', { 'the date should be correct in edit mode'); // open datepicker and select another value - testUtils.openDatepicker(list.$('.o_datepicker')); + testUtils.dom.openDatepicker(list.$('.o_datepicker')); assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open'); - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection - $('.bootstrap-datetimepicker-widget .year:contains(2017)').click(); - $('.bootstrap-datetimepicker-widget .month').eq(1).click(); // February - $('.day:contains(22)').click(); // select the 22 February + 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)')); assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed'); assert.strictEqual(list.$('.o_datepicker_input').val(), '02/22/2017', 'the selected date should be displayed in the input'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector)').text(), '02/22/2017', 'the selected date should be displayed after saving'); @@ -2851,16 +2848,16 @@ QUnit.module('basic_fields', { }); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017', 'the date should be correct in edit mode'); - form.$('.o_datepicker_input').val('').trigger('input').trigger('change').trigger('focusout'); + testUtils.fields.editAndTrigger(form.$('.o_datepicker_input'), '', ['input', 'change', 'focusout']); assert.strictEqual(form.$('.o_datepicker_input').val(), '', 'should have correctly removed the value'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_date').text(), '', 'the selected date should be displayed after saving'); @@ -2892,9 +2889,8 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_datepicker_input').val(), '02/08/2017', 'the date should be correct'); - form.$('input[name="datetime"]').val('02/08/2017') - .trigger('input').trigger('change').trigger('focusout'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editAndTrigger(form.$('input[name="datetime"]'),'02/08/2017', ['input', 'change', 'focusout']); + testUtils.form.clickSave(form); assert.verifySteps(['read']); // should not have save as nothing changed @@ -2928,24 +2924,23 @@ QUnit.module('basic_fields', { 'the datetime should be correctly displayed in readonly'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_datepicker_input').val(), expectedDateString, 'the datetime should be correct in edit mode'); // select 22 February at 8:23:33 assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open'); - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection - $('.bootstrap-datetimepicker-widget .year:contains(2017)').click(); - $('.bootstrap-datetimepicker-widget .month').eq(3).click(); // April - $('.bootstrap-datetimepicker-widget .day:contains(22)').click(); - $('.bootstrap-datetimepicker-widget .fa-clock-o').click(); - $('.bootstrap-datetimepicker-widget .timepicker-hour').click(); - $('.bootstrap-datetimepicker-widget .hour:contains(08)').click(); - $('.bootstrap-datetimepicker-widget .timepicker-minute').click(); - $('.bootstrap-datetimepicker-widget .minute:contains(25)').click(); - $('.bootstrap-datetimepicker-widget .timepicker-second').click(); - $('.bootstrap-datetimepicker-widget .second:contains(35)').click(); - $('.bootstrap-datetimepicker-widget .fa-times').click(); // close + 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(3)); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .day:contains(22)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .fa-clock-o')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hour')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .hour:contains(08)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-minute')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .minute:contains(25)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-second')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .second:contains(35)')); assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed'); var newExpectedDateString = "04/22/2017 08:25:35"; @@ -2953,7 +2948,7 @@ QUnit.module('basic_fields', { 'the selected date should be displayed in the input'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_date').text(), newExpectedDateString, 'the selected date should be displayed after saving'); @@ -3006,7 +3001,7 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_date input').val(), expectedDateString, 'the datetime should be correctly displayed in readonly'); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickDiscard(form); assert.strictEqual($('.modal').length, 0, "there should not be a Warning dialog"); @@ -3041,8 +3036,8 @@ QUnit.module('basic_fields', { 'the datetime should be correctly displayed in readonly'); // switch to edit mode - $cell.click(); - assert.strictEqual(list.$('input.o_datepicker_input').length, 1, + testUtils.dom.click($cell); + assert.containsOnce(list, 'input.o_datepicker_input', "the view should have a date input for editable mode"); assert.strictEqual(list.$('input.o_datepicker_input').get(0), document.activeElement, @@ -3053,19 +3048,18 @@ QUnit.module('basic_fields', { // select 22 February at 8:23:33 assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open'); - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection - $('.bootstrap-datetimepicker-widget .year:contains(2017)').click(); - $('.bootstrap-datetimepicker-widget .month').eq(3).click(); // April - $('.bootstrap-datetimepicker-widget .day:contains(22)').click(); - $('.bootstrap-datetimepicker-widget .fa-clock-o').click(); - $('.bootstrap-datetimepicker-widget .timepicker-hour').click(); - $('.bootstrap-datetimepicker-widget .hour:contains(08)').click(); - $('.bootstrap-datetimepicker-widget .timepicker-minute').click(); - $('.bootstrap-datetimepicker-widget .minute:contains(25)').click(); - $('.bootstrap-datetimepicker-widget .timepicker-second').click(); - $('.bootstrap-datetimepicker-widget .second:contains(35)').click(); - $('.bootstrap-datetimepicker-widget .fa-times').click(); // close + 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(3)); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .day:contains(22)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .fa-clock-o')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hour')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .hour:contains(08)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-minute')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .minute:contains(25)')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-second')); + testUtils.dom.click($('.bootstrap-datetimepicker-widget .second:contains(35)')); assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed'); var newExpectedDateString = "04/22/2017 08:25:35"; @@ -3073,7 +3067,7 @@ QUnit.module('basic_fields', { 'the selected datetime should be displayed in the input'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector)').text(), newExpectedDateString, 'the selected datetime should be displayed after saving'); @@ -3107,16 +3101,16 @@ QUnit.module('basic_fields', { }); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_datepicker_input').val(), '02/08/2017 12:00:00', 'the date time should be correct in edit mode'); - $('.o_datepicker_input').val('').trigger('input').trigger('change').trigger('focusout'); + testUtils.fields.editAndTrigger($('.o_datepicker_input'), '', ['input', 'change', 'focusout']); assert.strictEqual(form.$('.o_datepicker_input').val(), '', "should have an empty input"); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_date').text(), '', 'the selected date should be displayed after saving'); @@ -3160,7 +3154,7 @@ QUnit.module('basic_fields', { 'the datetime (datetime widget) should be correctly displayed in tree view'); // switch to form view - form.$('.o_field_widget[name=p] .o_data_row').click(); + testUtils.dom.click(form.$('.o_field_widget[name=p] .o_data_row')); assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/07/2017', 'the datetime (date widget) should be correctly displayed in form view'); @@ -3204,7 +3198,7 @@ QUnit.module('basic_fields', { 'the datetime (datetime widget) should be correctly displayed in tree view'); // switch to form view - form.$('.o_field_widget[name=p] .o_data_row').click(); + testUtils.dom.click(form.$('.o_field_widget[name=p] .o_data_row')); assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/08/2017', 'the datetime (date widget) should be correctly displayed in form view'); @@ -3212,7 +3206,7 @@ QUnit.module('basic_fields', { }); QUnit.test('datepicker option: daysOfWeekDisabled', function (assert) { - assert.expect(2); + assert.expect(42); this.data.partner.fields.datetime.default = "2017-08-02 12:00:05"; this.data.partner.fields.datetime.required = true; @@ -3228,12 +3222,16 @@ QUnit.module('basic_fields', { res_id: 1, }); - form.$buttons.find('.o_form_button_create').click(); - assert.ok($('.day:last-child(),.day:nth-child(2)').hasClass('disabled'), - 'first and last days must be disabled'); - assert.notOk($('.day:not(:last-child()):not(:nth-child(2))').hasClass('disabled'), - 'other days must stay clickable'); - + testUtils.form.clickCreate(form); + $.each($('.day:last-child(),.day:nth-child(2)'), function (index, value) { + assert.hasClass(value, 'disabled', 'first and last days must be disabled'); + }); + // the assertions below could be replaced by a single hasClass classic on the jQuery set using the idea + // All not <=> not Exists. But we want to be sure that the set is non empty. We don't have an helper + // function for that. + $.each($('.day:not(:last-child()):not(:nth-child(2))'), function (index, value) { + assert.doesNotHaveClass(value, 'disabled', 'other days must stay clickable'); + }); form.destroy(); }); @@ -3262,17 +3260,17 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a09.10', 'The value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), '9.10', 'The input should be rendered without the currency symbol.'); assert.strictEqual(form.$('input').parent().children().first().text(), '$', 'The input should be preceded by a span containing the currency symbol.'); - form.$('input').val('108.2458938598598').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_monetary input'), '108.2458938598598'); assert.strictEqual(form.$('input').val(), '108.2458938598598', 'The value should not be formated yet.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // Non-breaking space between the currency and the amount assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0108.25', 'The new value should be rounded properly.'); @@ -3303,17 +3301,17 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '0.00\u00a0€', 'The value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').first().val(), '0.00', 'The input should be rendered without the currency symbol.'); assert.strictEqual(form.$('input').parent().children().eq(1).text(), '€', 'The input should be followed by a span containing the currency symbol.'); - form.$('input').first().val('108.2458938598598').trigger('input'); + testUtils.fields.editInput(form.$('input').first(), '108.2458938598598'); assert.strictEqual(form.$('input').first().val(), '108.2458938598598', 'The value should not be formated yet.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // Non-breaking space between the currency and the amount assert.strictEqual(form.$('.o_field_widget').first().text(), '108.25\u00a0€', 'The new value should be rounded properly.'); @@ -3360,17 +3358,17 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '99.1234\u00a0Bs.F', 'The value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').first().val(), '99.1234', 'The input should be rendered without the currency symbol.'); assert.strictEqual(form.$('input').parent().children().eq(1).text(), 'Bs.F', 'The input should be followed by a span containing the currency symbol.'); - form.$('input').first().val('99.111111111').trigger('input'); + testUtils.fields.editInput(form.$('input').first(), '99.111111111'); assert.strictEqual(form.$('input').first().val(), '99.111111111', 'The value should not be formated yet.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // Non-breaking space between the currency and the amount assert.strictEqual(form.$('.o_field_widget').first().text(), '99.1111\u00a0Bs.F', 'The new value should be rounded properly.'); @@ -3408,22 +3406,22 @@ QUnit.module('basic_fields', { // switch to edit mode var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector):contains($)'); - $cell.click(); + testUtils.dom.click($cell); assert.strictEqual($cell.children().length, 1, 'The cell td should only contain the special div of monetary widget.'); - assert.strictEqual(list.$('[name="qux"] input').length, 1, + assert.containsOnce(list, '[name="qux"] input', 'The view should have 1 input for editable monetary float.'); assert.strictEqual(list.$('[name="qux"] input').val(), '9.10', 'The input should be rendered without the currency symbol.'); assert.strictEqual(list.$('[name="qux"] input').parent().children().first().text(), '$', 'The input should be preceded by a span containing the currency symbol.'); - list.$('[name="qux"] input').val('108.2458938598598').trigger('input'); + testUtils.fields.editInput(list.$('[name="qux"] input'), '108.2458938598598'); assert.strictEqual(list.$('[name="qux"] input').val(), '108.2458938598598', 'The typed value should be correctly displayed.'); - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector):contains($)').text(), '$\u00a0108.25', 'The new value should be rounded properly.'); @@ -3469,20 +3467,19 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_monetary').first().next().html(), "$ 4.20", "readonly value should contain the currency"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_monetary > input').val(), "9.10", "input value in edition should only contain the value, without the currency"); - form.$('input[type="checkbox"]').click(); // Change the field on which the monetary depends - assert.strictEqual(form.$('.o_field_monetary > input').length, 1, + testUtils.dom.click(form.$('input[type="checkbox"]')); + assert.containsOnce(form, '.o_field_monetary > input', "After the onchange, the monetary should not have been duplicated"); - assert.strictEqual(form.$('.o_field_monetary[name=quux]').length, 1, + assert.containsOnce(form, '.o_field_monetary[name=quux]', "After the onchange, the monetary readonly field should not have been duplicated"); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').click(); - $dropdown.find('li:not(.o_m2o_dropdown_option):last').mouseenter().click(); + testUtils.fields.many2one.clickOpenDropdown('currency_id'); + testUtils.fields.many2one.clickItem('currency_id','€'); assert.strictEqual(form.$('.o_field_monetary > span').html(), "€", "After currency change, the monetary field currency should have been updated"); assert.strictEqual(form.$('.o_field_monetary').first().next().html(), "4.20 €", @@ -3552,30 +3549,30 @@ QUnit.module('basic_fields', { // test the monetary field inside the one2many var $o2m = form.$('.o_field_widget[name=p]'); - $o2m.find('.o_field_x2many_list_row_add a').click(); - $o2m.find('.o_field_widget input').val("22").trigger('input'); + testUtils.dom.click($o2m.find('.o_field_x2many_list_row_add a')); + testUtils.fields.editInput($o2m.find('.o_field_widget input'), "22"); assert.strictEqual($o2m.find('.o_field_widget input').get(0), document.activeElement, "the focus should still be on the input"); assert.strictEqual($o2m.find('.o_field_widget input').val(), "22", "the value should not have been formatted yet"); - form.$el.click(); // focusout the input + testUtils.dom.click(form.$el); assert.strictEqual($o2m.find('.o_field_widget[name=qux]').html(), "$ 22.00", "the value should have been formatted after losing the focus"); // test the monetary field inside the many2many var $m2m = form.$('.o_field_widget[name=m2m]'); - $m2m.find('.o_data_row td:first').click(); - $m2m.find('.o_field_widget input').val("22").trigger('input'); + testUtils.dom.click($m2m.find('.o_data_row td:first')); + testUtils.fields.editInput($m2m.find('.o_field_widget input'), "22"); assert.strictEqual($m2m.find('.o_field_widget input').get(0), document.activeElement, "the focus should still be on the input"); assert.strictEqual($m2m.find('.o_field_widget input').val(), "22", "the value should not have been formatted yet"); - form.$el.click(); // focusout the input + testUtils.dom.click(form.$el); assert.strictEqual($m2m.find('.o_field_widget[name=qux]').html(), "22.00 €", "the value should have been formatted after losing the focus"); @@ -3583,7 +3580,7 @@ QUnit.module('basic_fields', { form.destroy(); }); - QUnit.test('monetary field with currency set by an onchange', function (assert) { + QUnit.test('monetary field with currency set by an onchange',async function (assert) { // this test ensures that the monetary field can be re-rendered with and // without currency (which can happen as the currency can be set by an // onchange) @@ -3609,31 +3606,33 @@ QUnit.module('basic_fields', { }, }); - list.$buttons.find('.o_list_button_add').click(); - assert.strictEqual(list.$('div.o_field_widget[name=qux] input').length, 1, + testUtils.dom.click(list.$buttons.find('.o_list_button_add')); + assert.containsOnce(list, 'div.o_field_widget[name=qux] input', "monetary field should have been rendered correctly (without currency)"); - assert.strictEqual(list.$('.o_field_widget[name=qux] span').length, 0, + assert.containsNone(list, '.o_field_widget[name=qux] span', "monetary field should have been rendered correctly (without currency)"); // set a value for int_field -> should set the currency and re-render qux - list.$('.o_field_widget[name=int_field]').click().val('7').trigger('input'); - assert.strictEqual(list.$('div.o_field_widget[name=qux] input').length, 1, + testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'),'7'); + assert.containsOnce(list, 'div.o_field_widget[name=qux] input', "monetary field should have been re-rendered correctly (with currency)"); assert.strictEqual(list.$('.o_field_widget[name=qux] span:contains(€)').length, 1, "monetary field should have been re-rendered correctly (with currency)"); var $quxInput = list.$('.o_field_widget[name=qux] input'); - $quxInput.click(); // check that the field is focusable + testUtils.dom.click($quxInput); assert.strictEqual(document.activeElement, $quxInput[0], "focus should be on the qux field's input"); // unset the value of int_field -> should unset the currency and re-render qux - list.$('.o_field_widget[name=int_field]').click().val('0').trigger('input'); + testUtils.dom.click(list.$('.o_field_widget[name=int_field]')); + testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'),'0'); $quxInput = list.$('div.o_field_widget[name=qux] input'); assert.strictEqual($quxInput.length, 1, "monetary field should have been re-rendered correctly (without currency)"); - assert.strictEqual(list.$('.o_field_widget[name=qux] span').length, 0, + assert.containsNone(list, '.o_field_widget[name=qux] span', "monetary field should have been re-rendered correctly (without currency)"); - $quxInput.click(); // check that the field is still focusable + await concurrency.delay(0); + testUtils.dom.click($quxInput); assert.strictEqual(document.activeElement, $quxInput[0], "focus should be on the qux field's input"); @@ -3653,7 +3652,7 @@ QUnit.module('basic_fields', { res_id: 4, }); - assert.notOk(form.$('.o_field_widget').hasClass('o_field_empty'), + assert.doesNotHaveClass(form.$('.o_field_widget'), 'o_field_empty', 'Non-set integer field should be recognized as 0.'); assert.strictEqual(form.$('.o_field_widget').text(), "0", 'Non-set integer field should be recognized as 0.'); @@ -3672,18 +3671,18 @@ QUnit.module('basic_fields', { res_id: 2, }); - assert.ok(!form.$('.o_field_widget').hasClass('o_field_empty'), + assert.doesNotHaveClass(form.$('.o_field_widget'), 'o_field_empty', 'Integer field should be considered set for value 0.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), '0', 'The value should be rendered correctly in edit mode.'); - form.$('input').val('-18').trigger('input'); + testUtils.fields.editInput(form.$('input'), '-18'); assert.strictEqual(form.$('input').val(), '-18', 'The value should be correctly displayed in the input.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), '-18', 'The new value should be saved and displayed properly.'); @@ -3725,16 +3724,16 @@ QUnit.module('basic_fields', { // switch to edit mode var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first(); - $cell.click(); + testUtils.dom.click($cell); - assert.strictEqual(list.$('input[name="int_field"]').length, 1, + assert.containsOnce(list, 'input[name="int_field"]', 'The view should have 1 input for editable integer.'); - list.$('input[name="int_field"]').val('-28').trigger('input'); + testUtils.fields.editInput(list.$('input[name="int_field"]'), '-28'); assert.strictEqual(list.$('input[name="int_field"]').val(), '-28', 'The value should be displayed properly in the input.'); - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('td:not(.o_list_record_selector)').first().text(), '-28', 'The new value should be saved and displayed properly.'); @@ -3758,18 +3757,18 @@ QUnit.module('basic_fields', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'), 'Integer field with option type must have a type attribute.'); - assert.strictEqual(form.$('.o_field_widget').attr('type'), 'number', + assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'number', 'Integer field with option type must have a type attribute equals to "number".'); - form.$('input').val('1234567890').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.fields.editInput(form.$('input'), '1234567890'); + testUtils.form.clickSave(form); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget').val(), '1234567890', 'Integer value must be not formatted if input type is number.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), '1,234,567,890', 'Integer value must be formatted in readonly view even if the input type is number.'); @@ -3793,13 +3792,13 @@ QUnit.module('basic_fields', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_widget').attr('type'), 'text', + testUtils.form.clickEdit(form); + assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'text', 'Integer field without option type must have a text type (default type).'); - form.$('input').val('1234567890').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.fields.editInput(form.$('input'), '1234567890'); + testUtils.form.clickSave(form); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget').val(), '1,234,567,890', 'Integer value must be formatted if input type isn\'t number.'); @@ -3835,15 +3834,15 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '09:06', 'The formatted time value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), '09:06', 'The value should be rendered correctly in the input.'); - form.$('input').val('-11:48').trigger('input'); + testUtils.fields.editInput(form.$('input'), '-11:48'); assert.strictEqual(form.$('input').val(), '-11:48', 'The new value should be displayed properly in the input.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').first().text(), '-11:48', 'The new value should be saved and displayed properly.'); @@ -3877,13 +3876,13 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '4.55', // 9.1 / 0.5 'The formatted value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), '4.55', 'The value should be rendered correctly in the input.'); - form.$('input').val('2.3').trigger('input'); + testUtils.fields.editInput(form.$('input'), '2.3'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').first().text(), '2.30', 'The new value should be saved and displayed properly.'); @@ -3916,17 +3915,17 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget').first().text(), '0.056', 'The formatted time value should be displayed properly.'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('button.o_field_float_toggle').text(), '0.056', 'The value should be rendered correctly on the button.'); - form.$('button.o_field_float_toggle').click(); // clicking will make the next value 1, since 0 was the closest of 0.056 + testUtils.dom.click(form.$('button.o_field_float_toggle')); assert.strictEqual(form.$('button.o_field_float_toggle').text(), '1.000', 'The value should be rendered correctly on the button.'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').first().text(), '1.000', 'The new value should be saved and displayed properly.'); @@ -3966,17 +3965,17 @@ QUnit.module('basic_fields', { "value should be displayed properly"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[type="text"].o_field_widget').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'input[type="text"].o_field_widget', "should have an input for the phone field"); assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop', "input should contain field value in edit mode"); // change value in edit mode - form.$('input[type="text"].o_field_widget').val('new').trigger('input'); + testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('a.o_field_widget.o_form_uri').text(), 'new', "new value should be displayed properly"); @@ -4003,24 +4002,24 @@ QUnit.module('basic_fields', { assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop', "value should be displayed properly"); - assert.strictEqual(list.$('a.o_field_widget.o_form_uri').length, 5, + assert.containsN(list, 'a.o_field_widget.o_form_uri', 5, "should have the correct classnames"); // Edit a line and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), 'should be set as edit mode'); + testUtils.dom.click($cell); + assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode'); assert.strictEqual($cell.find('input').val(), 'yop', 'should have the corect value in internal input'); - $cell.find('input').val('new').trigger('input'); + testUtils.fields.editInput($cell.find('input'), 'new'); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), 'should not be in edit mode anymore'); + assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore'); assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new', "value should be properly updated"); - assert.strictEqual(list.$('a.o_field_widget.o_form_uri').length, 5, + assert.containsN(list, 'a.o_field_widget.o_form_uri', 5, "should still have links with correct classes"); list.destroy(); @@ -4043,7 +4042,7 @@ QUnit.module('basic_fields', { '', }); - form.$('input[name=display_name]').click(); + testUtils.dom.click(form.$('input[name=display_name]')); assert.strictEqual(form.$('input[name="display_name"]')[0], document.activeElement, "display_name should be focused"); form.$('input[name="display_name"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); @@ -4123,7 +4122,7 @@ QUnit.module('basic_fields', { // occurs in a setTimeout after 200ms so it's not trivial to test it here. // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2, "should still have two stars"); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1, @@ -4132,7 +4131,7 @@ QUnit.module('basic_fields', { "should still have one empty star since the value is the second value"); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2, "should still have two stars"); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1, @@ -4141,7 +4140,7 @@ QUnit.module('basic_fields', { "should still have one empty star since the value is the second value"); // switch to edit mode to check that the new value was properly written - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2, "should still have two stars"); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1, @@ -4150,7 +4149,7 @@ QUnit.module('basic_fields', { "should still have one empty star since the value is the second value"); // click on the second star in edit mode - form.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').last().click(); + testUtils.dom.click(form.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').last()); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2, "should still have two stars"); @@ -4160,7 +4159,7 @@ QUnit.module('basic_fields', { "should now have no empty star since the value is the third value"); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2, "should still have two stars"); assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 2, @@ -4195,7 +4194,7 @@ QUnit.module('basic_fields', { // switch to edit mode and check the result var $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); + testUtils.dom.click($cell); assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2, "should have two stars for representing each possible value: no star, one star and two stars"); assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1, @@ -4204,7 +4203,7 @@ QUnit.module('basic_fields', { "should have one empty star since the value is the second value"); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2, "should have two stars for representing each possible value: no star, one star and two stars"); assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1, @@ -4222,7 +4221,7 @@ QUnit.module('basic_fields', { "should temporary have no empty star since we are hovering the third value"); // click on the first star in readonly mode - list.$('.o_priority a.o_priority_star.fa-star').first().click(); + testUtils.dom.click(list.$('.o_priority a.o_priority_star.fa-star').first()); assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2, "should still have two stars"); @@ -4233,7 +4232,7 @@ QUnit.module('basic_fields', { // re-enter edit mode to force re-rendering the widget to check if the value was correctly saved $cell = list.$('tbody td:not(.o_list_record_selector)').first(); - $cell.click(); + testUtils.dom.click($cell); assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2, "should still have two stars"); @@ -4243,7 +4242,7 @@ QUnit.module('basic_fields', { "should now have two empty stars since the value is the first value"); // Click on second star in edit mode - list.$('.o_priority a.o_priority_star.fa-star-o').last().click(); + testUtils.dom.click(list.$('.o_priority a.o_priority_star.fa-star-o').last()); assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star').length, 2, "should still have two stars"); @@ -4253,7 +4252,7 @@ QUnit.module('basic_fields', { "should now have no empty star since the value is the third value"); // save - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star').length, 2, "should still have two stars"); assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star.fa-star').length, 2, @@ -4287,65 +4286,65 @@ QUnit.module('basic_fields', { }, }); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 1, + assert.containsOnce(form, '.o_field_widget.o_selection > a span.o_status.o_status_red', "should have one red status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_green', "should not have one green status since selection is the second, blocked state"); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, + assert.containsNone(form, '.dropdown-menu.state:visible', "there should not be a dropdown"); // Click on the status button to make the dropdown appear - form.$('.o_field_widget.o_selection .o_status').first().click(); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 1, + testUtils.dom.click(form.$('.o_field_widget.o_selection .o_status').first()); + assert.containsOnce(form, '.dropdown-menu.state:visible', "there should be a dropdown"); - assert.strictEqual(form.$('.dropdown-menu.state:visible .dropdown-item').length, 2, + assert.containsN(form, '.dropdown-menu.state:visible .dropdown-item', 2, "there should be two options in the dropdown"); // Click on the first option, "Normal" - form.$('.dropdown-menu.state:visible .dropdown-item').first().click(); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, + testUtils.dom.click(form.$('.dropdown-menu.state:visible .dropdown-item').first()); + assert.containsNone(form, '.dropdown-menu.state:visible', "there should not be a dropdown anymore"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red', "should not have one red status since selection is the first, normal state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_green', "should not have one green status since selection is the first, normal state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status').length, 1, + assert.containsOnce(form, '.o_field_widget.o_selection > a span.o_status', "should have one grey status since selection is the first, normal state"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, + testUtils.form.clickEdit(form); + assert.containsNone(form, '.dropdown-menu.state:visible', "there should still not be a dropdown"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red', "should still not have one red status since selection is the first, normal state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_green', "should still not have one green status since selection is the first, normal state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status').length, 1, + assert.containsOnce(form, '.o_field_widget.o_selection > a span.o_status', "should still have one grey status since selection is the first, normal state"); // Click on the status button to make the dropdown appear - form.$('.o_field_widget.o_selection .o_status').first().click(); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 1, + testUtils.dom.click(form.$('.o_field_widget.o_selection .o_status').first()); + assert.containsOnce(form, '.dropdown-menu.state:visible', "there should be a dropdown"); - assert.strictEqual(form.$('.dropdown-menu.state:visible .dropdown-item').length, 2, + assert.containsN(form, '.dropdown-menu.state:visible .dropdown-item', 2, "there should be two options in the dropdown"); // Click on the last option, "Done" - form.$('.dropdown-menu.state:visible .dropdown-item').last().click(); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, + testUtils.dom.click(form.$('.dropdown-menu.state:visible .dropdown-item').last()); + assert.containsNone(form, '.dropdown-menu.state:visible', "there should not be a dropdown anymore"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red', "should not have one red status since selection is the third, done state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 1, + assert.containsOnce(form, '.o_field_widget.o_selection > a span.o_status.o_status_green', "should have one green status since selection is the third, done state"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.dropdown-menu.state:visible').length, 0, + testUtils.form.clickSave(form); + assert.containsNone(form, '.dropdown-menu.state:visible', "there should still not be a dropdown anymore"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red', "should still not have one red status since selection is the third, done state"); - assert.strictEqual(form.$('.o_field_widget.o_selection > a span.o_status.o_status_green').length, 1, + assert.containsOnce(form, '.o_field_widget.o_selection > a span.o_status.o_status_green', "should still have one green status since selection is the third, done state"); form.destroy(); @@ -4364,97 +4363,97 @@ QUnit.module('basic_fields', { '', }); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5, "should have five status selection widgets"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 1, + assert.containsOnce(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red', "should have one red status"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 1, + assert.containsOnce(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_green', "should have one green status"); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown"); // Click on the status button to make the dropdown appear var $cell = list.$('tbody td.o_state_selection_cell').first(); - list.$('.o_state_selection_cell .o_selection > a span.o_status').first().click(); - assert.ok(!$cell.parent().hasClass('o_selected_row'), + testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').first()); + assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode since we clicked on the state selection widget'); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 1, + assert.containsOnce(list, '.dropdown-menu.state:visible', "there should be a dropdown"); - assert.strictEqual(list.$('.dropdown-menu.state:visible .dropdown-item').length, 2, + assert.containsN(list, '.dropdown-menu.state:visible .dropdown-item', 2, "there should be two options in the dropdown"); // Click on the first option, "Normal" - list.$('.dropdown-menu.state:visible .dropdown-item').first().click(); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, + testUtils.dom.click(list.$('.dropdown-menu.state:visible .dropdown-item').first()); + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5, "should still have five status selection widgets"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red', "should now have no red status"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 1, + assert.containsOnce(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_green', "should still have one green status"); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown"); // switch to edit mode and check the result $cell = list.$('tbody td.o_state_selection_cell').first(); - $cell.click(); - assert.ok($cell.parent().hasClass('o_selected_row'), + testUtils.dom.click($cell); + assert.hasClass($cell.parent(),'o_selected_row', 'should now be in edit mode'); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5, "should still have five status selection widgets"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red', "should now have no red status"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 1, + assert.containsOnce(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_green', "should still have one green status"); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown"); // Click on the status button to make the dropdown appear - list.$('.o_state_selection_cell .o_selection > a span.o_status').first().click(); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 1, + testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').first()); + assert.containsOnce(list, '.dropdown-menu.state:visible', "there should be a dropdown"); - assert.strictEqual(list.$('.dropdown-menu.state:visible .dropdown-item').length, 2, + assert.containsN(list, '.dropdown-menu.state:visible .dropdown-item', 2, "there should be two options in the dropdown"); // Click on another row - var $firstCell = list.$('tbody td.o_state_selection_cell').first(); var $lastCell = list.$('tbody td.o_state_selection_cell').last(); - $lastCell.click(); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + testUtils.dom.click($lastCell); + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown anymore"); - assert.ok(!$firstCell.parent().hasClass('o_selected_row'), + var $firstCell = list.$('tbody td.o_state_selection_cell').first(); + assert.doesNotHaveClass($firstCell.parent(), 'o_selected_row', 'first row should not be in edit mode anymore'); - assert.ok($lastCell.parent().hasClass('o_selected_row'), + assert.hasClass($lastCell.parent(),'o_selected_row', 'last row should be in edit mode'); // Click on the last status button to make the dropdown appear - list.$('.o_state_selection_cell .o_selection > a span.o_status').last().click(); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 1, + testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').last()); + assert.containsOnce(list, '.dropdown-menu.state:visible', "there should be a dropdown"); - assert.strictEqual(list.$('.dropdown-menu.state:visible .dropdown-item').length, 2, + assert.containsN(list, '.dropdown-menu.state:visible .dropdown-item', 2, "there should be two options in the dropdown"); // Click on the last option, "Done" - list.$('.dropdown-menu.state:visible .dropdown-item').last().click(); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + testUtils.dom.click(list.$('.dropdown-menu.state:visible .dropdown-item').last()); + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown anymore"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5, "should still have five status selection widgets"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red', "should still have no red status"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 2, + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_green', 2, "should now have two green status"); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown"); // save - list.$buttons.find('.o_list_button_save').click(); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status').length, 5, + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5, "should have five status selection widgets"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_red').length, 0, + assert.containsNone(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red', "should have no red status"); - assert.strictEqual(list.$('.o_state_selection_cell .o_selection > a span.o_status.o_status_green').length, 2, + assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_green', 2, "should have two green status"); - assert.strictEqual(list.$('.dropdown-menu.state:visible').length, 0, + assert.containsNone(list, '.dropdown-menu.state:visible', "there should not be a dropdown"); list.destroy(); @@ -4482,14 +4481,14 @@ QUnit.module('basic_fields', { domain: [['id', '=', 1]], }); - assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star').length, 1, + assert.containsOnce(kanban, '.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star', 'should be favorite'); assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Remove from Favorites', 'the label should say "Remove from Favorites"'); // click on favorite - kanban.$('.o_field_widget.o_favorite').click(); - assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star').length, 0, + testUtils.dom.click(kanban.$('.o_field_widget.o_favorite')); + assert.containsNone(kanban, '.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star', 'should not be favorite'); assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Add to Favorites', 'the label should say "Add to Favorites"'); @@ -4514,35 +4513,35 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1, + assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star', 'should be favorite'); assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites', 'the label should say "Remove from Favorites"'); // click on favorite - form.$('.o_field_widget.o_favorite').click(); - assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 0, + testUtils.dom.click(form.$('.o_field_widget.o_favorite')); + assert.containsNone(form, '.o_field_widget.o_favorite > a i.fa.fa-star', 'should not be favorite'); assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites', 'the label should say "Add to Favorites"'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star-o').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star-o', 'should not be favorite'); assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites', 'the label should say "Add to Favorites"'); // click on favorite - form.$('.o_field_widget.o_favorite').click(); - assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1, + testUtils.dom.click(form.$('.o_field_widget.o_favorite')); + assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star', 'should be favorite'); assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites', 'the label should say "Remove from Favorites"'); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_widget.o_favorite > a i.fa.fa-star').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star', 'should be favorite'); assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites', 'the label should say "Remove from Favorites"'); @@ -4562,22 +4561,22 @@ QUnit.module('basic_fields', { '', }); - assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 1, + assert.containsOnce(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star', 'should be favorite'); // switch to edit mode - list.$('tbody td:not(.o_list_record_selector)').first().click(); - assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 1, + testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector)').first()); + assert.containsOnce(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star', 'should be favorite'); // click on favorite - list.$('.o_data_row:first .o_field_widget.o_favorite').click(); - assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star').length, 0, + testUtils.dom.click(list.$('.o_data_row:first .o_field_widget.o_favorite')); + assert.containsNone(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star', 'should not be favorite'); // save - list.$buttons.find('.o_list_button_save').click(); - assert.strictEqual(list.$('.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star-o').length, 1, + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); + assert.containsOnce(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star-o', 'should not be favorite'); list.destroy(); @@ -4604,33 +4603,33 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').length, 1, + assert.containsOnce(form, '.o_field_widget.badge.badge-warning', "should have a warning status label since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.badge.badge-secondary').length, 0, + assert.containsNone(form, '.o_field_widget.badge.badge-secondary', "should not have a default status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.badge.badge-success').length, 0, + assert.containsNone(form, '.o_field_widget.badge.badge-success', "should not have a success status since selection is the second, blocked state"); assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the label should say 'Blocked' since this is the label value for that state"); // // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_field_widget.badge.badge-warning', "should have a warning status label since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.badge.badge-secondary').length, 0, + assert.containsNone(form, '.o_field_widget.badge.badge-secondary', "should not have a default status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.badge.badge-success').length, 0, + assert.containsNone(form, '.o_field_widget.badge.badge-success', "should not have a success status since selection is the second, blocked state"); assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the label should say 'Blocked' since this is the label value for that state"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.o_field_widget.badge.badge-warning', "should have a warning status label since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.badge.badge-secondary').length, 0, + assert.containsNone(form, '.o_field_widget.badge.badge-secondary', "should not have a default status since selection is the second, blocked state"); - assert.strictEqual(form.$('.o_field_widget.badge.badge-success').length, 0, + assert.containsNone(form, '.o_field_widget.badge.badge-success', "should not have a success status since selection is the second, blocked state"); assert.strictEqual(form.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the label should say 'Blocked' since this is the label value for that state"); @@ -4654,49 +4653,49 @@ QUnit.module('basic_fields', { assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3, "should have three visible status labels"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-warning', "should have one warning status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the warning label should read 'Blocked'"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-secondary', "should have one default status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal', "the default label should read 'Normal'"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-success', "should have one success status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done', "the success label should read 'Done'"); // switch to edit mode and check the result - list.$('tbody td:not(.o_list_record_selector)').first().click(); + testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector)').first()); assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3, "should have three visible status labels"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-warning', "should have one warning status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the warning label should read 'Blocked'"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-secondary', "should have one default status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal', "the default label should read 'Normal'"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-success', "should have one success status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done', "the success label should read 'Done'"); // save and check the result - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3, "should have three visible status labels"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-warning', "should have one warning status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-warning').text(), 'Blocked', "the warning label should read 'Blocked'"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-secondary', "should have one default status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-secondary').text(), 'Normal', "the default label should read 'Normal'"); - assert.strictEqual(list.$('.o_field_widget.badge.badge-success').length, 1, + assert.containsOnce(list, '.o_field_widget.badge.badge-success', "should have one success status label"); assert.strictEqual(list.$('.o_field_widget.badge.badge-success').text(), 'Done', "the success label should read 'Done'"); @@ -4763,7 +4762,7 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should have 10 as value"); @@ -4771,8 +4770,8 @@ QUnit.module('basic_fields', { 'int_field', "should have 'int_field' as text"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should still have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should still have 10 as value"); @@ -4780,8 +4779,8 @@ QUnit.module('basic_fields', { 'int_field', "should have 'int_field' as text"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should have 10 as value"); @@ -4815,7 +4814,7 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should have 10 as value"); @@ -4823,8 +4822,8 @@ QUnit.module('basic_fields', { 'yop', "should have 'yop' as text, since it is the value of field foo"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should still have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should still have 10 as value"); @@ -4832,8 +4831,8 @@ QUnit.module('basic_fields', { 'yop', "should have 'yop' as text, since it is the value of field foo"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should have 10 as value"); @@ -4866,7 +4865,7 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should have 10 as value"); @@ -4874,8 +4873,8 @@ QUnit.module('basic_fields', { '', "should not have any label"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should still have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should still have 10 as value"); @@ -4883,8 +4882,8 @@ QUnit.module('basic_fields', { '', "should not have any label"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info', "should have one stat button"); assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(), '10', "should have 10 as value"); @@ -4914,7 +4913,7 @@ QUnit.module('basic_fields', { res_id: 1, }); - assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1, + assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie', "should have a pie chart"); assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(), '10%', "should have 10% as pie value since int_field=10"); @@ -4924,8 +4923,8 @@ QUnit.module('basic_fields', { 'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie', "should have a pie chart"); assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(), '10%', "should have 10% as pie value since int_field=10"); @@ -4935,8 +4934,8 @@ QUnit.module('basic_fields', { 'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie', "should have a pie chart"); assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(), '10%', "should have 10% as pie value since int_field=10"); @@ -4965,35 +4964,35 @@ QUnit.module('basic_fields', { res_id: 3, }); - assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1, + assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie', "should have a pie chart"); assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(), '80%', "should have 80% as pie value since int_field=80"); assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'), 'transform: rotate(288deg);'), "left mask should be rotated from 360*(80/100) = 288 degrees"); - assert.ok(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().hasClass('o_full'), + assert.hasClass(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last(),'o_full', "right mask should be hidden since the value > 50%"); // switch to edit mode and check the result - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie', "should have a pie chart"); assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(), '80%', "should have 80% as pie value since int_field=80"); assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'), 'transform: rotate(288deg);'), "left mask should be rotated from 360*(80/100) = 288 degrees"); - assert.ok(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().hasClass('o_full'), + assert.hasClass(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last(),'o_full', "right mask should be hidden since the value > 50%"); // save - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie').length, 1, + testUtils.form.clickSave(form); + assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie', "should have a pie chart"); assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(), '80%', "should have 80% as pie value since int_field=80"); assert.ok(_.str.include(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').first().attr('style'), 'transform: rotate(288deg);'), "left mask should be rotated from 360*(80/100) = 288 degrees"); - assert.ok(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last().hasClass('o_full'), + assert.hasClass(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_mask').last(),'o_full', "right mask should be hidden since the value > 50%"); form.destroy(); @@ -5018,7 +5017,7 @@ QUnit.module('basic_fields', { // '', // }); // - // assert.strictEqual(list.$('.o_field_percent_pie .o_pie').length, 5, + // assert.containsN(list, '.o_field_percent_pie .o_pie', 5, // "should have five pie charts"); // assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_pie_value').first().text(), // '10%', "should have 10% as pie value since int_field=10"); @@ -5028,7 +5027,7 @@ QUnit.module('basic_fields', { // 'transform: rotate(36deg);', "right mask should be rotated from 360*(10/100) = 36 degrees"); // // // switch to edit mode and check the result - // list.$('tbody td:not(.o_list_record_selector)').first().click(); +// testUtils.dom.click( list.$('tbody td:not(.o_list_record_selector)').first()); // assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_pie_value').first().text(), // '10%', "should have 10% as pie value since int_field=10"); // assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').first().attr('style'), @@ -5037,7 +5036,7 @@ QUnit.module('basic_fields', { // 'transform: rotate(36deg);', "right mask should be rotated from 360*(10/100) = 36 degrees"); // // // save - // list.$buttons.find('.o_list_button_save').click(); +// testUtils.dom.click( list.$buttons.find('.o_list_button_save')); // assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_pie_value').first().text(), // '10%', "should have 10% as pie value since int_field=10"); // assert.strictEqual(list.$('.o_field_percent_pie:first .o_pie .o_mask').first().attr('style'), @@ -5097,7 +5096,7 @@ QUnit.module('basic_fields', { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // As the domain is empty, there should be a button to add the first // domain part @@ -5108,7 +5107,7 @@ QUnit.module('basic_fields', { // Clicking on the button should add the [["id", "=", "1"]] domain, so // there should be a field selector in the DOM - $domainAddFirstNodeButton.click(); + testUtils.dom.click($domainAddFirstNodeButton); var $fieldSelector = $domain.find(".o_field_selector"); assert.equal($fieldSelector.length, 1, "there should be a field selector"); @@ -5135,14 +5134,14 @@ QUnit.module('basic_fields', { // Clicking on this field should close the popover, then changing the // associated value should reveal one matched record - $colorIndex.click(); + testUtils.dom.click($colorIndex); $domain.find(".o_domain_leaf_value_input").val(2).change(); assert.equal($domain.find(".o_domain_show_selection_button").text().trim().substr(0, 2), "1 ", "changing color value to 2 should reveal only one record"); // Saving the form view should show a readonly domain containing the // "color" field - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); $domain = form.$(".o_field_domain"); assert.ok($domain.html().indexOf("Color index") >= 0, "field selector readonly value should now contain 'Color index'"); @@ -5171,7 +5170,7 @@ QUnit.module('basic_fields', { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // As the domain is equal to [["id", "=", 1]] there should be a field // selector to change this @@ -5202,7 +5201,8 @@ QUnit.module('basic_fields', { "field selector popover should contain 'Product Name' field"); // Now change the value of the "bar" field to "partner_type" - form.$("input.o_field_widget").click().val("partner_type").trigger("input"); + testUtils.dom.click(form.$("input.o_field_widget")); + testUtils.fields.editInput(form.$("input.o_field_widget"), "partner_type"); // Refocusing the field selector input should open the popover again $fieldSelector = form.$(".o_field_selector"); @@ -5256,7 +5256,7 @@ QUnit.module('basic_fields', { "the domain being empty, there should be 5 records"); // update display_name to trigger the onchange and reset foo - form.$('.o_field_widget[name=display_name]').val('new value').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value'); assert.equal(form.$('.o_domain_show_selection_button').text().trim(), '1 record(s)', "the domain has changed, there should be only 1 record"); @@ -5296,7 +5296,7 @@ QUnit.module('basic_fields', { assert.strictEqual(form.$('.o_field_widget[name=foo]:not(.o_field_empty)').length, 1, "there should be a domain field, not considered empty"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $warning = form.$('.o_field_widget[name=foo] .text-warning'); assert.strictEqual($warning.length, 0, "should not display that the domain is invalid"); @@ -5332,14 +5332,14 @@ QUnit.module('basic_fields', { "selection should contain 2 records"); // open the selection - form.$(".o_domain_show_selection_button").click(); + testUtils.dom.click(form.$(".o_domain_show_selection_button")); assert.strictEqual($('.modal .o_list_view .o_data_row').length, 2, "should have open a list view with 2 records in a dialog"); // click on a record -> should not open the record // we don't actually check that it doesn't open the record because even // if it tries to, it will crash as we don't define an arch in this test - $('.modal .o_list_view .o_data_row:first .o_data_cell').click(); + testUtils.dom.click($('.modal .o_list_view .o_data_row:first .o_data_cell')); form.destroy(); }); 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 e782a27cb4a..e6f2c06173f 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 @@ -178,7 +178,7 @@ QUnit.module('fields', {}, function () { // the SelectCreateDialog requests the session, so intercept its custom // event to specify a fake session to prevent it from crashing - testUtils.intercept(form, 'get_session', function (event) { + testUtils.mock.intercept(form, 'get_session', function (event) { event.data.callback({ user_context: {} }); }); @@ -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'); - form.$buttons.find('.o_form_button_edit').click(); + 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 - form.$('.oe_kanban_global_click:first()').click(); + testUtils.dom.click(form.$('.oe_kanban_global_click:first()')); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); + 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 - form.$('.o_field_many2many .o-kanban-button-new').click(); + 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"); - $('.modal .o_list_view tbody tr:contains(red)').click(); // select red + 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 - form.$('.o_field_many2many .o-kanban-button-new').click(); + 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"); - $('.modal .o_list_view thead .o_list_record_selector input').click(); // select all - $('.modal .o_select_button').click(); // validate selection + testUtils.dom.click($('.modal .o_list_view thead .o_list_record_selector input')); + 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 - form.$('.o_field_many2many .o-kanban-button-new').click(); - $('.modal .modal-footer .btn-primary:nth(1)').click(); // click on 'Create' + testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new')); + 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"); - $('.modal .o_form_view input').val('A new type').trigger('input'); - $('.modal:nth(1) footer .btn-primary:first()').click(); // click on 'Save & Close' + testUtils.fields.editInput($('.modal .o_form_view input'), 'A new type'); + 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,23 +246,23 @@ QUnit.module('fields', {}, function () { 'the newly created type should be in the kanban'); // delete subrecords - form.$('.o_kanban_record:contains(silver)').click(); + 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'); - $('.modal .modal-footer .o_btn_remove').click(); // Click Remove Button of Formview Dialog + 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'); - form.$('.o_kanban_record:contains(blue) .delete_icon').click(); + 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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -291,7 +291,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + 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"); @@ -335,14 +335,14 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o-kanban-button-new').length, '"Add" button should not be available in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + 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'); - form.$('.o-kanban-button-new').click(); // click on 'Add' + 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'); @@ -392,9 +392,9 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not be visible in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 records'); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'gold', 'display_name of first subrecord should be the one in DB'); @@ -404,35 +404,35 @@ QUnit.module('fields', {}, function () { '"Add an item" should be visible in edit'); // edit existing subrecord - form.$('.o_list_view tbody tr:first()').click(); + testUtils.dom.click(form.$('.o_list_view tbody tr:first()')); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); + 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 - form.$('.o_field_x2many_list_row_add a').click(); + 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"); - $('.modal .o_list_view .o_data_row').click(); // select a record + testUtils.dom.click($('.modal .o_list_view .o_data_row')); assert.strictEqual($('.modal .o_list_view').length, 0, "the modal should be closed"); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 3, + assert.containsN(form, '.o_list_view td.o_list_number', 3, 'should contain 3 subrecords'); // remove subrecords - form.$('.o_list_record_remove:nth(1)').click(); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + 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 - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + 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'); @@ -494,59 +494,59 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not be visible in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 records'); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'gold', 'display_name of first subrecord should be the one in DB'); assert.ok(form.$('.o_list_record_remove').length, 'delete icon should be visible in edit'); - assert.ok(form.$('td.o_list_record_remove button').first().hasClass('fa fa-times'), + assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-times', "should have X icons to remove (unlink) records"); assert.ok(form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not visible in edit'); // edit existing subrecord - form.$('.o_list_view tbody td:first()').click(); + 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.ok(form.$('.o_list_view tbody tr:first()').hasClass('o_selected_row'), + assert.hasClass(form.$('.o_list_view tbody tr:first()'),'o_selected_row', 'first row should be in edition'); - form.$('.o_list_view input:first()').val('new name').trigger('input'); - assert.ok(form.$('.o_list_view .o_data_row:first').hasClass('o_selected_row'), + 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'); - form.$el.click(); // click outside the list to validate the row - assert.ok(!form.$('.o_list_view tbody tr:first').hasClass('o_selected_row'), + 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', 'value of subrecord should have been updated'); assert.verifySteps(['read', 'read']); // add new subrecords - form.$('.o_field_x2many_list_row_add a').click(); + 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"); - $('.modal .o_list_view .o_data_row').click(); // select a record + testUtils.dom.click($('.modal .o_list_view .o_data_row')); assert.strictEqual($('.modal .o_list_view').length, 0, "the modal should be closed"); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 3, + assert.containsN(form, '.o_list_view td.o_list_number', 3, 'should contain 3 subrecords'); // remove subrecords - form.$('.o_list_record_remove:nth(1)').click(); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + 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 - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + 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'); @@ -583,10 +583,10 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_x2many_list_row_add').length, 1, "should have the 'Add an item' link"); - assert.strictEqual(form.$('.o_list_record_remove').length, 2, "should have the 'Add an item' link"); + 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(); @@ -604,10 +604,10 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_x2many_list_row_add').length, 0, "should not have the 'Add an item' link"); - assert.strictEqual(form.$('.o_list_record_remove').length, 0, "should not have the 'Add an item' link"); + 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"); form.destroy(); }); @@ -631,7 +631,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'); - form.$buttons.find('.o_form_button_edit').click(); + 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'); @@ -694,10 +694,10 @@ QUnit.module('fields', {}, function () { assert.ok(form.$('.custom-checkbox input').eq(2).prop('checked'), "third checkbox should be checked"); - form.$('.custom-checkbox input:checked').click(); // Uncheck default record - form.$('.custom-checkbox input').first().click(); // Check first record - form.$('.custom-checkbox input').first().click(); // Uncheck first record - form.$('.custom-checkbox input').first().click(); // Recheck first record + testUtils.dom.click(form.$('.custom-checkbox input:checked')); + testUtils.dom.click(form.$('.custom-checkbox input').first()); + testUtils.dom.click(form.$('.custom-checkbox input').first()); + testUtils.dom.click(form.$('.custom-checkbox input').first()); assert.ok(form.$('.custom-checkbox input').eq(0).prop('checked'), "first checkbox should be checked"); @@ -706,7 +706,7 @@ QUnit.module('fields', {}, function () { assert.notOk(form.$('.custom-checkbox input').eq(2).prop('checked'), "third checkbox should not be checked"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -741,10 +741,10 @@ QUnit.module('fields', {}, function () { assert.ok(form.$('.custom-checkbox input').eq(2).prop('checked'), "third checkbox should be checked"); - form.$('.custom-checkbox input:checked').click(); // Uncheck default record - form.$('.custom-checkbox input').first().click(); // Check first record - form.$('.custom-checkbox input').first().click(); // Uncheck first record - form.$('.custom-checkbox input').first().click(); // Recheck first record + testUtils.dom.click(form.$('.custom-checkbox input:checked')); + testUtils.dom.click(form.$('.custom-checkbox input').first()); + testUtils.dom.click(form.$('.custom-checkbox input').first()); + testUtils.dom.click(form.$('.custom-checkbox input').first()); assert.ok(form.$('.custom-checkbox input').eq(0).prop('checked'), "first checkbox should be checked"); @@ -753,7 +753,7 @@ QUnit.module('fields', {}, function () { assert.notOk(form.$('.custom-checkbox input').eq(2).prop('checked'), "third checkbox should not be checked"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -798,18 +798,18 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_data_row:first').click(); // add a first record to the relation + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.dom.click($('.modal .o_data_row:first')); - assert.strictEqual(form.$('.o_data_row').length, 1, + 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"); - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_data_row:first').click(); // add a second record to the relation + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.dom.click($('.modal .o_data_row:first')); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "the second record should have been added to the relation"); assert.strictEqual(form.$('.o_data_row:nth(1) .o_badge_text').text(), 'donatelloraphael', "inner m2m should have been fetched and correctly displayed"); @@ -859,7 +859,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + 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)"); @@ -897,14 +897,14 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('td.o_data_cell:first').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('td.o_data_cell:first')); - $('.modal-body input[type="checkbox"]').click(); - $('.modal .modal-footer .btn-primary').first().click(); + testUtils.dom.click($('.modal-body input[type="checkbox"]')); + testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); // there is nothing left to save -> should not do a 'write' RPC - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.verifySteps([ 'read', // read initial record (on partner) @@ -972,7 +972,7 @@ QUnit.module('fields', {}, function () { assert.verifySteps(['read']); - form.$('.o_field_widget[name=foo]').val('trigger onchange').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange'); assert.verifySteps(['read', 'onchange', 'read']); assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(), @@ -980,27 +980,27 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40, 'there should be 40 records displayed on page 1'); - form.$('.o_pager_next').click(); + testUtils.dom.click(form.$('.o_pager_next')); assert.verifySteps(['read', 'onchange', 'read', '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'); - form.$buttons.find('.o_form_button_save').click(); + 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'); - form.$('.o_pager_next').click(); + testUtils.dom.click(form.$('.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'); - form.$('.o_pager_next').click(); // back to page 1 + testUtils.dom.click(form.$('.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, @@ -1041,7 +1041,7 @@ QUnit.module('fields', {}, function () { '', }); - form.$('.o_field_widget[name=int_field]').val(2).trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); form.destroy(); }); @@ -1109,45 +1109,45 @@ QUnit.module('fields', {}, function () { }); // First round: add 51 records in batch - form.$buttons.find('.btn.btn-primary.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit')); + 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'); - $modal.find('thead input[type=checkbox]').click(); //select all the records we created in batch + 'gold' + testUtils.dom.click($modal.find('thead input[type=checkbox]')); - $modal.find('.btn.btn-primary.o_select_button').click(); + 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' - form.$buttons.find('.btn.btn-primary.o_form_button_save').click(); + testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_save')); // Secound round: remove one record - form.$buttons.find('.btn.btn-primary.o_form_button_edit').click(); + 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'); - trash_buttons.first().click(); + 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 - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); $modal = $('.modal-lg'); assert.equal($modal.length, 1, 'There should be one modal'); - $modal.find('thead input[type=checkbox]').click(); + testUtils.dom.click($modal.find('thead input[type=checkbox]')); - $modal.find('.btn.btn-primary.o_select_button').click(); + 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 72044b99d2f..855b7695415 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 @@ -189,18 +189,18 @@ QUnit.module('fields', {}, function () { }, }); - testUtils.intercept(form, 'do_action', function (event) { + testUtils.mock.intercept(form, 'do_action', function (event) { assert.strictEqual(event.data.action.res_id, 17, "should do a do_action with correct parameters"); }); assert.strictEqual(form.$('a.o_form_uri:contains(aaa)').length, 1, "should contain a link"); - form.$('a.o_form_uri').click(); // click on the link in readonly mode (should trigger do_action) + testUtils.dom.click(form.$('a.o_form_uri')); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('.o_external_button').click(); // click on the external button (should do an RPC) + 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"); @@ -237,16 +237,16 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // click on the external button (should do an RPC) - form.$('.o_external_button').click(); + testUtils.dom.click(form.$('.o_external_button')); // save and close modal - $('.modal .modal-footer .btn-primary:first').click(); + testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); // save form - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; // click next on pager - form.pager.$('.o_pager_next').click(); + testUtils.dom.click(form.pager.$('.o_pager_next')); // this checks that the view did not ask for confirmation that the // record is dirty @@ -306,19 +306,19 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // click on the external button (should do an RPC) - form.$('.o_external_button').click(); + testUtils.dom.click(form.$('.o_external_button')); - $('.modal input[name="foo"]').val('brandon').trigger('input'); + testUtils.fields.editInput($('.modal input[name="foo"]'), 'brandon'); // save and close modal - $('.modal .modal-footer .btn-primary:first').click(); + testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); // save form - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; // click next on pager - form.pager.$('.o_pager_next').click(); + testUtils.dom.click(form.pager.$('.o_pager_next')); // this checks that the view did not ask for confirmation that the // record is dirty @@ -359,13 +359,13 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('a.o_form_uri').html(), 'aaa
Street
City ZIP', "input should have a multi-line content in readonly due to show_address"); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('button.o_external_button:visible').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'button.o_external_button:visible', "should have an open record button"); - form.$('input.o_input').click(); + testUtils.dom.click(form.$('input.o_input')); - assert.strictEqual(form.$('button.o_external_button:visible').length, 1, + assert.containsOnce(form, 'button.o_external_button:visible', "should still have an open record button"); form.$('input.o_input').trigger('focusout'); assert.strictEqual($('.modal button:contains(Create and edit)').length, 0, @@ -410,7 +410,7 @@ QUnit.module('fields', {}, function () { }, }); // click the turtle field, opens a modal with the turtle form view - form.$('.o_data_row:first td.o_data_cell').click(); + 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"); @@ -454,7 +454,7 @@ QUnit.module('fields', {}, function () { }, }); // click the turtle field, opens a modal with the turtle form view - form.$('.o_data_row:first').click(); + 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"); @@ -501,18 +501,18 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').click(); - $dropdown.find('.o_m2o_dropdown_option:contains(Search)').mouseenter().click(); // Open Search More + testUtils.form.clickEdit(form); + + testUtils.fields.many2one.clickOpenDropdown('trululu'); + testUtils.fields.many2one.clickItem('trululu', 'Search'); assert.strictEqual($('tr.o_data_row').length, 9, "should display 9 records"); - $('button:contains(Filters)').click(); - $('.o_add_custom_filter:visible').click(); // Add a custom filter, datetime field is selected + testUtils.dom.click($('button:contains(Filters)')); + 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"); - $('.o_apply_filter').click(); + testUtils.dom.click($('.o_apply_filter')); assert.strictEqual($('tr.o_data_row').length, 0, "should display 0 records"); form.destroy(); @@ -552,17 +552,17 @@ QUnit.module('fields', {}, function () { }); // open the many2one in form view and change something - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_external_button').click(); - $('.modal-body input[name="other_field"]').val('wood').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_external_button')); + testUtils.fields.editInput($('.modal-body input[name="other_field"]'), 'wood'); // save the modal and make sure an onchange is triggered - $('.modal .modal-footer .btn-primary').first().click(); + 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) - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']); form.destroy(); }); @@ -584,13 +584,12 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - assert.strictEqual(form.$('span.o_field_widget[name=trululu]').length, 1, + assert.containsOnce(form, 'span.o_field_widget[name=trululu]', "should be displayed inside a span (sanity check)"); - assert.strictEqual(form.$('span.o_form_uri').length, 0, "should not have an anchor"); + assert.containsNone(form, 'span.o_form_uri', "should not have an anchor"); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_widget[name=trululu] .o_external_button').length, - 0, "should not have the button to open the record"); + 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(); }); @@ -632,14 +631,15 @@ QUnit.module('fields', {}, function () { // the SelectCreateDialog requests the session, so intercept its custom // event to specify a fake session to prevent it from crashing - testUtils.intercept(form, 'get_session', function (event) { + testUtils.mock.intercept(form, 'get_session', function (event) { event.data.callback({ user_context: {} }); }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); + var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').click(); + 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,21 +647,21 @@ QUnit.module('fields', {}, function () { assert.strictEqual($dropdown.find('li.o_m2o_dropdown_option').length, 2, 'autocomplete should contain "Search More" and Create and Edit..."'); - form.$('.o_field_many2one input').click(); + 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 - form.$('.o_field_many2one input').click(); - $dropdown.find('li:first()').click(); + testUtils.fields.many2one.clickOpenDropdown('trululu'); + 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 - form.$('.o_field_many2one input').click(); + testUtils.fields.many2one.clickOpenDropdown('trululu'); // click on 'Search More' (mouseenter required by ui-autocomplete) - $dropdown.find('.o_m2o_dropdown_option:contains(Search)').mouseenter().click(); + 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"); @@ -674,14 +674,14 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('.modal tbody tr').length, 10, "list should be restricted to records containing a P (10 records)"); // choose a record - $('.modal tbody tr:contains(Partner 20)').click(); // choose record 'Partner 20' + 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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.strictEqual(form.$('a.o_form_uri').text(), 'Partner 20', "should display correct value after save"); @@ -701,17 +701,17 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - assert.strictEqual(form.$('a.o_form_uri').length, 1, + assert.containsOnce(form, 'a.o_form_uri', "should display 1 m2o link in form"); - assert.strictEqual(form.$('a.o_form_uri').attr('href'), "#id=4&model=partner", + assert.hasAttrValue(form.$('a.o_form_uri'), 'href', "#id=4&model=partner", "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 - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); form.$('.o_field_many2one input').val('').trigger('keyup').trigger('focusout'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; - assert.strictEqual(form.$('a.o_form_uri').attr('href'), "#", + assert.hasAttrValue(form.$('a.o_form_uri'), 'href', "#", "href should have #"); form.destroy(); @@ -748,7 +748,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_field_many2one input').val(), 'aaa', "should be initially set to 'aaa'"); - form.$('.o_field_many2one input').click(); // should search with '' + 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 () { @@ -758,8 +758,8 @@ QUnit.module('fields', {}, function () { return concurrency.delay(0); }).then(function () { // close and re-open the dropdown -> should search with 'p' again - form.$('.o_field_many2one input').click(); - form.$('.o_field_many2one input').click(); + testUtils.dom.click(form.$('.o_field_many2one input')); + testUtils.dom.click(form.$('.o_field_many2one input')); assert.verifySteps(['search: ', 'search: ', 'search: p', 'search: p']); @@ -793,12 +793,12 @@ QUnit.module('fields', {}, function () { assert.ok(form.$('a:contains(and some address)').length, "should display additional result"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), "first record", "actual field value should be displayed to be edited"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.ok(form.$('a:contains(and some address)').length, "should still display additional result"); @@ -816,8 +816,8 @@ QUnit.module('fields', {}, function () { }); // edit first input, to trigger autocomplete - list.$('.o_data_row .o_data_cell').first().click(); - list.$('.o_data_cell input').val('').trigger('input'); + testUtils.dom.click(list.$('.o_data_row .o_data_cell').first()); + testUtils.fields.editInput(list.$('.o_data_cell input'), ''); // press keydown, to select first choice list.$('.o_data_cell input').focus().trigger($.Event('keydown', { @@ -829,15 +829,15 @@ QUnit.module('fields', {}, function () { // to the next line) var $dropdown = list.$('.o_field_many2one input').autocomplete('widget'); assert.ok($dropdown.is(':visible'), "dropdown should be visible"); - assert.ok(list.$('.o_data_row:eq(0)').hasClass('o_selected_row'), + assert.hasClass(list.$('.o_data_row:eq(0)'),'o_selected_row', 'first data row should still be selected'); - assert.ok(!list.$('.o_data_row:eq(1)').hasClass('o_selected_row'), + assert.doesNotHaveClass(list.$('.o_data_row:eq(1)'), 'o_selected_row', 'second data row should not be selected'); list.destroy(); }); - QUnit.test('standalone many2one field', function (assert) { + QUnit.test('standalone many2one field', async function (assert) { assert.expect(4); var done = assert.async(); @@ -867,7 +867,7 @@ QUnit.module('fields', {}, function () { }, }); var parent = new StandaloneWidget(model); - testUtils.addMockEnvironment(parent, { + testUtils.mock.addMockEnvironment(parent, { data: self.data, mockRPC: function (route, args) { assert.step(args.method); @@ -881,14 +881,12 @@ QUnit.module('fields', {}, function () { }); relField.appendTo(fixture); - $('input.o_input').val('xyzzrot').trigger('input'); + testUtils.fields.editInput($('input.o_input'), 'xyzzrot'); concurrency.delay(0).then(function () { - var $dropdown = $('input.o_input').autocomplete('widget'); - $dropdown.find('.o_m2o_dropdown_option:contains(Create)') - .first().mouseenter().click(); + testUtils.fields.many2one.clickItem('partner_id', 'Create'); - assert.strictEqual(relField.$('.o_external_button').length, 0, + assert.containsNone(relField, '.o_external_button', "should not have the button to open the record"); assert.verifySteps(['name_search', 'name_create']); @@ -923,21 +921,17 @@ QUnit.module('fields', {}, function () { // '', // res_id: 1, // }); - // form.$buttons.find('.o_form_button_edit').click(); + // testUtils.form.clickEdit(form); // assert.strictEqual(form.$('input').eq(1).val(), 'xpad', "initial product_id val should be xpad"); - // form.$('input').eq(0).val("let us trigger an onchange").trigger('input'); + // testUtils.fields.editInput(form.$('input').eq(0), "let us trigger an onchange"); // assert.strictEqual(form.$('input').eq(1).val(), 'xphone', "onchange should have been applied"); // }); - QUnit.test('form: quick create then save directly', function (assert) { - var done = assert.async(); + QUnit.test('form: quick create then save directly', async function (assert) { assert.expect(5); - var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var def = $.Deferred(); var newRecordID; var form = createView({ @@ -964,33 +958,21 @@ QUnit.module('fields', {}, function () { return result; }, }); + await testUtils.fields.many2one.searchAndClickItem('trululu', 'b'); + testUtils.form.clickSave(form);; - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').val('b').trigger('keydown'); - concurrency.delay(0).then(function () { - $dropdown.find('li:first()').click(); // quick create 'b' - form.$buttons.find('.o_form_button_save').click(); + assert.verifySteps(['name_create'], + "should wait for the name_create before creating the record"); - assert.verifySteps(['name_create'], - "should wait for the name_create before creating the record"); + def.resolve(); - def.resolve(); - - assert.verifySteps(['name_create', 'create']); - - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + assert.verifySteps(['name_create', 'create']); + form.destroy(); }); - QUnit.test('list: quick create then save directly', function (assert) { - var done = assert.async(); + QUnit.test('list: quick create then save directly', async function (assert) { assert.expect(8); - var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var def = $.Deferred(); var newRecordID; var list = createView({ @@ -1018,40 +1000,30 @@ QUnit.module('fields', {}, function () { }, }); - list.$buttons.find('.o_list_button_add').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_add')); - var $dropdown = list.$('.o_field_many2one input').autocomplete('widget'); - list.$('.o_field_many2one input').val('b').trigger('keydown'); - concurrency.delay(0).then(function () { - $dropdown.find('li:first()').click(); // quick create 'b' - list.$buttons.find('.o_list_button_add').click(); + await testUtils.fields.many2one.searchAndClickItem('trululu', {search:'b'}); + list.$buttons.find('.o_list_button_add').show(); + testUtils.dom.click(list.$buttons.find('.o_list_button_add')); - assert.verifySteps(['name_create'], - "should wait for the name_create before creating the record"); - assert.strictEqual(list.$('.o_data_row').length, 4, - "should wait for the name_create before adding the new row"); + assert.verifySteps(['name_create'], + "should wait for the name_create before creating the record"); + assert.containsN(list, '.o_data_row', 4, + "should wait for the name_create before adding the new row"); - def.resolve(); + def.resolve(); - assert.verifySteps(['name_create', 'create']); - assert.strictEqual(list.$('.o_data_row:nth(1) .o_data_cell').text(), 'b', - "created row should have the correct m2o value"); - assert.strictEqual(list.$('.o_data_row').length, 5, - "should have added the fifth row"); + assert.verifySteps(['name_create', '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"); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - list.destroy(); - done(); - }); + list.destroy(); }); - QUnit.test('list in form: quick create then save directly', function (assert) { - var done = assert.async(); + QUnit.test('list in form: quick create then save directly', async function (assert) { assert.expect(6); - var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var def = $.Deferred(); var newRecordID; var form = createView({ @@ -1085,27 +1057,19 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.many2one.searchAndClickItem('trululu', {search: 'b'}); + testUtils.form.clickSave(form);; - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').val('b').trigger('keydown'); - concurrency.delay(0).then(function () { - $dropdown.find('li:first()').click(); // quick create 'b' - form.$buttons.find('.o_form_button_save').click(); + assert.verifySteps(['name_create'], + "should wait for the name_create before creating the record"); - assert.verifySteps(['name_create'], - "should wait for the name_create before creating the record"); + def.resolve(); - def.resolve(); - - assert.verifySteps(['name_create', 'create']); - assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b', - "first row should have the correct m2o value"); - - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + assert.verifySteps(['name_create', '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) { @@ -1154,31 +1118,29 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); - - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); + 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 () { - $dropdown.find('li:first()').click(); // quick create 'b' - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.fields.many2one.clickHighlightedItem('trululu'); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "there should still be only one row"); - assert.ok(form.$('.o_data_row').hasClass('o_selected_row'), + assert.hasClass(form.$('.o_data_row'),'o_selected_row', "the row should still be in edition"); def.resolve(); assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b', "first row should have the correct m2o value"); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "there should now be 2 rows"); - assert.ok(form.$('.o_data_row:nth(1)').hasClass('o_selected_row'), + assert.hasClass(form.$('.o_data_row:nth(1)'),'o_selected_row', "the second row should be in edition"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; - assert.strictEqual(form.$('.o_data_row').length, 1, + 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"); @@ -1304,9 +1266,9 @@ QUnit.module('fields', {}, function () { assert.strictEqual(requiredElement.text(), "", "should have empty string in the required field on this record"); - requiredElement.click(); + testUtils.dom.click(requiredElement); // discard by clicking on body - $('body').click(); + testUtils.dom.click($('body')); assert.strictEqual($('tr.o_data_row').length, 1, "should still have the record in the o2m"); @@ -1398,7 +1360,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"); - form.$('button.o_pager_next').click(); + 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"); @@ -1451,7 +1413,7 @@ QUnit.module('fields', {}, function () { }); // check that there is a record in the editable list with empty string as required field - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should have a row in the editable list"); assert.strictEqual($('td.o_data_cell').first().text(), "entry", "should have the correct displayed name"); @@ -1462,12 +1424,12 @@ QUnit.module('fields', {}, function () { "should have empty string in the required field on this record"); // click on empty required field in editable list record - requiredField.click(); + testUtils.dom.click(requiredField); // click off so that the required field still stay empty - $('body').click(); + testUtils.dom.click($('body')); // record should not be dropped - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should not have dropped record in the editable list"); assert.strictEqual($('td.o_data_cell').first().text(), "entry", "should still have the correct displayed name"); @@ -1513,15 +1475,15 @@ QUnit.module('fields', {}, function () { }); // check no record in list - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "should have no row in the editable list"); // select product_id to force on_change in editable list - form.$('.o_field_widget[name="product_id"] .o_input').click(); - $('.ui-menu-item').first().click(); + testUtils.dom.click(form.$('.o_field_widget[name="product_id"] .o_input')); + testUtils.dom.click($('.ui-menu-item').first()); // check that there is a record in the editable list with empty string as required field - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should have a row in the editable list"); assert.strictEqual($('td.o_data_cell').first().text(), "entry", "should have the correct displayed name"); @@ -1532,12 +1494,12 @@ QUnit.module('fields', {}, function () { "should have empty string in the required field on this record"); // click on empty required field in editable list record - requiredField.click(); + testUtils.dom.click(requiredField); // click off so that the required field still stay empty - $('body').click(); + testUtils.dom.click($('body')); // record should not be dropped - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should not have dropped record in the editable list"); assert.strictEqual($('td.o_data_cell').first().text(), "entry", "should still have the correct displayed name"); @@ -1569,13 +1531,13 @@ QUnit.module('fields', {}, function () { }); // Click on "Add an item" - form.$('.o_field_x2many_list_row_add a').click(); + 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"); assert.strictEqual(charField.length, 1, "should have a char field 'display_name' on this record"); - assert.notOk(charField.hasClass('o_required_modifier'), + assert.doesNotHaveClass(charField, 'o_required_modifier', "the char field should not be required on this record"); assert.strictEqual(charField.val(), "some text", "should have entered text in the char field on this record"); @@ -1585,12 +1547,12 @@ QUnit.module('fields', {}, function () { "should have empty string in the required field on this record"); // click on empty required field in editable list record - requiredField.click(); + testUtils.dom.click(requiredField); // click off so that the required field still stay empty - $('body').click(); + testUtils.dom.click($('body')); // record should be dropped - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "should have dropped record in the editable list"); form.destroy(); @@ -1621,12 +1583,12 @@ QUnit.module('fields', {}, function () { '', }); - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "should initially not have any record in the list"); // Click on "Add an item" - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('.o_data_row').length, 1, + 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"); var $inputEditMode = form.$('.o_field_widget.o_required_modifier[name="trululu"] input'); @@ -1636,23 +1598,19 @@ 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 - $inputEditMode.click(); - $('li.ui-menu-item').first().click(); - $('body').click(); // leave edit mode on the line + testUtils.dom.click($inputEditMode); + testUtils.dom.click($('li.ui-menu-item').first()); + testUtils.dom.click($('body')); var $inputReadonlyMode = form.$('.o_data_cell.o_required_modifier'); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should not have dropped valid record when leaving edit mode"); assert.strictEqual($inputReadonlyMode.text(), "first record", "should have put some content in the required field on this record"); // remove the required field and leave edit mode of the record - $('.o_data_row').click(); // enter edit mode on the line - $inputEditMode.click(); - $inputEditMode.val(""); - $('body').click(); - - assert.strictEqual(form.$('.o_data_row').length, 1, + 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", "should keep previous valid required field content on this record"); @@ -1714,9 +1672,9 @@ QUnit.module('fields', {}, function () { // edit the subrecord and save displayName = 'new value'; - form.$('.o_data_cell').click(); - form.$('.o_data_cell input').val(displayName).trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('.o_data_cell')); + testUtils.fields.editInput(form.$('.o_data_cell input'), displayName); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -1769,7 +1727,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -1819,11 +1777,11 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('td.o_data_cell:first').click(); // edit first one2many line - form.$('.o_external_button').click(); // open product sub view in modal - $('button:contains("Just do it !")').click(); // click on action button - $('button:contains("Just don\'t do it !")').click(); // click on object button + 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 !")')); form.destroy(); }); @@ -1891,9 +1849,9 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }).then(function (form) { - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_data_cell').click(); - form.$('.o_external_button').click(); + 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, @@ -1903,12 +1861,12 @@ QUnit.module('fields', {}, function () { assert.equal($handles.length, 2, 'There should be 2 sequence handlers'); - testUtils.dragAndDrop($handles.eq(1), $modal.find('tbody tr').first(), + testUtils.dom.dragAndDrop($handles.eq(1), $modal.find('tbody tr').first(), { position: 'top' }); // Saving the modal and then the original model - $modal.find('.modal-footer .btn-primary').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click($modal.find('.modal-footer .btn-primary')); + testUtils.form.clickSave(form);; assert.verifySteps(['onchange sequence', 'partner_type write']); @@ -1937,9 +1895,9 @@ QUnit.module('fields', {}, function () { return this._super(route, args); } }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('input').click(); + testUtils.dom.click(form.$('input')); form.destroy(); }); @@ -1963,9 +1921,9 @@ QUnit.module('fields', {}, function () { return this._super(route, args); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('input:eq(2)').click(); + testUtils.dom.click(form.$('input:eq(2)')); form.destroy(); }); @@ -2016,15 +1974,13 @@ QUnit.module('fields', {}, function () { res_id: 1, }); assert.strictEqual(form.$('a').text(), '', 'the tag a should be empty'); - form.$buttons.find('.o_form_button_edit').click(); - - form.$('.o_field_many2one input').click(); - form.$('.o_field_many2one input').autocomplete('widget').find('a').first().click(); - + testUtils.form.clickEdit(form); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickItem('product_id','xphone'); assert.strictEqual(form.$('input').val(), "xphone", "should have selected xphone"); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickDiscard(form);; assert.strictEqual(form.$('a').text(), '', 'the tag a should be empty'); form.destroy(); }); @@ -2073,10 +2029,10 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_widget[name=product_id] input').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_widget[name=product_id] input')); - form.$('.o_field_widget[name=trululu] input').click(); + testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); form.destroy(); }); @@ -2105,7 +2061,7 @@ QUnit.module('fields', {}, function () { form.$('.o_field_many2one input').focus(); form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout'); - $('.modal .modal-footer .btn-primary').first().click(); + testUtils.dom.click($('.modal .modal-footer .btn-primary').first()); form.destroy(); }); @@ -2134,30 +2090,30 @@ QUnit.module('fields', {}, function () { // cancel the many2one creation with Cancel button form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - $('.modal .modal-footer .btn:contains(Cancel)').click(); + testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)')); 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'); - $('.modal .modal-header button').click(); + 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)'); // select a new value then cancel the creation of the new one --> restore the previous - form.$('.o_field_many2one input').click(); - form.$('.o_field_many2one input').autocomplete('widget').find('a').first().click(); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickItem('product_id','o'); assert.strictEqual(form.$('input').val(), "xphone", "should have selected xphone"); form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur'); assert.strictEqual($('.modal').length, 1, "there should be one opened modal"); - $('.modal .modal-footer .btn:contains(Cancel)').click(); + 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'); - $('.modal .modal-footer .btn-primary').click(); + testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); assert.strictEqual($('.modal .o_form_view').length, 1, 'a new modal should be opened and contain a form view'); @@ -2213,21 +2169,21 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_many2one input').click(); + 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"); - $('.ui-autocomplete li:contains(xpad)').mouseenter().click(); + 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.strictEqual(form.$('.o_field_many2one .o_external_button').length, 1, + assert.containsOnce(form, '.o_field_many2one .o_external_button', "there should be an external button displayed"); - form.$('.o_field_many2one .o_external_button').click(); + 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"); - $('.modal .o_form_button_cancel').click(); + testUtils.dom.click($('.modal .o_form_button_cancel')); form.$('.o_field_many2one input').val('new product').trigger('keyup').trigger('focusout'); @@ -2248,13 +2204,13 @@ QUnit.module('fields', {}, function () { arch: '', }); - list.$('td.o_data_cell:first').click(); - assert.strictEqual(list.$('.o_selected_row').length, 1, + 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 - list.$('td.o_data_cell input:first').val('a').trigger('input'); + 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'); @@ -2276,12 +2232,12 @@ QUnit.module('fields', {}, function () { assert.notOk(document.contains($input[0]), "input should no longer be in dom"); - assert.ok(list.$('tr.o_data_row:eq(1)').hasClass('o_selected_row'), + 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 - list.$('td.o_data_cell input:first').val('a').trigger('input'); + 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'); @@ -2302,7 +2258,7 @@ QUnit.module('fields', {}, function () { assert.notOk(document.contains($input[0]), "input should no longer be in dom"); - assert.ok(list.$('tr.o_data_row:eq(2)').hasClass('o_selected_row'), + 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; @@ -2331,7 +2287,7 @@ QUnit.module('fields', {}, function () { }); var $input = form.$('.o_field_many2one input'); - $input.val("Something that does not exist").trigger('input'); + 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', { @@ -2351,7 +2307,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('.modal').length, 1, "should have one modal in body"); // Check that discarding clears $input - $('.modal .o_form_button_cancel').click(); + testUtils.dom.click($('.modal .o_form_button_cancel')); assert.strictEqual($input.val(), '', "the field should be empty"); form.destroy(); @@ -2393,7 +2349,7 @@ QUnit.module('fields', {}, function () { }); var $input = form.$('.o_field_many2one input'); - $input.val("first").trigger('input'); + testUtils.fields.editInput($input, "first"); concurrency.delay(0).then(function () { var evOptions = { which: $.ui.keyCode.TAB, @@ -2452,8 +2408,8 @@ QUnit.module('fields', {}, function () { }, }); - list.$('td.o_data_cell:first').click(); - list.$('td.o_data_cell input:first').val('a').trigger('input'); + 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', { @@ -2508,8 +2464,8 @@ QUnit.module('fields', {}, function () { }, }); - list.$('td.o_data_cell:first').click(); - list.$('td.o_data_cell input:first').val('a').trigger('input'); + 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', { @@ -2572,13 +2528,13 @@ QUnit.module('fields', {}, function () { }); // trigger a name_search (domain should be []) - form.$('.o_field_widget[name=trululu] input').click(); + testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); // close the dropdown - form.$('.o_field_widget[name=trululu] input').click(); + testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); // trigger an onchange that will update the domain - form.$('.o_field_widget[name=int_field]').val(2).trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); // trigger a name_search (domain should be [['id', 'in', [10]]]) - form.$('.o_field_widget[name=trululu] input').click(); + testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); form.destroy(); }); @@ -2624,18 +2580,18 @@ QUnit.module('fields', {}, function () { // add a first row with a specific domain for the m2o domain = [['id', 'in', [10]]]; // domain for subrecord 1 - form.$('.o_field_x2many_list_row_add a').click(); // triggers the onchange - form.$('.o_field_widget[name=trululu] input').click(); // triggers the name_search + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + 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 - form.$('.o_field_x2many_list_row_add a').click(); // triggers the onchange - form.$('.o_field_widget[name=trululu] input').click(); // triggers the name_search + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + 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 - form.$('.o_data_row:first .o_data_cell').click(); - form.$('.o_field_widget[name=trululu] input').click(); // triggers the name_search + testUtils.dom.click(form.$('.o_data_row:first .o_data_cell')); + testUtils.dom.click(form.$('.o_field_widget[name=trululu] input')); form.destroy(); }); @@ -2673,15 +2629,15 @@ QUnit.module('fields', {}, function () { }); // Opening the modal - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_data_row td:contains(first record)').click(); - form.$('.o_external_button').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_data_row td:contains(first record)')); + testUtils.dom.click(form.$('.o_external_button')); assert.strictEqual($('.modal').length, 1, "should have one modal in body"); // Changing the 'trululu' value - $('.modal input[name="display_name"]').val('test').trigger('input'); - $('.modal button.btn-primary').click(); + testUtils.fields.editInput($('.modal input[name="display_name"]'), 'test'); + testUtils.dom.click($('.modal button.btn-primary')); // Test whether the value has changed assert.strictEqual($('.modal').length, 0, @@ -2716,12 +2672,12 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '124', "should have correct order initially"); - form.$('.o_list_view thead th:nth(1)').click(); + 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)"); - form.$('.o_list_view thead th:nth(1)').click(); + 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)"); @@ -2757,20 +2713,20 @@ QUnit.module('fields', {}, function () { } }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a record in the list - x2mList.find('.o_field_x2many_list_row_add a').click(); + 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]'); - nameInput.val('michelangelo').trigger('input'); + testUtils.fields.editInput(nameInput, 'michelangelo'); // Save the record in the modal (though it is still virtual) - modal.find('.btn-primary').first().click(); + 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'); @@ -2783,7 +2739,7 @@ QUnit.module('fields', {}, function () { 'The display name field should have the right value'); // Save the whole thing - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; x2mList = form.$('.o_field_x2many_list[name=p]'); @@ -2828,15 +2784,15 @@ QUnit.module('fields', {}, function () { var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a record in the list - x2mList.find('.o_field_x2many_list_row_add a').click(); + 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]'); - nameInput.val('michelangelo').trigger('input'); + testUtils.fields.editInput(nameInput, 'michelangelo'); // Save the record in the modal (though it is still virtual) - modal.find('.btn-primary').first().click(); + 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'); @@ -2871,13 +2827,13 @@ QUnit.module('fields', {}, function () { var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a first record in the list - x2mList.find('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a')); // Save & New - $('.modal-lg').find('.btn-primary').eq(1).click(); + testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(1)); // Save & Close - $('.modal-lg').find('.btn-primary').eq(0).click(); + 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'); @@ -2913,18 +2869,18 @@ QUnit.module('fields', {}, function () { '', res_id: 1, }); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_many2one[name="product_id"] input').click(); - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); - assert.strictEqual(form.$('th').length, 1, + 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')); + 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'); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - form.$('.o_field_boolean[name="bar"] input').click(); - assert.strictEqual(form.$('th').length, 1, + testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); + assert.containsOnce(form, 'th', "should be 1 column after the value change"); form.destroy(); }); @@ -2959,19 +2915,19 @@ QUnit.module('fields', {}, function () { }); // bar is false so there should be 1 column - assert.strictEqual(form.$('th').length, 1, + assert.containsOnce(form, 'th', "should be only 1 column ('foo') in the one2many"); - assert.strictEqual(form.$('.o_list_view .o_data_row').length, 1, "should contain one row"); + assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // add a new o2m record - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.$('.o_field_one2many input:first').focus(); - form.$('.o_field_one2many input:first').val('New line').trigger('input'); - form.$el.click(); // click outside to save a line + testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line'); + testUtils.dom.click(form.$el); - assert.strictEqual(form.$('th').length, 2, "should be 2 columns('foo' + 'int_field')"); + assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')"); form.destroy(); }); @@ -3005,18 +2961,18 @@ QUnit.module('fields', {}, function () { '', }, }); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_many2one[name="product_id"] input').click(); - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); - assert.strictEqual(form.$('th').length, 1, + 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')); + 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'); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - form.$('.o_field_boolean[name="bar"] input').click(); - assert.strictEqual(form.$('th').length, 1, + 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 7181b5267b1..af508179830 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 @@ -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.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -240,7 +240,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list .o_field_x2many_list_row_add a').click(); + 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, @@ -286,7 +286,6 @@ QUnit.module('fields', {}, function () { archs: { 'turtle,false,form': '
', }, - mockRPC: function (route, args) { if (route === '/web/dataset/call_kw/turtle/name_search') { // We are going to pass twice here @@ -295,29 +294,24 @@ QUnit.module('fields', {}, function () { assert.deepEqual(args.kwargs.args, [['id', 'in', []]]); } return this._super(route, args); - } + }, }); - form.$('.o_field_x2many_list[name=turtles] .o_field_x2many_list_row_add a').click(); + 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'); + var $modal = $('.modal-content'); - var $turtleParent = $modal.find('.o_field_many2one input'); - var $dropdown = $turtleParent.autocomplete('widget'); - - $turtleParent.click(); - - $dropdown.find('li.o_m2o_dropdown_option:contains(Create)').first().mouseenter().click(); - - $modal = $('.modal-content'); - - $modal.eq(1).find('.modal-footer .btn-primary').eq(0).click(); // Confirm new Record - $modal.eq(0).find('.modal-footer .btn-primary').eq(1).click(); // Save & New + 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)); assert.equal(form.$('.o_data_row').length, 1, 'The main record should have the new record in its o2m'); $modal = $('.modal-content'); - $modal.find('.o_field_many2one input').click(); + testUtils.dom.click($modal.find('.o_field_many2one input')); form.destroy(); }); @@ -350,16 +344,16 @@ QUnit.module('fields', {}, function () { } }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + 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 - $targetInput.val('f').trigger('input'); - $targetInput.val($targetInput.val() + 'f').trigger('input'); + testUtils.fields.editInput($targetInput, 'f'); + testUtils.fields.editInput($targetInput, $targetInput.val() + 'f'); assert.equal($targetInput[0], document.activeElement, 'The first input of the line should still have the focus'); @@ -373,10 +367,10 @@ QUnit.module('fields', {}, function () { 'The second input of the line should have the focus after the TAB press'); - $secondTarget.val(9).trigger('input'); - $secondTarget.val($secondTarget.val() + 9).trigger('input'); + testUtils.fields.editInput($secondTarget, 9); + testUtils.fields.editInput($secondTarget, $secondTarget.val() + 9); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -406,19 +400,19 @@ QUnit.module('fields', {}, function () { }); - assert.strictEqual(form.$('td.o_list_record_selector').length, 0, + assert.containsNone(form, 'td.o_list_record_selector', "embedded one2many should not have a selector"); assert.ok(!form.$('.o_field_x2many_list_row_add').length, "embedded one2many should not be editable"); assert.ok(!form.$('td.o_list_record_remove').length, "embedded one2many records should not have a remove icon"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(form.$('.o_field_x2many_list_row_add').length, "embedded one2many should now be editable"); - assert.strictEqual(form.$('.o_field_x2many_list_row_add').attr('colspan'), "2", + assert.hasAttrValue(form.$('.o_field_x2many_list_row_add'), 'colspan', "2", "should have colspan 2 (one for field foo, one for being below remove icon)"); assert.ok(form.$('td.o_list_record_remove').length, @@ -443,17 +437,17 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - assert.strictEqual(form.$('td.hey').length, 1, + assert.containsOnce(form, 'td.hey', 'should have a td with the desired class'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('td.hey').length, 1, + assert.containsOnce(form, 'td.hey', 'should have a td with the desired class'); - form.$('td.o_data_cell').click(); + testUtils.dom.click(form.$('td.o_data_cell')); - assert.strictEqual(form.$('input[name="turtle_foo"].hey').length, 1, + assert.containsOnce(form, 'input[name="turtle_foo"].hey', 'should have an input with the desired class'); form.destroy(); @@ -552,7 +546,7 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, 'should display 2 data rows'); form.destroy(); }); @@ -581,7 +575,7 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, 'should display 2 data rows'); form.destroy(); }); @@ -641,7 +635,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - assert.strictEqual(form.$('span.o_row_handle').length, 1, "should have 1 handles"); + assert.containsOnce(form, 'span.o_row_handle', "should have 1 handles"); form.destroy(); }); @@ -649,7 +643,7 @@ QUnit.module('fields', {}, function () { assert.expect(10); var nbConfirmChange = 0; - testUtils.patch(ListRenderer, { + testUtils.mock.patch(ListRenderer, { confirmChange: function () { nbConfirmChange++; return this._super.apply(this, arguments); @@ -679,21 +673,21 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.intercept(form, "field_changed", function (event) { + testUtils.mock.intercept(form, "field_changed", function (event) { assert.step(event.data.changes.turtles.data.turtle_int.toString()); }, true); assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa", "should have the 3 rows in the correct order"); - form.$buttons.find('.o_form_button_edit').click(); + 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.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -706,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"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.deepEqual(_.map(this.data.turtle.records, function (turtle) { return _.pick(turtle, 'id', 'turtle_foo', 'turtle_int'); @@ -719,7 +713,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipyopkawa", "should still have the 3 rows in the new order"); - testUtils.unpatch(ListRenderer); + testUtils.mock.unpatch(ListRenderer); form.destroy(); }); @@ -779,11 +773,11 @@ QUnit.module('fields', {}, function () { } }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_data_cell').eq(1).click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_data_cell').eq(1)); var $cell = form.$('.o_selected_row .o_input[name=turtle_foo]'); - $cell.val("hop").trigger('change'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editSelect($cell, "hop"); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -841,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"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_data_cell').eq(1).click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_data_cell').eq(1)); var $cell = form.$('.o_selected_row .o_input[name=turtle_foo]'); - $cell.val("hop").trigger("change"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editSelect($cell, "hop"); + testUtils.form.clickSave(form);; assert.deepEqual(form.$('.o_many2many_tags_cell').text().trim().split(/\s+/), ["second", "record", "aaa"], @@ -892,10 +886,10 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // Drag and drop the second line in first position - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -949,14 +943,14 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); + 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.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -966,7 +960,7 @@ QUnit.module('fields', {}, function () { "should still have the 3 rows in the correct order"); assert.strictEqual(turtleOnchange, 3, "should update all lines"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -1010,16 +1004,16 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$('.o_pager_next').click(); + testUtils.dom.click(form.$('.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"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_one2many .o_list_view tbody tr:first td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:first input:first').val('blurp').trigger('input'); + 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'); // Drag and drop the third line in second position - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(2), form.$('.o_field_one2many tbody tr').eq(1), { position: 'top' } @@ -1027,8 +1021,8 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_cell').text(), "blurpkawablip", "should display to record in 'turtle_int' order"); - form.$buttons.find('.o_form_button_save').click(); - form.$('.o_pager_next').click(); + testUtils.form.clickSave(form);; + testUtils.dom.click(form.$('.o_pager_next')); assert.strictEqual(form.$('.o_data_cell:not(.o_handle_cell)').text(), "blurpkawablip", "should display to record in 'turtle_int' order"); @@ -1095,29 +1089,29 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + 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"); - form.$('.o_field_one2many .o_list_view tbody tr:first td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:first input:first').val('blurp').trigger('input'); + 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'); // the domain fail if the widget does not use the allready loaded data. - form.$buttons.find('.o_form_button_cancel').click(); + 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"); - $('.modal .modal-footer button:first').click(); + 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"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // Drag and drop the third line in second position - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(2), form.$('.o_field_one2many tbody tr').eq(1), { position: 'top' } @@ -1127,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.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(2), form.$('.o_field_one2many tbody tr').eq(1), { position: 'top' } @@ -1136,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)"); - form.$buttons.find('.o_form_button_cancel').click(); + 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"); - $('.modal .modal-footer button:first').click(); + 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"); @@ -1189,33 +1183,33 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_pager_next').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_pager_next')); - form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first').val('value 1').trigger('input'); - form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first').val('value 2').trigger('input'); + 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'); - assert.strictEqual(form.$('.o_data_row').length, 40, "should display 40 records"); + 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"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 40, "should display 39 records and the create line"); - assert.strictEqual(form.$('.o_data_row:first .o_field_char').length, 1, "should display the create line in first position"); + 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"); - form.$('.o_data_row input:first').val('value 3').trigger('input'); + testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3'); - assert.strictEqual(form.$('.o_data_row:first .o_field_char').length, 1, "should display the create line in first position after onchange"); + 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"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 40, "should display 39 records and the create line"); - assert.strictEqual(form.$('.o_data_row:first .o_field_char').length, 1, "should display the create line in first position"); + 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:has(.o_data_cell:contains(value 3))').index(), 1, "should display the created line at the second position"); assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 2, "should display '#39' at the third line"); @@ -1264,27 +1258,27 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_pager_next').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_pager_next')); - form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first').val('value 1').trigger('input'); - form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first').val('value 2').trigger('input'); + 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'); - assert.strictEqual(form.$('.o_data_row').length, 40, "should display 40 records"); + 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"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 41, "should display 41 records and the create line"); + 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"); - form.$('.o_data_row input:first').val('value 3').trigger('input'); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3'); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 42, "should display 42 records and the create line"); + 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"); assert.strictEqual(form.$('.o_data_row:has(.o_field_char)').index(), 41, "should display the create line at the last position"); @@ -1318,13 +1312,13 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "there should be one record in the relation"); // change the value of foo to trigger the onchange - form.$('.o_field_widget[name=foo]').val('some value').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); - assert.strictEqual(form.$('.o_data_row').length, 3, + assert.containsN(form, '.o_data_row', 3, "there should be three records in the relation"); form.destroy(); @@ -1373,16 +1367,16 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "there should be one record in the relation"); assert.strictEqual(form.$('.o_data_row .o_field_widget[name=partner_ids]').text().replace(/\s/g, ''), 'secondrecordaaa', "many2many_tags should be correctly displayed"); // change the value of foo to trigger the onchange checkRPC = true; // enable flag to check read RPC for the m2m field - form.$('.o_field_widget[name=foo]').val('some value').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); - assert.strictEqual(form.$('.o_data_row').length, 3, + assert.containsN(form, '.o_data_row', 3, "there should be three records in the relation"); assert.strictEqual(form.$('.o_data_row:first .o_field_widget[name=partner_ids]').text().trim(), 'first record', "many2many_tags should be correctly displayed"); @@ -1431,16 +1425,16 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "there should be one record in the relation"); assert.strictEqual(form.$('.ref_field').text().trim(), 'xpad', "reference field should be correctly displayed"); // change the value of foo to trigger the onchange checkRPC = true; // enable flag to check read RPC for reference field - form.$('.o_field_widget[name=foo]').val('some value').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value'); - assert.strictEqual(form.$('.o_data_row').length, 3, + assert.containsN(form, '.o_data_row', 3, "there should be three records in the relation"); assert.strictEqual(form.$('.ref_field').text().trim(), 'xpadxphone', "reference fields should be correctly displayed"); @@ -1482,25 +1476,25 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "the onchange should have created one record in the relation"); // open the created o2m record in a form view, and add a m2m subrecord // in its relation - form.$('.o_data_row').click(); + 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 - $('.modal .o_field_x2many_list_row_add a').click(); + 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 - $('.modal:nth(1) .o_list_view .o_data_cell:first').click(); + testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first')); assert.strictEqual($('.modal').length, 1, "second dialog should be closed"); @@ -1510,25 +1504,25 @@ QUnit.module('fields', {}, function () { 'm2m pager should be hidden'); // click on 'Save & Close' - $('.modal-footer .btn-primary:first').click(); + 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 - form.$('.o_data_row').click(); + 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 - $('.modal .o_field_x2many_list_row_add a').click(); + testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 2, "should have opened a second dialog"); - $('.modal:nth(1) .o_list_view .o_data_cell:first').click(); + testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first')); assert.strictEqual($('.modal').length, 1, "second dialog should be closed"); @@ -1536,12 +1530,12 @@ QUnit.module('fields', {}, function () { "there should be two records in the one2many in the dialog"); // click on 'Discard' - $('.modal-footer .btn-secondary').click(); + 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 - form.$('.o_data_row').click(); + 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, @@ -1596,11 +1590,11 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.intercept(form, "field_changed", function (event) { + testUtils.mock.intercept(form, "field_changed", function (event) { assert.step(form.model.get(event.data.changes.turtles.id).res_id); }, true); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var steps = []; var positions = [ @@ -1611,7 +1605,7 @@ QUnit.module('fields', {}, function () { function dragAndDrop() { var pos = positions.shift(); - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(pos[0]), form.$('tbody tr').eq(pos[1]), { position: pos[2] } @@ -1670,19 +1664,19 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - testUtils.intercept(form, "field_changed", function (event) { + testUtils.mock.intercept(form, "field_changed", function (event) { assert.step(event.data.changes.p.data.int_field.toString()); }, true); 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"); - form.$buttons.find('.o_form_button_edit').click(); + 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.dragAndDrop( + testUtils.dom.dragAndDrop( form.$('.ui-sortable-handle').eq(1), form.$('tbody tr').first(), { position: 'top' } @@ -1694,12 +1688,12 @@ 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"); - form.$('tbody tr:first td:first').click(); + 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"); - form.$buttons.find('.o_form_button_save').click(); + 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"); @@ -1773,7 +1767,7 @@ QUnit.module('fields', {}, function () { // 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 - form.$('.o_x2m_control_panel .o_pager_next').click(); + 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'); @@ -1788,7 +1782,7 @@ QUnit.module('fields', {}, function () { // been correctly reloaded form.pager.previous(); assert.strictEqual(count, 11, 'two RPCs should have been done'); - form.$('.o_x2m_control_panel .o_pager_next').click(); + 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'); @@ -1895,10 +1889,10 @@ QUnit.module('fields', {}, function () { // add a record on page one checkRead = true; - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o-kanban-button-new').click(); - $('.modal input').val('new record').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // save and close + 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')); // checks assert.strictEqual(readIDs, undefined, "should not have read any record"); assert.strictEqual(form.$('span:contains(new record)').length, 0, @@ -1910,14 +1904,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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; // delete a record on page one checkRead = true; - form.$buttons.find('.o_form_button_edit').click(); + 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)'); - form.$('.delete_icon:first').click(); + testUtils.dom.click(form.$('.delete_icon:first')); // checks assert.deepEqual(readIDs, [50], "should have read a record (to display 40 records on page 1)"); @@ -1926,31 +1920,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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; // add and delete records in both pages - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); checkRead = true; readIDs = undefined; // add and delete a record in page 1 - form.$('.o-kanban-button-new').click(); - $('.modal input').val('new record page 1').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // save and close + 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')); 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)'); - form.$('.delete_icon:first').click(); + 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 - form.$('.o_x2m_control_panel .o_pager_next').click(); + 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; - form.$('.delete_icon:first').click(); - form.$('.o-kanban-button-new').click(); - $('.modal input').val('new record page 2').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // save and close + 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')); assert.strictEqual(readIDs, undefined, "should not have read any record"); // checks assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5, @@ -1962,7 +1956,7 @@ 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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -1991,16 +1985,16 @@ QUnit.module('fields', {}, function () { }, res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - $('input[name="turtle_int"]').val('5').trigger('input'); - $('.modal-footer button.btn-primary').first().click(); + 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()); assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '5', 'should display 5 in the foo field'); - form.$('tbody tr:eq(1) td.o_data_cell').click(); + testUtils.dom.click(form.$('tbody tr:eq(1) td.o_data_cell')); - $('input[name="turtle_int"]').val('3').trigger('input'); - $('.modal-footer button.btn-primary').first().click(); + testUtils.fields.editInput($('input[name="turtle_int"]'), '3'); + 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(); @@ -2041,13 +2035,13 @@ QUnit.module('fields', {}, function () { throw "should not render the whole form"; }; - form.$('table thead th:contains(Foo)').click(); + 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"); - form.$('table thead th:contains(Foo)').click(); + 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"); @@ -2080,33 +2074,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'"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_one2many tbody td').first().click(); - assert.ok(form.$('.o_field_one2many tbody td').first().parent().hasClass('o_selected_row'), + testUtils.form.clickEdit(form); + 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"); - form.$('.o_field_one2many tbody td').first().find('input').val("new value").trigger('input'); - assert.ok(form.$('.o_field_one2many tbody td').first().parent().hasClass('o_selected_row'), + 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 - form.$el.click(); - assert.ok(!form.$('.o_field_one2many tbody td').first().parent().hasClass('o_selected_row'), + 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 - form.$buttons.find('.o_form_button_cancel').click(); + 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"); - $('.modal .modal-footer .btn-primary').click(); + 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 - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_one2many tbody td').first().click(); - form.$('.o_field_one2many tbody td').first().find('input').val("new value").trigger('input'); - form.$el.click(); - form.$buttons.find('.o_form_button_save').click(); + 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);; // 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', @@ -2134,7 +2128,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'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in readonly'); @@ -2175,29 +2169,29 @@ QUnit.module('fields', {}, function () { '
', }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('td.o_list_record_remove button').length, 3, + assert.containsN(form, 'td.o_list_record_remove button', 3, "should have 3 remove buttons"); - assert.ok(form.$('td.o_list_record_remove button').first().hasClass('fa fa-times'), + assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-times', "should have X icons to remove (unlink) records"); - form.$('td.o_list_record_remove button').first().click(); + testUtils.dom.click(form.$('td.o_list_record_remove button').first()); - assert.strictEqual(form.$('td.o_list_record_remove button').length, 2, + assert.containsN(form, 'td.o_list_record_remove button', 2, "should have 2 remove buttons (a record is supposed to have been unlinked)"); - form.$('tr.o_data_row').first().click(); + 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'); - $('.modal .modal-footer .o_btn_remove').click(); + testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); - assert.strictEqual(form.$('td.o_list_record_remove button').length, 1, + 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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -2235,29 +2229,29 @@ QUnit.module('fields', {}, function () { '
', }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('td.o_list_record_remove button').length, 3, + assert.containsN(form, 'td.o_list_record_remove button', 3, "should have 3 remove buttons"); - assert.ok(form.$('td.o_list_record_remove button').first().hasClass('fa fa-trash-o'), + assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-trash-o', "should have trash bin icons to remove (delete) records"); - form.$('td.o_list_record_remove button').first().click(); + testUtils.dom.click(form.$('td.o_list_record_remove button').first()); - assert.strictEqual(form.$('td.o_list_record_remove button').length, 2, + assert.containsN(form, 'td.o_list_record_remove button', 2, "should have 2 remove buttons (a record is supposed to have been deleted)"); - form.$('tr.o_data_row').first().click(); + 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'); - $('.modal .modal-footer .o_btn_remove').click(); + testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); - assert.strictEqual(form.$('td.o_list_record_remove button').length, 1, + 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 - form.$buttons.find('.o_form_button_save').click(); + 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 @@ -2304,7 +2298,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_one2many .o-kanban-button-new').length, '"Create" button should not be visible in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1, 'should contain 1 record'); @@ -2316,46 +2310,46 @@ QUnit.module('fields', {}, function () { 'delete icon should be visible in edit'); assert.ok(form.$('.o_field_one2many .o-kanban-button-new').length, '"Create" button should be visible in edit'); - assert.ok(form.$('.o_field_one2many .o-kanban-button-new').hasClass('btn-secondary'), + assert.hasClass(form.$('.o_field_one2many .o-kanban-button-new'),'btn-secondary', "'Create' button should have className 'btn-secondary'"); assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').text().trim(), "Add", 'Create button should have "Add" label'); // edit existing subrecord - form.$('.oe_kanban_global_click').click(); + testUtils.dom.click(form.$('.oe_kanban_global_click')); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new name'); + 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 - form.$('.o-kanban-button-new').click(); - $('.modal .o_form_view input').val('new subrecord 1').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save and close + 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')); 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 - form.$('.o-kanban-button-new').click(); - $('.modal .o_form_view input').val('new subrecord 2').trigger('input'); - $('.modal .modal-footer .btn-primary:nth(1)').click(); // save and new - $('.modal .o_form_view input').val('new subrecord 3').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save and close + 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')); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4, 'should contain 4 records'); // delete subrecords - form.$('.oe_kanban_global_click').first().click(); + 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'); - $('.modal .modal-footer .o_btn_remove').click(); // Click Remove Button of Formview Dialog + 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'); - form.$('.o_kanban_view .delete_icon:first()').click(); - form.$('.o_kanban_view .delete_icon:first()').click(); + testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()')); + 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', @@ -2386,7 +2380,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + 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"); @@ -2423,7 +2417,7 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o-kanban-button-new').length, '"Add" button should not be available in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(!form.$('.o-kanban-button-new').length, '"Add" button should not be available in edit'); @@ -2453,9 +2447,9 @@ QUnit.module('fields', {}, function () { }); // add a record, then click in form view to confirm it - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$el.click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_cp_pager').text().trim(), '1-3 / 5', "pager should display the correct total"); @@ -2498,9 +2492,9 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" should not be visible in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 2, + assert.containsN(form, '.o_list_view td.o_list_number', 2, 'should contain 2 records'); assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'second record', 'display_name of first subrecord should be the one in DB'); @@ -2510,10 +2504,10 @@ QUnit.module('fields', {}, function () { '"Add an item" should not visible in edit'); // edit existing subrecord - form.$('.o_list_view tbody tr:first() td:eq(1)').click(); + testUtils.dom.click(form.$('.o_list_view tbody tr:first() td:eq(1)')); - $('.modal .o_form_view input').val('new name').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // save + testUtils.fields.editInput($('.modal .o_form_view input'), 'new name'); + 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"); @@ -2522,13 +2516,13 @@ QUnit.module('fields', {}, function () { // TODO when 'Add an item' will be implemented // remove subrecords - form.$('.o_list_record_remove:nth(1)').click(); - assert.strictEqual(form.$('.o_list_view td.o_list_number').length, 1, + 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"'); - form.$buttons.find('.o_form_button_save').click(); // save the record + testUtils.form.clickSave(form);; // save the record assert.strictEqual(nbWrite, 1, "should have write the changes in DB"); form.destroy(); @@ -2558,26 +2552,26 @@ QUnit.module('fields', {}, function () { assert.ok(!form.$('.o_field_x2many_list_row_add').length, '"Add an item" link should not be available in readonly'); - form.$('.o_list_view tbody td:first()').click(); + 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'); - $('.modal .o_form_button_cancel').click(); // close the dialog + testUtils.dom.click($('.modal .o_form_button_cancel')); - form.$buttons.find('.o_form_button_edit').click(); + 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 - form.$('.o_list_view tbody td:first()').click(); + 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.ok(form.$('.o_list_view tbody tr:first()').hasClass('o_selected_row'), + assert.hasClass(form.$('.o_list_view tbody tr:first()'),'o_selected_row', 'first row should be in edition'); - form.$('.o_list_view input:first()').val('new name').trigger('input'); + testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name'); - form.$('.o_list_view tbody tr:nth(1) td:first').click(); // click on second record to validate the first one - assert.ok(!form.$('.o_list_view tbody tr:first').hasClass('o_selected_row'), + 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', 'value of subrecord should have been updated'); @@ -2614,22 +2608,22 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item and enter a value - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_selected_row > td input').val('kartoffel').trigger('input'); + 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'); // click again on Add an item - form.$('.o_field_x2many_list_row_add a').click(); + 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.strictEqual(form.$('.o_selected_row > td input').length, 1, + assert.containsOnce(form, '.o_selected_row > td input', "should have one other new td"); - assert.strictEqual(form.$('tr.o_data_row').length, 2, "should have 2 data rows"); + assert.containsN(form, 'tr.o_data_row', 2, "should have 2 data rows"); // enter another value and save - form.$('.o_selected_row > td input').val('gemuse').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 2, "should have 2 data rows"); + testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'gemuse'); + 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"); assert.strictEqual(form.$('td:contains(gemuse)').length, 1, @@ -2658,18 +2652,18 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item 2 times - assert.strictEqual(form.$('tr.o_data_row').length, 1, + assert.containsOnce(form, 'tr.o_data_row', "should have 1 data rows"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 3, + 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')); + assert.containsN(form, 'tr.o_data_row', 3, "should have 3 data rows"); // cancel the edition - form.$buttons.find('.o_form_button_cancel').click(); - $('.modal-footer button.btn-primary').first().click(); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + testUtils.form.clickDiscard(form);; + testUtils.dom.click($('.modal-footer button.btn-primary').first()); + assert.containsOnce(form, 'tr.o_data_row', "should have 1 data rows"); form.destroy(); @@ -2706,18 +2700,16 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item - assert.strictEqual(form.$('tr.o_data_row').length, 0, + assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + 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 - var $dropdown = form.$('.o_field_many2one[name=turtle_trululu] input') - .autocomplete('widget'); - form.$('.o_field_many2one[name=turtle_trululu] input').click(); - $dropdown.find('a:contains(first record)').mouseenter().click(); + testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); + 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(); @@ -2752,18 +2744,18 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item, then click elsewhere - assert.strictEqual(form.$('tr.o_data_row').length, 0, + assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('label.o_form_label').first().click(); - assert.strictEqual(form.$('tr.o_data_row').length, 0, + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + 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 - form.$('.o_field_x2many_list_row_add a').click(); - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 0, + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.form.clickSave(form);; + assert.containsNone(form, 'tr.o_data_row', "should still have 0 data rows"); assert.verifySteps(['read', 'default_get', 'default_get']); @@ -2789,8 +2781,8 @@ QUnit.module('fields', {}, function () { }); // add a record, to reach the page size limit - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // the record currently being added should not count in the pager assert.ok(!form.$('.o_cp_pager').is(':visible'), @@ -2819,12 +2811,12 @@ QUnit.module('fields', {}, function () { }); // add a record, then discard - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.form.clickDiscard(form);; // confirm the discard operation - $('.modal .modal-footer .btn-primary').click(); // click on confirm + testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.strictEqual(form.$('.o_cp_pager').text().trim(), '1-3 / 4', "pager should still be visible"); @@ -2853,12 +2845,12 @@ QUnit.module('fields', {}, function () { }); // add a (empty) record - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + 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 - form.$('.o_pager_next').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + testUtils.dom.click(form.$('.o_pager_next')); + assert.containsOnce(form, 'tr.o_data_row', "should have 1 data rows"); form.destroy(); @@ -2887,23 +2879,23 @@ QUnit.module('fields', {}, function () { }); // add a record with a dirty state, but not valid - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('input[name="turtle_int"]').val(4321).trigger('input'); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + 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 - form.$('.o_pager_next').click(); + testUtils.dom.click(form.$('.o_pager_next')); assert.strictEqual(form.$('.o_cp_pager').text().trim(), '1-3 / 4', "pager should still display the correct total"); // click on cancel - $('.modal .modal-footer .btn-secondary').click(); // click on cancel + testUtils.dom.click($('.modal .modal-footer .btn-secondary')); assert.strictEqual(form.$('.o_cp_pager').text().trim(), '1-3 / 4', "pager should again display the correct total"); - assert.strictEqual(form.$('.o_field_one2many input.o_field_invalid').length, 1, + assert.containsOnce(form, '.o_field_one2many input.o_field_invalid', "there should be an invalid input in the one2many"); form.destroy(); }); @@ -2928,20 +2920,20 @@ QUnit.module('fields', {}, function () { }); // add a 4 records record (to make the pager appear) - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_x2many_list_row_add a').click(); + 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')); // go on next page - form.$('.o_pager_next').click(); + testUtils.dom.click(form.$('.o_pager_next')); // discard - form.$buttons.find('.o_form_button_cancel').click(); - $('.modal .modal-footer .btn-primary').click(); + testUtils.form.clickDiscard(form);; + testUtils.dom.click($('.modal .modal-footer .btn-primary')); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + assert.containsOnce(form, 'tr.o_data_row', "should have 1 data row"); assert.ok(!form.$('.o_cp_pager').is(':visible'), "pager should not be visible"); @@ -2973,31 +2965,31 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item, then click elsewhere - assert.strictEqual(form.$('tr.o_data_row').length, 0, + assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + testUtils.form.clickEdit(form); + 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 - form.$('input[name="turtle_int"]').val('12345').trigger('input'); + testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '12345'); // click elsewhere, - form.$('label.o_form_label').click(); + 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 - $('.modal .modal-footer button.btn-secondary').click(); - assert.strictEqual(form.$('tr.o_data_row.o_selected_row').length, 1, + 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) - form.$('label.o_form_label').click(); - $('.modal .modal-footer button.btn-primary').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 0, + testUtils.dom.click(form.$('label.o_form_label')); + 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(); @@ -3029,13 +3021,13 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item, then click elsewhere - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + 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, })); - assert.ok(form.$('input[name="turtle_foo"]').hasClass('o_field_invalid'), + assert.hasClass(form.$('input[name="turtle_foo"]'),'o_field_invalid', "input should be marked invalid"); assert.verifySteps(['read', 'default_get']); form.destroy(); @@ -3076,18 +3068,18 @@ QUnit.module('fields', {}, function () { }); // edit mode, then click on Add an item - assert.strictEqual(form.$('tr.o_data_row').length, 0, + assert.containsNone(form, 'tr.o_data_row', "should have 0 data rows"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // input some text in required turtle_foo field - form.$('input[name="turtle_foo"]').val('aubergine').trigger('input'); + 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 - form.$buttons.find('.o_form_button_save').click(); + 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, @@ -3118,13 +3110,13 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + testUtils.form.clickEdit(form); + 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 }); - assert.strictEqual(form.$('tr.o_data_row').length, 0, + assert.containsNone(form, 'tr.o_data_row', "data row should have been discarded"); assert.verifySteps(['read', 'default_get']); form.destroy(); @@ -3153,13 +3145,13 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 1, + testUtils.form.clickEdit(form); + 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 }); - assert.strictEqual(form.$('tr.o_data_row').length, 0, + assert.containsNone(form, 'tr.o_data_row', "data row should have been discarded"); assert.verifySteps(['read', 'default_get']); form.destroy(); @@ -3196,8 +3188,8 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + 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"); @@ -3243,10 +3235,10 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_data_cell:first').click(); + 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'); - form.$('.o_list_record_remove').click(); + testUtils.dom.click(form.$('.o_list_record_remove')); assert.verifySteps(['read', 'read', 'onchange'], 'onchange should have been done'); form.destroy(); @@ -3289,10 +3281,10 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_one2many tbody td').first().click(); - form.$('.o_field_one2many tbody td').first().find('input').val("new value").trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + 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);; assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'from onchange', "display name of first record in o2m list should be 'new value'"); @@ -3388,10 +3380,10 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('td:contains(9)').click(); - form.$('td input[name="turtle_int"]').val("3").trigger('input'); + testUtils.dom.click(form.$('td:contains(9)')); + 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 @@ -3428,17 +3420,17 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('td:contains(01/25/2017)').click(); - form.$('.o_datepicker_input').click(); - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection - $('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection - $('.bootstrap-datetimepicker-widget .year:contains(2017)').click(); - $('.bootstrap-datetimepicker-widget .month').eq(1).click(); // February - $('.day:contains(22)').click(); // select the 22 February + 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)')); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.verifySteps(['read', 'read', 'onchange', 'write', 'read', 'read']); form.destroy(); @@ -3482,34 +3474,34 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "o2m should contain one row"); // empty o2m by triggering the onchange - form.$('.o_field_widget[name=foo]').val('trigger onchange').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange'); - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "rows of the o2m should have been deleted"); // add two new subrecords - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_widget[name=display_name]').val('x').trigger('input'); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_widget[name=display_name]').val('y').trigger('input'); + 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'); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "o2m should contain two rows"); // empty o2m by triggering the onchange - form.$('.o_field_widget[name=foo]').val('trigger onchange again').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange again'); - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "rows of the o2m should have been deleted"); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_widget[name=display_name]').val('z').trigger('input'); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'z'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -3568,13 +3560,13 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "o2m should contain one row"); - form.$('.o_field_one2many .o_list_view tbody tr:first td:first').click(); - form.$('.o_field_one2many .o_list_view tbody tr:first input:first').val('blurp').trigger('input'); + 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'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -3582,7 +3574,7 @@ QUnit.module('fields', {}, function () { assert.expect(5); var delta = 0; - testUtils.patch(AbstractField, { + testUtils.mock.patch(AbstractField, { init: function () { delta++; this._super.apply(this, arguments); @@ -3649,43 +3641,43 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "o2m shouldn't contain any row"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // trigger the first onchange deactiveOnchange = false; - form.$('input[name="turtle_int"]').val('10').trigger('input'); + testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '10'); // put the list back in non edit mode - form.$('input[name="foo"]').click(); + 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 - form.$('.o_field_x2many_list tbody tr:first td:first').click(); - form.$('input[name="turtle_int"]').val('20').trigger('input'); + testUtils.dom.click(form.$('.o_field_x2many_list tbody tr:first td:first')); + testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '20'); - form.$('input[name="foo"]').click(); + testUtils.dom.click(form.$('input[name="foo"]')); assert.strictEqual(form.$('.o_data_row').text(), "first20second-20", "should correctly refresh the records"); - assert.strictEqual(form.$('.o_field_widget').length, delta, + assert.containsN(form, '.o_field_widget', delta, "all (non visible) field widgets should have been destroyed"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.strictEqual(form.$('.o_data_row').text(), "first20second-20", "should correctly refresh the records after save"); form.destroy(); - testUtils.unpatch(AbstractField); + testUtils.mock.unpatch(AbstractField); }); QUnit.test('editable one2many with sub widgets are rendered in readonly', function (assert) { assert.expect(2); var editableWidgets = 0; - testUtils.patch(AbstractField, { + testUtils.mock.patch(AbstractField, { init: function () { this._super.apply(this, arguments); if (this.mode === 'edit') { @@ -3714,13 +3706,13 @@ QUnit.module('fields', {}, function () { assert.strictEqual(editableWidgets, 1, "o2m is only widget in edit mode"); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.strictEqual(editableWidgets, 3, "3 widgets currently in edit mode"); form.destroy(); - testUtils.unpatch(AbstractField); + testUtils.mock.unpatch(AbstractField); }); QUnit.test('one2many editable list with onchange keeps the order', function (assert) { @@ -3751,9 +3743,9 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_cell').text(), 'first recordsecond recordaaa', "records should be display in the correct order"); - form.$('.o_data_row:first .o_data_cell').click(); - form.$('.o_selected_row .o_field_widget[name=display_name]').val('new').trigger('input'); - form.$el.click(); // click outside to validate the row + 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); assert.strictEqual(form.$('.o_data_cell').text(), 'newsecond recordaaa', "records should be display in the correct order"); @@ -3783,18 +3775,18 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.ok(form.$('.o_list_view tbody tr:eq(0) td:first').hasClass('o_readonly_modifier'), + assert.hasClass(form.$('.o_list_view tbody tr:eq(0) td:first'),'o_readonly_modifier', "first record should have display_name in readonly mode"); - assert.notOk(form.$('.o_list_view tbody tr:eq(1) td:first').hasClass('o_readonly_modifier'), + assert.doesNotHaveClass(form.$('.o_list_view tbody tr:eq(1) td:first'), 'o_readonly_modifier', "second record should not have display_name in readonly mode"); form.destroy(); }); QUnit.test('pager of one2many field in new record', function (assert) { - assert.expect(2); + assert.expect(3); this.data.partner.records[0].p = []; @@ -3805,23 +3797,18 @@ QUnit.module('fields', {}, function () { arch: '
' + '' + '' + - '' + + '' + '' + '' + '
', - archs: { - 'partner,false,form': - '
', - }, }); assert.ok(!form.$('.o_x2m_control_panel .o_cp_pager div').is(':visible'), 'o2m pager should be hidden'); // click to create a subrecord - form.$('tbody td.o_field_x2many_list_row_add a').click(); - $('.modal input').val('new record').trigger('input'); - $('.modal .modal-footer button:eq(0)').click(); // save and close + 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'), 'o2m pager should be hidden'); @@ -3864,7 +3851,7 @@ QUnit.module('fields', {}, function () { "should trigger onchange with correct parameters"); } return this._super.apply(this, arguments); - } + }, }); assert.strictEqual(form.$('tbody td:contains(xphone)').length, 1, @@ -3872,18 +3859,14 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('tbody td:contains(xpad)').length, 0, "should not display 'xpad' anywhere"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); - $('.modal .o_field_many2one input').click(); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickItem('product_id', 'xpad'); - var $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); - - $dropdown.find('li:eq(1) a').mouseenter(); - $dropdown.find('li:eq(1) a').click(); - - $('.modal .modal-footer button:eq(0)').click(); // save and close + testUtils.dom.click($('.modal .modal-footer button:eq(0)')); assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1, "should display 'xpad' on a td"); @@ -3930,56 +3913,52 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); // write in the many2one field, value = 37 (xphone) - $('.modal .o_field_many2one input').click(); - var $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); - $dropdown.find('li:eq(0) a').mouseenter(); - $dropdown.find('li:eq(0) a').click(); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickHighlightedItem('product_id'); // write in the integer field - $('.modal .modal-body input.o_field_widget').val('123').trigger('input'); + testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '123'); // save and close - $('.modal .modal-footer button:eq(0)').click(); + 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 - form.$('tbody td:contains(xphone)').click(); + testUtils.dom.click(form.$('tbody td:contains(xphone)')); assert.strictEqual($('.modal .modal-body input').val(), "xphone", "should display 'xphone' in an input"); - $('.modal .modal-body input.o_field_widget').val('456').trigger('input'); + testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '456'); // discard - $('.modal .modal-footer span:contains(Discard)').click(); + testUtils.dom.click($('.modal .modal-footer span:contains(Discard)')); // reopen the record in form view - form.$('tbody td:contains(xphone)').click(); + 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) - $('.modal .o_field_many2one input').click(); - $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); - $dropdown.find('li:eq(1) a').mouseenter(); - $dropdown.find('li:eq(1) a').click(); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickItem('product_id', 'xpad'); // save and close - $('.modal .modal-footer button:eq(0)').click(); + 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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -4018,12 +3997,12 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // open a modal - form.$('tr.o_data_row:eq(0) td:contains(xphone)').click(); + testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)')); // write in the many2one field - $('.modal .o_field_many2one input').click(); + testUtils.dom.click($('.modal .o_field_many2one input')); form.destroy(); }); @@ -4057,8 +4036,8 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_widget[name=product_id] input').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_widget[name=product_id] input')); form.destroy(); }); @@ -4091,12 +4070,12 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('tr.o_data_row:eq(0) td:contains(xphone)').click(); + testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)')); // trigger a name search - form.$('table td input').click(); + testUtils.dom.click(form.$('table td input')); form.destroy(); }); @@ -4131,8 +4110,8 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.destroy(); }); @@ -4169,10 +4148,10 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('input[name="turtle_foo"]').val('hammer').trigger('input'); - form.$('.o_field_x2many_list_row_add a').click(); + 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')); form.destroy(); }); @@ -4194,20 +4173,20 @@ QUnit.module('fields', {}, function () { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('td input.o_field_widget').length, 1, + assert.containsOnce(form, 'td input.o_field_widget', "should have created a row in edit mode"); - form.$('td input.o_field_widget').val('a').trigger('input'); + testUtils.fields.editInput(form.$('td input.o_field_widget'), 'a'); - assert.strictEqual(form.$('td input.o_field_widget').length, 1, + assert.containsOnce(form, 'td input.o_field_widget', "should not have unselected the row after edition"); - form.$('td input.o_field_widget').val('abc').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('td input.o_field_widget'), 'abc'); + testUtils.form.clickSave(form);; assert.strictEqual(form.$('td:contains(abc)').length, 1, "should have a row with the correct value"); @@ -4240,8 +4219,8 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); form.destroy(); }); @@ -4288,39 +4267,37 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + 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)"); - $('.modal .o_data_row:first .o_list_record_selector input').click(); - $('.modal .o_select_button').click(); - $('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + 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')); assert.strictEqual($('.modal .o_data_row').length, 1, "sould have 1 record in the select view"); - $('.modal-footer button:eq(1)').click(); - $('.modal input.o_field_widget[name="turtle_foo"]').val('tototo').trigger('input'); - $('.modal input.o_field_widget[name="turtle_int"]').val(50).trigger('input'); - var $many2one = $('.modal [name="product_id"] input').click(); - var $dropdown = $many2one.autocomplete('widget'); - $dropdown.find('li:first a').mouseenter(); - $dropdown.find('li:first a').click(); + 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'); - $('.modal-footer button:contains(&):first').click(); + testUtils.dom.click($('.modal-footer button:contains(&):first')); assert.strictEqual($('.modal').length, 0, "sould close the modals"); - assert.strictEqual(form.$('.o_data_row').length, 3, + assert.containsN(form, '.o_data_row', 3, "sould have 3 records in one2many list"); assert.strictEqual(form.$('.o_data_row').text(), "blip1.59yop1.50tototo1.550xphone", "should display the record values in one2many list"); - $('.o_form_button_save').click(); + testUtils.dom.click($('.o_form_button_save')); form.destroy(); }); @@ -4370,37 +4347,33 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_data_row:first').click(); + 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"); - $('.modal .o_form_button_cancel').click(); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.dom.click($('.modal .o_form_button_cancel')); + testUtils.form.clickEdit(form); // edit the first one2many record - form.$('.o_data_row:first').click(); - var $many2one = $('.modal [name="product_id"] input').click(); - var $dropdown = $many2one.autocomplete('widget'); - $dropdown.find('li:first a').mouseenter(); - $dropdown.find('li:first a').click(); - $('.modal-footer button:first').click(); + 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')); - $('.o_form_button_save').click(); // don't save anything because the one2many does not change + testUtils.dom.click($('.o_form_button_save')); // add a one2many record - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_data_row:first .o_list_record_selector input').click(); - $('.modal .o_select_button').click(); + 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')); // edit the second one2many record - form.$('.o_data_row:eq(1)').click(); - $many2one = $('.modal [name="product_id"] input').click(); - $dropdown = $many2one.autocomplete('widget'); - $dropdown.find('li:first a').mouseenter(); - $dropdown.find('li:first a').click(); - $('.modal-footer button:first').click(); + 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')); - $('.o_form_button_save').click(); + testUtils.dom.click($('.o_form_button_save')); form.destroy(); }); @@ -4436,8 +4409,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); form.destroy(); }); @@ -4468,8 +4440,8 @@ QUnit.module('fields', {}, function () { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); form.destroy(); }); @@ -4499,9 +4471,7 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - - form.$buttons.find('.o_form_button_edit').click(); - form.$('tbody td.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.verifySteps(['default_get', 'onchange', 'default_get', 'onchange']); form.destroy(); }); @@ -4559,9 +4529,9 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - form.$('td.o_field_x2many_list_row_add a').click(); - form.$('td input[name="turtle_foo"]').val('cat').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + 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);; form.destroy(); }); @@ -4588,9 +4558,9 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('tbody td.o_field_x2many_list_row_add a').click(); - $('.modal-footer button.btn-primary').first().click(); + 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()); assert.strictEqual($('.modal').length, 1, "should still have an open modal"); assert.strictEqual($('.modal tbody label.o_field_invalid').length, 1, @@ -4631,7 +4601,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_list_button button').click(); + testUtils.dom.click(form.$('.o_list_button button')); form.destroy(); }); @@ -4675,7 +4645,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.oe_kanban_action_button').click(); + testUtils.dom.click(form.$('.oe_kanban_action_button')); form.destroy(); }); @@ -4720,7 +4690,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$('.oe_kanban_action:eq(0)').click(); + testUtils.dom.click(form.$('.oe_kanban_action:eq(0)')); assert.strictEqual($('.o_domain_selector').length, 1, "should add domain selector widget"); form.destroy(); }); @@ -4788,17 +4758,17 @@ QUnit.module('fields', {}, function () { } }); - form.$('.o_field_one2many .o_field_x2many_list_row_add a').click(); + 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"); - $('.modal-body input[name="model_name"]').val('partner').trigger('input'); - $('.modal-footer button:first').click(); + testUtils.fields.editInput($('.modal-body input[name="model_name"]'), 'partner'); + 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"); - form.$('.o_field_one2many .o_list_view tbody tr:eq(0) td:first').click(); + testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(0) td:first')); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.strictEqual(nbFetchSpecialDomain, 1, "should only fetch special domain once"); form.destroy(); @@ -4826,10 +4796,10 @@ QUnit.module('fields', {}, function () { } }); - assert.strictEqual(form.$('.o_field_widget[name="turtles"] .o_list_view').length, 1, + assert.containsOnce(form, '.o_field_widget[name="turtles"] .o_list_view', 'should display one2many list view in the modal'); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, 'should display the 2 turtles'); form.destroy(); @@ -4879,7 +4849,7 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, 'should display the 2 turtles'); assert.strictEqual(form.$('.o_data_row:first td:nth(1)').text(), 'xphone', "should correctly display the m2o"); @@ -4888,36 +4858,34 @@ 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"); - form.$('.o_data_row:first').click(); + 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'); - $('.modal-footer button').click(); // close the modal + testUtils.dom.click($('.modal-footer button')); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // edit the m2m of first row - form.$('.o_list_view tbody td:first()').click(); + testUtils.dom.click(form.$('.o_list_view tbody td:first()')); // remove a tag - form.$('.o_field_many2manytags .badge:contains(aaa) .o_delete').click(); + 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 - var $m2mInput = form.$('.o_selected_row .o_field_many2manytags input'); - $m2mInput.click(); - $m2mInput.autocomplete('widget').find('li:first()').click(); + testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + 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 - var $m2oInput = form.$('.o_selected_row .o_field_many2one:first input'); - $m2oInput.click(); - $m2oInput.autocomplete('widget').find('li:contains(xpad)').mouseover().click(); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + 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) - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -4948,12 +4916,12 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, 'there should be only 2 rows displayed'); - form.$('.o_list_record_remove').click(); - form.$('.o_list_record_remove').click(); + testUtils.dom.clickFirst(form.$('.o_list_record_remove')); + testUtils.dom.clickFirst(form.$('.o_list_record_remove')); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', 'there should be just one remaining row'); assert.verifySteps([ @@ -5035,20 +5003,20 @@ QUnit.module('fields', {}, function () { }); // add new line (first, xpad) - form.$('.o_field_x2many_list_row_add a').click(); - form.$('input[name="display_name"]').val('first').trigger('input'); - form.$('div[name="product_id"] input').click(); + 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')); // the onchange won't be generated - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); + testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter')); - assert.strictEqual(form.$('.o_field_many2manytags.o_input').length, 1, + assert.containsOnce(form, '.o_field_many2manytags.o_input', 'should display the line in editable mode'); assert.strictEqual(form.$('.o_field_many2one input').val(), "xpad", 'should display the product xpad'); assert.strictEqual(form.$('.o_field_many2manytags.o_input .o_badge_text').text(), "first record", 'should display the tag from the onchange'); - form.$('input.o_field_integer[name="int_field"]').click(); + 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'); @@ -5056,7 +5024,7 @@ QUnit.module('fields', {}, function () { 'should display the tag in readonly'); // enable the many2many onchange and generate it - form.$('input.o_field_integer[name="int_field"]').val('10').trigger('input'); + 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'); @@ -5064,23 +5032,23 @@ QUnit.module('fields', {}, function () { 'should display the name, one2many and many2many value'); // disable the many2many onchange - form.$('input.o_field_integer[name="int_field"]').val('0').trigger('input'); + testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '0'); // remove and start over - form.$('.o_list_record_remove:first button').click(); - form.$('.o_list_record_remove:first button').click(); + testUtils.dom.click(form.$('.o_list_record_remove:first button')); + testUtils.dom.click(form.$('.o_list_record_remove:first button')); // enable the many2many onchange - form.$('input.o_field_integer[name="int_field"]').val('10').trigger('input'); + testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10'); // add new line (first, xenomorphe) - form.$('.o_field_x2many_list_row_add a').click(); - form.$('input[name="display_name"]').val('first').trigger('input'); - form.$('div[name="product_id"] input').click(); + 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')); // generate the onchange - $('li.ui-menu-item a:contains(xenomorphe)').trigger('mouseenter').click(); + testUtils.dom.click($('li.ui-menu-item a:contains(xenomorphe)').trigger('mouseenter')); - assert.strictEqual(form.$('.o_field_many2manytags.o_input').length, 1, + assert.containsOnce(form, '.o_field_many2manytags.o_input', 'should display the line in editable mode'); assert.strictEqual(form.$('.o_field_many2one input').val(), "xenomorphe", 'should display the product xenomorphe'); @@ -5088,19 +5056,19 @@ QUnit.module('fields', {}, function () { 'should display the tag from the onchange'); // put list in readonly mode - form.$('input.o_field_integer[name="int_field"]').click(); + 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)'); - form.$('input.o_field_integer[name="int_field"]').val('10').trigger('input'); + 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'); - form.$buttons.find('.o_form_button_save').click(); + 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'); @@ -5141,10 +5109,10 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, 'should display the 2 turtles'); - form.$('.o_data_row:first').click(); + 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'); @@ -5176,7 +5144,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_data_row:first').click(); + 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'); @@ -5225,18 +5193,17 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_data_row:first').click(); // edit first record + testUtils.dom.click(form.$('.o_data_row:first')); // edit first record - var $input = $('.modal .o_field_many2manytags input'); - $input.click(); // opens the dropdown - $input.autocomplete('widget').find('li').click(); // add 'first record' + testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + testUtils.fields.many2one.clickHighlightedItem('partner_ids'); // add a many2many tag and save - $('.modal .o_field_x2many_list_row_add a').click(); - $('.modal .o_field_widget[name=name]').val('test').trigger('input'); - $('.modal .modal-footer .btn-primary').click(); // 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 - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -5283,20 +5250,20 @@ QUnit.module('fields', {}, function () { }); // edit the first partner in the one2many partner form view - form.$('.o_data_row:first td.o_data_cell').click(); + testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell')); // open form view for many2one - form.$('.o_external_button').click(); + testUtils.dom.click(form.$('.o_external_button')); // click on add, to add a new partner in the m2m - $('.modal .o_field_x2many_list_row_add a').click(); + testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); // select the partner_type 'gold' (this closes the 2nd modal) - $('.modal td:contains(gold)').click(); + testUtils.dom.click($('.modal td:contains(gold)')); // confirm the changes in the modal - $('.modal .modal-footer .btn-primary').click(); + testUtils.dom.click($('.modal .modal-footer .btn-primary')); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -5327,9 +5294,9 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_list_view .o_data_row').length, 2, + assert.containsN(form, '.o_list_view .o_data_row', 2, "one2many list should contain 2 rows"); - assert.strictEqual(form.$('.o_list_view .o_field_many2manytags[name="partner_ids"] .badge').length, 2, + assert.containsN(form, '.o_list_view .o_field_many2manytags[name="partner_ids"] .badge', 2, "m2mtags should contain two tags"); assert.strictEqual(form.$('.o_list_view .o_field_many2manytags[name="partner_ids"] .o_badge_text').text(), 'aaafirst record', "tag names should have been correctly loaded"); @@ -5361,7 +5328,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_data_row:first').click(); + 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'); @@ -5410,21 +5377,21 @@ QUnit.module('fields', {}, function () { res_id: 4, }); - assert.strictEqual(form.$('.o_field_widget .o_kanban_view').length, 1, + 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, 0, "should not have kanban records yet"); // // switch to edit mode and create a new kanban record - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_widget .o-kanban-button-new').click(); + testUtils.form.clickEdit(form); + 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"); - $('.modal-content .btn-primary').first().click(); + testUtils.dom.click($('.modal-content .btn-primary').first()); - assert.strictEqual(form.$('.o_field_widget .o_kanban_view').length, 1, + 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, "should now have one kanban record"); @@ -5434,8 +5401,8 @@ 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 - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('.o_field_widget .o_kanban_view').length, 1, + 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, "should now have one kanban record"); @@ -5467,9 +5434,9 @@ QUnit.module('fields', {}, function () { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('.o_data_row:first td:first').click(); + 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"); @@ -5508,21 +5475,21 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should start with one data row"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "should have 2 data rows"); assert.strictEqual(form.$('tr.o_data_row:first input').val(), 'default foo turtle', "first row should be the new value"); - assert.ok(form.$('tr.o_data_row:first').hasClass('o_selected_row'), + assert.hasClass(form.$('tr.o_data_row:first'),'o_selected_row', "first row should be selected"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -5555,21 +5522,21 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should start with one data row"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "should have 2 data rows"); assert.strictEqual(form.$('tr.o_data_row:eq(1) input').val(), 'default foo turtle', "second row should be the new value"); - assert.ok(form.$('tr.o_data_row:eq(1)').hasClass('o_selected_row'), + assert.hasClass(form.$('tr.o_data_row:eq(1)'),'o_selected_row', "second row should be selected"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -5601,7 +5568,7 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - assert.strictEqual(form.$('.o_field_one2many .o_kanban_view').length, 1, + assert.containsOnce(form, '.o_field_one2many .o_kanban_view', "should have rendered a kanban view"); form.destroy(); @@ -5638,17 +5605,17 @@ QUnit.module('fields', {}, function () { }, res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0", "int_field should start with value 0"); - form.$('.o_field_x2many_list_row_add a').click(); + 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"); - form.$('.o_field_widget[name="turtle_foo"]').val("some text").trigger('input'); + 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 now be 1 (the onchange should have been done"); @@ -5699,27 +5666,26 @@ QUnit.module('fields', {}, function () { }, res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + 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) - form.$('.o_field_x2many_list_row_add a').click(); + 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 - form.$('.o_field_widget[name="turtle_foo"]').val("some text").trigger('input'); + 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"); // fill partner_ids field with a tag (all required fields will then be set) - var $m2mInput = form.$('.o_field_widget[name=partner_ids] input'); - $m2mInput.click(); - $m2mInput.autocomplete('widget').find('li:first()').click(); + testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + 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"); @@ -5751,18 +5717,18 @@ QUnit.module('fields', {}, function () { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10", "int_field should start with value 10"); - form.$('.o_field_x2many_list_row_add a').click(); + 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 - form.$('.o_field_widget[name="turtle_foo"]').val("some text").trigger('input'); + 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)"); @@ -5796,18 +5762,18 @@ QUnit.module('fields', {}, function () { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10", "int_field should start with value 10"); - form.$('.o_field_x2many_list_row_add a').click(); + 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 - form.$('.o_field_widget[name="turtle_int"]').val("1").trigger('input'); + 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)"); @@ -5848,29 +5814,29 @@ QUnit.module('fields', {}, function () { }); // add a first line but hold the onchange back - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('.o_data_row').length, 1, + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + assert.containsOnce(form, '.o_data_row', "should have created the first row immediately"); def = $.Deferred(); - form.$('.o_field_many2one input').click(); - form.$('.o_field_many2one input').autocomplete('widget').find('a').first().click(); + testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); + testUtils.fields.many2one.clickHighlightedItem('turtle_trululu'); // try to add a second line and check that it is correctly waiting // for the onchange to return - form.$('.o_field_x2many_list_row_add a').click(); + 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"); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should wait for the onchange to create the second row"); - assert.ok(form.$('.o_data_row').hasClass('o_selected_row'), + assert.hasClass(form.$('.o_data_row'),'o_selected_row', "first row should still be in edition"); // resolve the onchange def def.resolve(); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "second row should now have been created"); - assert.notOk(form.$('.o_data_row:first').hasClass('o_selected_row'), + assert.doesNotHaveClass(form.$('.o_data_row:first'), 'o_selected_row', "first row should no more be in edition"); form.destroy(); @@ -5906,16 +5872,16 @@ QUnit.module('fields', {}, function () { // click twice to add a new line def = $.Deferred(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('.o_data_row').length, 0, + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + 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(); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "only one row should have been created"); - assert.ok(form.$('.o_data_row:first').hasClass('o_selected_row'), + assert.hasClass(form.$('.o_data_row:first'),'o_selected_row', "the created row should be in edition"); form.destroy(); @@ -5960,17 +5926,17 @@ QUnit.module('fields', {}, function () { }); // trigger the two onchanges - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_data_row .o_field_widget').val('a name').trigger('input'); + 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(); - form.$('.o_datepicker_input').click(); // focusout o2m and set value to today + testUtils.dom.click(form.$('.o_datepicker_input')); var dateTimeVal = fieldUtils.format.datetime(moment(), { timezone: false }); - form.$('.o_datepicker_input').val(dateTimeVal).trigger('change'); + testUtils.fields.editSelect(form.$('.o_datepicker_input'), dateTimeVal); // resolve the onchange def def.resolve(); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should have one record in the o2m"); assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new', "should be the record created by the onchange"); @@ -6021,11 +5987,11 @@ QUnit.module('fields', {}, function () { }); // add a line (this should trigger an onchange and a warning) - form.$('.o_field_x2many_list_row_add a').click(); + 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) - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.verifySteps(['onchange', 'warning', 'onchange', 'warning']); @@ -6081,9 +6047,9 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$('.o_data_cell:first').click(); - form.$('.o_field_widget[name=display_name]').val('abc').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('.o_data_cell:first')); + testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'abc'); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -6114,7 +6080,7 @@ QUnit.module('fields', {}, function () { }, }); - form.$('input[name="foo"]').val('abcd').trigger('input'); + testUtils.fields.editInput(form.$('input[name="foo"]'), 'abcd'); assert.verifySteps(['read', 'onchange']); form.destroy(); @@ -6155,12 +6121,12 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "the one2many should contain one row"); - assert.strictEqual(form.$('.o_field_widget[name="timmy"]').length, 0, + assert.containsNone(form, '.o_field_widget[name="timmy"]', "timmy should not be displayed in the list view"); - form.$('.o_data_row td:first').click(); // open the record + 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"); @@ -6199,10 +6165,10 @@ QUnit.module('fields', {}, function () { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // triggers an onchange on partner, because the new record is valid - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.verifySteps(['read', 'default_get', 'onchange']); form.destroy(); @@ -6241,11 +6207,11 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_x2many_list_row_add a').click(); - $('.modal .o_data_cell input').val('new record').trigger('input'); + 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'); checkOnchange = true; - $('.modal .modal-footer .btn-primary').click(); // save (should trigger the onchange) + testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); form.destroy(); }); @@ -6285,18 +6251,18 @@ QUnit.module('fields', {}, function () { }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('tr.o_data_row').length, 41, + assert.containsN(form, 'tr.o_data_row', 41, "should have 41 data rows on the current page"); - assert.ok(form.$('tr.o_data_row').last().hasClass('o_selected_row'), + assert.hasClass(form.$('tr.o_data_row').last(),'o_selected_row', "last row should be selected"); - form.$('.o_data_row input[name="turtle_foo"]').val('rainbow dash').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); + testUtils.form.clickSave(form);; - assert.strictEqual(form.$('tr.o_data_row').length, 40, + assert.containsN(form, 'tr.o_data_row', 40, "should have 40 data rows on the current page"); assert.verifySteps(['read', 'read', 'default_get', 'write', 'read', 'read']); @@ -6328,13 +6294,13 @@ QUnit.module('fields', {}, function () { }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_data_row input[name="turtle_foo"]').val('rainbow dash').trigger('input'); - form.$('.o_x2m_control_panel .o_pager_next').click(); - form.$('.o_x2m_control_panel .o_pager_next').click(); + 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')); - assert.strictEqual(form.$('tr.o_data_row').length, 3, + assert.containsN(form, 'tr.o_data_row', 3, "should have 3 data rows on the current page"); form.destroy(); }); @@ -6375,27 +6341,27 @@ QUnit.module('fields', {}, function () { }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_pager_next').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_pager_next')); - assert.strictEqual(form.$('tr.o_data_row').length, 2, + assert.containsN(form, 'tr.o_data_row', 2, "should have 2 data rows on the current page"); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('tr.o_data_row').length, 3, + assert.containsN(form, 'tr.o_data_row', 3, "should have 3 data rows on the current page (2 records and the created line)"); - assert.ok(form.$('tr.o_data_row').first().hasClass('o_selected_row'), + assert.hasClass(form.$('tr.o_data_row').first(),'o_selected_row', "first row should be selected"); assert.strictEqual(form.$('tr.o_data_row input').val(), 'default foo', "selected input should have correct string"); - form.$('.o_data_row input[name="turtle_foo"]').val('rainbow dash').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash'); + testUtils.form.clickSave(form);; - assert.strictEqual(form.$('tr.o_data_row').length, 40, + assert.containsN(form, 'tr.o_data_row', 40, "should have 40 data rows on the current page"); assert.verifySteps(['read', 'read', 'read', 'default_get', 'write', 'read', 'read']); @@ -6435,11 +6401,9 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); def = $.Deferred(); - form.$('.o_field_widget[name=int_field]') - .val('44') - .trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), '44'); var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); // set trululu before onchange @@ -6490,19 +6454,17 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); def = $.Deferred(); - form.$('.o_field_widget[name=int_field]') - .val('44') - .trigger('input') - .trigger({ type: 'keydown', which: $.ui.keyCode.TAB }); + testUtils.fields.editAndTrigger(form.$('.o_field_widget[name=int_field]'), '44', + ['input', { type: 'keydown', which: $.ui.keyCode.TAB }]); def.resolve(); assert.strictEqual(document.activeElement, form.$('.o_field_widget[name=qux]')[0], "qux field should have the focus"); - form.$('.o_field_many2one input').click(); - form.$('.o_field_many2one input').autocomplete('widget').find('a').first().click(); + testUtils.fields.many2one.clickOpenDropdown('trululu'); + testUtils.fields.many2one.clickHighlightedItem('trululu'); assert.strictEqual(form.$('.o_field_many2one input').val(), 'first record', "the one2many field should have the expected value"); @@ -6529,9 +6491,9 @@ QUnit.module('fields', {}, function () { '', }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - form.$('.o_field_widget[name=bar] input').click(); + 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"); @@ -6560,15 +6522,15 @@ QUnit.module('fields', {}, function () { }); // edit the line and enter an invalid value for int_field - form.$('.o_data_row .o_data_cell:nth(1)').click(); - form.$('.o_field_widget[name=int_field]').val('e').trigger('input'); - form.$el.click(); // try to validate the line + 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); - assert.strictEqual(form.$('.o_data_row.o_selected_row').length, 1, + assert.containsOnce(form, '.o_data_row.o_selected_row', "line should not have been removed and should still be in edition"); assert.strictEqual($('.modal').length, 1, "a confirmation dialog should be opened"); - assert.ok(form.$('.o_field_widget[name=int_field]').hasClass('o_field_invalid'), + assert.hasClass(form.$('.o_field_widget[name=int_field]'),'o_field_invalid', "should indicate that int_field is invalid"); form.destroy(); @@ -6609,7 +6571,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual(form.$('.o_data_cell').text(), '1 record', "should correctly display the value of the inner o2m"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -6656,23 +6618,23 @@ QUnit.module('fields', {}, function () { "initial text should be correct"); // click and edit value to 'foo', which will trigger onchange - form.$('.o_data_row .o_data_cell:nth(0)').click(); - form.$('.o_field_widget[name=turtle_foo]').val('foo').trigger('input'); - form.$el.click(); + 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); 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 - form.$('.o_data_row .o_data_cell:nth(0)').click(); - form.$('.o_field_widget[name=turtle_foo]').val('pinky').trigger('input'); - form.$el.click(); + 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); 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. - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -6700,9 +6662,9 @@ QUnit.module('fields', {}, function () { }, viewOptions: { context: { flutter: 'shy' } }, }); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('input[name="turtle_foo"]').val('pinky pie').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + 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);; form.destroy(); }); @@ -6756,19 +6718,19 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_widget[name=display_name]').val('trigger onchange').trigger('input'); + 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 - form.$('.o_data_cell:first').click(); + 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"); - $('.modal .modal-footer .btn-primary').click(); + testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary')); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; form.destroy(); }); @@ -6810,7 +6772,7 @@ QUnit.module('fields', {}, function () { mode: 'edit', }, }); - form.$('.o_list_record_remove:first button').click(); + 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(); @@ -6854,7 +6816,7 @@ QUnit.module('fields', {}, function () { mode: 'edit', }, }); - form.$('.o_list_record_remove:first button').click(); + 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(); @@ -6893,9 +6855,9 @@ QUnit.module('fields', {}, function () { // check line is at the correct place var inputText = 'ninja'; - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_input[name="turtle_foo"]').val(inputText).trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + 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);; assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText); form.destroy(); @@ -6934,9 +6896,9 @@ QUnit.module('fields', {}, function () { // check line is at the correct place var inputText = 'ninja'; - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_input[name="turtle_foo"]').val(inputText).trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + 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);; assert.strictEqual($('.o_data_cell').text(), inputText + "blipyopkawa"); form.destroy(); @@ -6980,13 +6942,13 @@ QUnit.module('fields', {}, function () { // check line is at the correct place var inputText = 'ninja'; - $('.o_field_x2many_list_row_add a').click(); - $('.o_input[name="turtle_foo"]').val(inputText).trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); + 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')); assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText); - $('.o_form_button_save').click(); + testUtils.dom.click($('.o_form_button_save')); assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText); form.destroy(); }); @@ -7020,7 +6982,7 @@ QUnit.module('fields', {}, function () { // click add a new line // check turtle_int for new is the current max of the page - $('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click($('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_input[name="turtle_int"]').val(), '10'); form.destroy(); }); @@ -7054,7 +7016,7 @@ QUnit.module('fields', {}, function () { // click add a new line // check turtle_int for new is the current max of the page +1 - $('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click($('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .o_input[name="turtle_int"]').val(), '22'); form.destroy(); }); @@ -7108,11 +7070,11 @@ QUnit.module('fields', {}, function () { var inputText1 = 'relax'; var inputText2 = 'max'; - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_input[name="turtle_foo"]').val(inputText1).trigger('input'); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_input[name="turtle_foo"]').val(inputText2).trigger('input'); - form.$('.o_field_x2many_list_row_add a').click(); + 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')); assert.strictEqual($('.o_data_cell:nth-child(2)').text(), inputText1 + inputText2); @@ -7120,7 +7082,7 @@ QUnit.module('fields', {}, function () { assert.equal($handles.length, 3, 'There should be 3 sequence handlers'); - testUtils.dragAndDrop($handles.eq(1), + testUtils.dom.dragAndDrop($handles.eq(1), form.$('tbody tr').first(), { position: 'top' } ); @@ -7186,9 +7148,9 @@ QUnit.module('fields', {}, function () { "should display two records out of three, in the correct order"); // edit turtle_int field of first row - form.$('.o_data_cell:first').click(); - form.$('.o_field_widget[name=turtle_int]').val(3).trigger('input'); - form.$el.click(); // leave edition + testUtils.dom.click(form.$('.o_data_cell:first')); + testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_int]'), 3); + testUtils.dom.click(form.$el); assert.strictEqual(form.$('.o_data_cell.foo').text(), 'blipkawa', "should still display the same two records"); @@ -7225,7 +7187,7 @@ QUnit.module('fields', {}, function () { }); assert.strictEqual(form.$('.o_data_row').text(), 'yopblip', 'data has been properly loaded'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; assert.strictEqual(form.$('.o_data_row').text(), 'yopblip', 'data has been properly saved'); @@ -7266,10 +7228,10 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('.o_data_row').length, 4, 'should have 4 data rows'); - form.$('.o_input[name="turtle_foo"]').val('a').trigger('input'); - assert.strictEqual(form.$('.o_data_row').length, 4, + 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'); + assert.containsN(form, '.o_data_row', 4, 'should still have 4 data rows (the limit is increased to 4)'); form.destroy(); @@ -7306,7 +7268,7 @@ QUnit.module('fields', {}, function () { }); // swap 2 lines in the one2many - testUtils.dragAndDrop(form.$('.ui-sortable-handle:eq(1)'), form.$('tbody tr').first(), + 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(); @@ -7341,8 +7303,8 @@ QUnit.module('fields', {}, function () { }); // add a row and trigger the onchange - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_data_row .o_field_widget[name=display_name]').val('a name').trigger('input'); + 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'); assert.strictEqual(form.$('.o_data_row .o_field_widget[name=turtle_int]').val(), "44", "should have triggered the onchange"); @@ -7374,31 +7336,31 @@ QUnit.module('fields', {}, function () { '', }); - assert.strictEqual(form.$('.o_data_row').length, 0, + assert.containsNone(form, '.o_data_row', "there should be no record in the relation"); // add a new record - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal .o_field_widget').val('new record').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // Save & Close + 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')); assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new record', "should display the new record"); // reopen freshly added record and edit it - form.$('.o_data_row .o_data_cell').click(); - $('.modal .o_field_widget').val('new record edited').trigger('input'); + testUtils.dom.click(form.$('.o_data_row .o_data_cell')); + testUtils.fields.editInput($('.modal .o_field_widget'), 'new record edited'); // save it, and choose to directly create another record - $('.modal .modal-footer .btn-primary:nth(1)').click(); // Save & New + 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"); - $('.modal .o_field_widget').val('another new record').trigger('input'); - $('.modal .modal-footer .btn-primary:first').click(); // Save & Close + testUtils.fields.editInput($('.modal .o_field_widget'), 'another new record'); + 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"); @@ -7443,16 +7405,16 @@ QUnit.module('fields', {}, function () { // click add food // check it's empty - form.$('.o_field_x2many_list_row_add a:eq(0)').click(); + 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 - form.$('.o_field_x2many_list_row_add a:eq(1)').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)')); // click add pasta - form.$('.o_field_x2many_list_row_add a:eq(2)').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)')); + testUtils.form.clickSave(form);; assert.strictEqual($('.o_data_cell').text(), "pizzapasta"); form.destroy(); @@ -7495,22 +7457,22 @@ QUnit.module('fields', {}, function () { // click add food // check it's empty - form.$('.o_field_x2many_list_row_add a:eq(0)').click(); - $('.modal .modal-footer .btn-primary:first').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)')); + 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 - form.$('.o_field_x2many_list_row_add a:eq(1)').click(); - $('.modal .modal-footer .btn-primary:first').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)')); + 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 - form.$('.o_field_x2many_list_row_add a:eq(2)').click(); - $('.modal .modal-footer .btn-primary:first').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)')); + testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); assert.strictEqual($('.o_data_cell').text(), "pizzapasta"); form.destroy(); @@ -7582,27 +7544,27 @@ QUnit.module('fields', {}, function () { }, }); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "there should be one record in the one2many"); assert.strictEqual(form.$('.o_data_cell').text(), 'second record', "initial display_name of o2m record should be correct"); // open one2many record in form view - form.$('.o_data_cell:first').click(); + 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 - $('.modal .o_form_view button').click(); + 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 - $('.modal .modal-footer .btn-primary').click(); + 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"); @@ -7668,32 +7630,32 @@ QUnit.module('fields', {}, function () { }); // add a turtle on second partner - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_data_row:eq(1)').click(); - $('.modal .o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_data_row:eq(1)')); + testUtils.dom.click($('.modal .o_field_x2many_list_row_add a')); $('.modal input[name="display_name"]').val('michelangelo').change(); - $('.modal .btn-primary').click(); + testUtils.dom.click($('.modal .btn-primary')); // open first partner so changes from previous action are applied - form.$('.o_data_row:eq(0)').click(); - $('.modal .btn-primary').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('.o_data_row:eq(0)')); + testUtils.dom.click($('.modal .btn-primary')); + testUtils.form.clickSave(form);; assert.strictEqual(numUserOnchange, 2, 'there should 2 and only 2 onchange from closing the partner modal'); - form.$('.o_data_row:eq(0)').click(); + 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'); - $('.modal .o_form_button_cancel').click(); + testUtils.dom.click($('.modal .o_form_button_cancel')); - form.$('.o_data_row:eq(1)').click(); + 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'); - $('.modal .o_form_button_cancel').click(); + testUtils.dom.click($('.modal .o_form_button_cancel')); form.destroy(); }); @@ -7719,11 +7681,11 @@ QUnit.module('fields', {}, function () { res_id: 1, }); - form.$('.o_email_cell a').click(); + testUtils.dom.click(form.$('.o_email_cell a')); assert.strictEqual($('.modal .o_form_view').length, 0, 'click should not open the modal'); - form.$('.o_url_cell a').click(); + testUtils.dom.click(form.$('.o_url_cell a')); assert.strictEqual($('.modal .o_form_view').length, 0, 'click should not open the modal'); form.destroy(); @@ -7748,14 +7710,13 @@ QUnit.module('fields', {}, function () { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - assert.strictEqual(form.$('.o_selected_row').length, 1, + assert.containsOnce(form, '.o_selected_row', "should have create a new row in edition"); - var $input = form.$('.o_field_widget[name="turtle_trululu"] input'); - $input.click(); - $input.autocomplete('widget').find('.o_m2o_dropdown_option').focus().click(); + testUtils.fields.many2one.clickOpenDropdown('turtle_trululu'); + 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"); @@ -7767,7 +7728,7 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('.modal .o_form_view').length, 0, "should have closed the dialog"); - assert.strictEqual(form.$('.o_selected_row').length, 1, + assert.containsOnce(form, '.o_selected_row', "new row should still be present"); form.destroy(); @@ -7803,8 +7764,8 @@ QUnit.module('fields', {}, function () { }, }); - $('button[name="action_invoice_open"]').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click($('button[name="action_invoice_open"]')); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.destroy(); }); @@ -7830,18 +7791,16 @@ QUnit.module('fields', {}, function () { }); // add a row, fill it, then trigger the tab shortcut - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_input[name="turtle_foo"]') - .val('ninja') - .trigger('input') - .trigger($.Event('keydown', { - which: $.ui.keyCode.TAB, - keyCode: $.ui.keyCode.TAB, - })); + 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,})] + );; assert.strictEqual(form.$('.o_field_text').text(), 'blipninja', 'current line should be saved'); - assert.strictEqual(form.$('textarea.o_field_text').length, 1, + assert.containsOnce(form, 'textarea.o_field_text', 'new line should be created'); form.destroy(); @@ -7881,14 +7840,14 @@ QUnit.module('fields', {}, function () { var value = "hello"; // add a new line - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // we want to add a delay to simulate an onchange def = $.Deferred(); // write something in the field var $input = form.$('input[name="turtle_foo"]'); - $input.val(value).trigger('input'); + testUtils.fields.editInput($input, value); // trigger keydown ENTER $input.trigger($.Event('keydown', { @@ -7898,7 +7857,7 @@ QUnit.module('fields', {}, function () { // check that nothing changed before the onchange finished assert.strictEqual($input.val(), value, "input content shouldn't change"); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "should still contain only one row"); // unlock onchange @@ -7907,7 +7866,7 @@ QUnit.module('fields', {}, function () { // 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); assert.strictEqual(form.$('input[name="turtle_foo"]').val(), ''); - assert.strictEqual(form.$('.o_data_row').length, 2, + assert.containsN(form, '.o_data_row', 2, "should now contain two rows"); form.destroy(); @@ -7939,15 +7898,15 @@ QUnit.module('fields', {}, function () { fieldDebounce: 5000, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); - form.$('input').val('some foo value').trigger('input'); + testUtils.fields.editInput(form.$('input'), 'some foo value'); // click to add a second row to unselect the current one, then save - form.$('.o_field_x2many_list_row_add a').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.form.clickSave(form);; - assert.strictEqual(form.$('.o_form_readonly').length, 1, + assert.containsOnce(form, '.o_form_readonly', "form view should be in readonly"); assert.strictEqual(form.$('.o_data_row').text(), 'some foo value', "foo field should have correct value"); @@ -7992,20 +7951,20 @@ QUnit.module('fields', {}, function () { } }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a record in the list - x2mList.find('.o_field_x2many_list_row_add a').click(); + 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]'); - nameInput.val('michelangelo').trigger('input'); + testUtils.fields.editInput(nameInput, 'michelangelo'); // Save the record in the modal (though it is still virtual) - modal.find('.btn-primary').first().click(); + 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'); @@ -8018,7 +7977,7 @@ QUnit.module('fields', {}, function () { 'The display name field should have the right value'); // Save the whole thing - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form);; x2mList = form.$('.o_field_x2many_list[name=p]'); @@ -8064,18 +8023,18 @@ QUnit.module('fields', {}, function () { '', res_id: 1, }); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_many2one[name="product_id"] input').click(); - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); - assert.strictEqual(form.$('th').length, 1, + 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')); + 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'); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - form.$('.o_field_boolean[name="bar"] input').click(); - assert.strictEqual(form.$('th').length, 1, + testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); + assert.containsOnce(form, 'th', "should be 1 column after the value change"); form.destroy(); }); @@ -8110,19 +8069,19 @@ QUnit.module('fields', {}, function () { }); // bar is false so there should be 1 column - assert.strictEqual(form.$('th').length, 1, + assert.containsOnce(form, 'th', "should be only 1 column ('foo') in the one2many"); - assert.strictEqual(form.$('.o_list_view .o_data_row').length, 1, "should contain one row"); + assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // add a new o2m record - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.$('.o_field_one2many input:first').focus(); - form.$('.o_field_one2many input:first').val('New line').trigger('input'); - form.$el.click(); // click outside to save a line + testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line'); + testUtils.dom.click(form.$el); - assert.strictEqual(form.$('th').length, 2, "should be 2 columns('foo' + 'int_field')"); + assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')"); form.destroy(); }); @@ -8156,18 +8115,18 @@ QUnit.module('fields', {}, function () { '', }, }); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_many2one[name="product_id"] input').click(); - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); - assert.strictEqual(form.$('th').length, 1, + 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')); + 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'); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - form.$('.o_field_boolean[name="bar"] input').click(); - assert.strictEqual(form.$('th').length, 1, + 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_mobile_tests.js b/addons/web/static/tests/fields/relational_fields_mobile_tests.js index 8a1ab7ce1a5..1f2b2655e02 100644 --- a/addons/web/static/tests/fields/relational_fields_mobile_tests.js +++ b/addons/web/static/tests/fields/relational_fields_mobile_tests.js @@ -91,27 +91,27 @@ QUnit.module('relational_fields', { }, }); - assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 0, + assert.containsNone(form, '.o_field_one2many .o-kanban-button-new', '"Create" button should not be visible in readonly'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_one2many .o-kanban-button-new').length, 1, + assert.containsOnce(form, '.o_field_one2many .o-kanban-button-new', '"Create" button should be visible in edit'); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, "should have 2 records"); // open and delete record - form.$('.oe_kanban_global_click').first().click(); + testUtils.dom.click(form.$('.oe_kanban_global_click').first()); assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1, 'there should be a Remove button in the modal footer'); - $('.modal .modal-footer .o_btn_remove').click(); + testUtils.dom.click($('.modal .modal-footer .o_btn_remove')); assert.strictEqual($('.o_modal').length, 0, "there shoul be no more modal"); assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1, 'should contain 1 records'); // save and check that the correct command has been generated - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); }); diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js index ed34b56574b..f69c7004e54 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -183,12 +183,9 @@ QUnit.module('relational_fields', { assert.strictEqual(count, 1, 'once search_read should have been done to fetch the relational values'); assert.strictEqual(nb_fields_fetched, 1, 'search_read should only fetch field id'); - assert.strictEqual(form.$('.o_statusbar_status button:not(.dropdown-toggle)').length, 2, "should have 2 status"); - assert.strictEqual(form.$('.o_statusbar_status button:disabled').length, 2, - "all status should be disabled"); - assert.ok(form.$('.o_statusbar_status button[data-value="4"]').hasClass('btn-primary'), - "selected status should be btn-primary"); - + assert.containsN(form, '.o_statusbar_status button:not(.dropdown-toggle)', 2); + assert.containsN(form, '.o_statusbar_status button:disabled', 2); + assert.hasClass(form.$('.o_statusbar_status button[data-value="4"]'), 'btn-primary'); form.destroy(); }); @@ -217,7 +214,7 @@ QUnit.module('relational_fields', { }); QUnit.test('clickable statusbar widget on many2one field', function (assert) { - assert.expect(3); + assert.expect(5); var form = createView({ View: FormView, @@ -230,16 +227,17 @@ QUnit.module('relational_fields', { config: {device: {isMobile: false}}, }); - var $selectedStatus = form.$('.o_statusbar_status button[data-value="4"]'); - assert.ok($selectedStatus.hasClass('btn-primary') && $selectedStatus.hasClass('disabled'), - "selected status should be btn-primary and disabled"); + + assert.hasClass(form.$('.o_statusbar_status button[data-value="4"]'), 'btn-primary'); + assert.hasClass(form.$('.o_statusbar_status button[data-value="4"]'), 'disabled'); + + assert.containsN(form, '.o_statusbar_status button.btn-secondary:not(.dropdown-toggle):not(:disabled)', 2); + var $clickable = form.$('.o_statusbar_status button.btn-secondary:not(.dropdown-toggle):not(:disabled)'); - assert.strictEqual($clickable.length, 2, - "other status should be btn-secondary and not disabled"); - $clickable.last().click(); // (last is visually the first here (css)) - var $status = form.$('.o_statusbar_status button[data-value="1"]'); - assert.ok($status.hasClass("btn-primary") && $status.hasClass("disabled"), - "value should have been updated"); + testUtils.dom.click($clickable.last()); // (last is visually the first here (css)) + + assert.hasClass(form.$('.o_statusbar_status button[data-value="1"]'), "btn-primary"); + assert.hasClass(form.$('.o_statusbar_status button[data-value="1"]'), "disabled"); form.destroy(); }); @@ -259,8 +257,7 @@ QUnit.module('relational_fields', { config: {device: {isMobile: false}}, }); - assert.ok(form.$('.o_statusbar_status').hasClass('o_field_empty'), - 'statusbar widget should have class o_field_empty'); + assert.hasClass(form.$('.o_statusbar_status'), 'o_field_empty'); assert.strictEqual(form.$('.o_statusbar_status').children().length, 0, 'statusbar widget should be empty'); form.destroy(); @@ -282,8 +279,7 @@ QUnit.module('relational_fields', { config: {device: {isMobile: false}}, }); - assert.strictEqual(form.$('.o_statusbar_status button:disabled').length, 2, "should have 2 status"); - + assert.containsN(form, '.o_statusbar_status button:disabled', 2); form.destroy(); }); @@ -304,13 +300,10 @@ QUnit.module('relational_fields', { config: {device: {isMobile: false}}, }); - form.$buttons.find('.o_form_button_edit').click(); - - var $buttons = form.$('.o_statusbar_status button:not(.dropdown-toggle)'); - assert.strictEqual($buttons.length, 3, "there should be 3 status"); - $buttons.last().click(); // (last is visually the first here (css)) - assert.strictEqual(form.$('.o_statusbar_status button:not(.dropdown-toggle)').length, 2, - "there should be 2 status left"); + testUtils.form.clickEdit(form); + assert.containsN(form, '.o_statusbar_status button:not(.dropdown-toggle)', 3); + testUtils.dom.click(form.$('.o_statusbar_status button:not(.dropdown-toggle)').last()); + assert.containsN(form, '.o_statusbar_status button:not(.dropdown-toggle)', 2); form.destroy(); }); @@ -333,10 +326,10 @@ QUnit.module('relational_fields', { config: {device: {isMobile: false}}, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_statusbar_status:first .dropdown-menu button.disabled').length, 1, "should have 1 folded status"); - assert.strictEqual(form.$('.o_statusbar_status:last button.disabled').length, 1, "should have 1 status (other discarded)"); + assert.containsOnce(form, '.o_statusbar_status:first .dropdown-menu button.disabled'); + assert.containsOnce(form, '.o_statusbar_status:last button.disabled'); form.destroy(); }); @@ -368,14 +361,14 @@ QUnit.module('relational_fields', { config: {device: {isMobile: false}}, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_statusbar_status button.disabled').length, 3, "should have 3 status"); + assert.containsN(form, '.o_statusbar_status button.disabled', 3); assert.strictEqual(rpcCount, 1, "should have done 1 search_read rpc"); - form.$('input:first').val(9.5).trigger("input").trigger("change"); - assert.strictEqual(form.$('.o_statusbar_status button.disabled').length, 2, "should have 2 status"); + testUtils.fields.editInput(form.$('input[name=qux]'), 9.5); + assert.containsN(form, '.o_statusbar_status button.disabled', 2); assert.strictEqual(rpcCount, 2, "should have done 1 more search_read rpc"); - form.$('input:last').val("hey").trigger("input").trigger("change"); + testUtils.fields.editInput(form.$('input[name=qux]'), "hey"); assert.strictEqual(rpcCount, 2, "should not have done 1 more search_read rpc"); form.destroy(); @@ -401,7 +394,7 @@ QUnit.module('relational_fields', { assert.strictEqual(list.$('td:contains(Red)').length, 3, "should have 3 rows with correct value"); - list.$('td:contains(Red):first').click(); + testUtils.dom.click(list.$('td:contains(Red):first')); var $td = list.$('tbody tr.o_selected_row td:not(.o_list_record_selector)'); @@ -443,9 +436,9 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('.o_field_widget[name=color]').text(), 'Red', "should have rendered the selection field correctly"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('select').length, 3, + assert.containsN(form, 'select', 3, "should have 3 select tag in dom"); assert.strictEqual(form.$('select[name="product_id"] option:contains(xphone)').length, 1, "should have fetched xphone option"); @@ -455,7 +448,7 @@ QUnit.module('relational_fields', { "should have correct product_id value"); assert.strictEqual(form.$('select[name="trululu"]').val(), "false", "should not have any value in trululu field"); - form.$('select[name="product_id"]').val(41).trigger('change'); + testUtils.fields.editSelect(form.$('select[name="product_id"]'), 41); assert.strictEqual(form.$('select[name="product_id"]').val(), "41", "should have a value of xphone"); @@ -493,7 +486,7 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('.o_field_widget').text(), 'Value O', "the displayed value should be 'Value O'"); - assert.notOk(form.$('.o_field_widget').hasClass('o_field_empty'), + assert.doesNotHaveClass(form.$('.o_field_widget'), 'o_field_empty', "should not have class o_field_empty"); form.destroy(); @@ -523,7 +516,7 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('.o_field_widget').text(), '', "there should be no displayed value"); - assert.ok(form.$('.o_field_widget').hasClass('o_field_empty'), + assert.hasClass(form.$('.o_field_widget'),'o_field_empty', "should have class o_field_empty"); form.destroy(); @@ -552,8 +545,8 @@ QUnit.module('relational_fields', { }, }); - form.$('select').val("false").trigger('change'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editSelect(form.$('select'), "false"); + testUtils.form.clickSave(form); form.destroy(); }); @@ -615,13 +608,13 @@ QUnit.module('relational_fields', { }, }); - assert.strictEqual(form.$('.o_field_widget[name=trululu] option').length, 4, + assert.containsN(form, '.o_field_widget[name=trululu] option', 4, "should be 4 options in the selection"); // trigger an onchange that will update the domain - form.$('.o_field_widget[name=int_field]').val(2).trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); - assert.strictEqual(form.$('.o_field_widget[name=trululu] option').length, 1, + assert.containsOnce(form, '.o_field_widget[name=trululu] option', "should be 1 option in the selection"); form.destroy(); @@ -648,14 +641,14 @@ QUnit.module('relational_fields', { res_id: 1 }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name=color]')[0].options.length, 3, "non required selection field must have 3 options 1 blank option and 2 value options"); assert.strictEqual(form.$('.o_field_widget[name=feedback_value]')[0].options.length, 2, "should have only 2 options without blank option"); // change value to update widget modifier values - form.$('.o_field_widget[name=feedback_value]').val('"bad"').trigger('change'); + testUtils.fields.editSelect(form.$('.o_field_widget[name=feedback_value]'), '"bad"'); assert.strictEqual(form.$('.o_field_widget[name=color]')[0].options.length, 2, "should have only 2 options"); @@ -687,17 +680,16 @@ QUnit.module('relational_fields', { }); // add a tag on field partner_ids - var $input = form.$('.o_field_many2manytags[name="partner_ids"] input'); - $input.click(); // opens the dropdown - $input.autocomplete('widget').find('li:first()').click(); // adds a tag + testUtils.fields.many2one.clickOpenDropdown('partner_ids'); + testUtils.fields.many2one.clickHighlightedItem('partner_ids'); // add a tag on field timmy - $input = form.$('.o_field_many2manytags[name="timmy"] input'); - $input.click(); // opens the dropdown + testUtils.fields.many2one.clickOpenDropdown('timmy'); + var $input = form.$('.o_field_many2manytags[name="timmy"] input'); assert.strictEqual($input.autocomplete('widget').find('li').length, 3, - "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')"); - $input.autocomplete('widget').find('li:first()').click(); // adds a tag - assert.strictEqual(form.$('.o_field_many2manytags[name="timmy"] .badge').length, 1, + "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')"); + testUtils.fields.many2one.clickHighlightedItem('timmy'); + assert.containsOnce(form, '.o_field_many2manytags[name="timmy"] .badge', "should contain 1 tag"); assert.ok(form.$('.o_field_many2manytags[name="timmy"] .badge:contains("gold")').length, "should contain newly added tag 'gold'"); @@ -732,7 +724,7 @@ QUnit.module('relational_fields', { return this._super.apply(this, arguments); }, }); - assert.strictEqual(form.$('.o_field_many2manytags .badge .dropdown-toggle').length, 2, + assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 2, "should contain 2 tags"); assert.ok(form.$('.badge .dropdown-toggle:contains(gold)').length, 'should have fetched and rendered gold partner tag'); @@ -741,24 +733,24 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('.badge:first()').data('color'), 2, 'should have correctly fetched the color'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_many2manytags .badge .dropdown-toggle').length, 2, + assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 2, "should still contain 2 tags in edit mode"); assert.ok(form.$('.o_tag_color_2 .o_badge_text:contains(gold)').length, 'first tag should still contain "gold" and be color 2 in edit mode'); - assert.strictEqual(form.$('.o_field_many2manytags .o_delete').length, 2, + assert.containsN(form, '.o_field_many2manytags .o_delete', 2, "tags should contain a delete button"); // add an other existing tag var $input = form.$('.o_field_many2manytags input'); - $input.click(); // opens the dropdown + testUtils.fields.many2one.clickOpenDropdown('timmy'); assert.strictEqual($input.autocomplete('widget').find('li').length, 1, "autocomplete dropdown should have 1 entry"); assert.strictEqual($input.autocomplete('widget').find('li a:contains("red")').length, 1, "autocomplete dropdown should contain 'red'"); - $input.autocomplete('widget').find('li').click(); // add 'red' - assert.strictEqual(form.$('.o_field_many2manytags .badge .dropdown-toggle').length, 3, + testUtils.fields.many2one.clickHighlightedItem('timmy'); + assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 3, "should contain 3 tags"); assert.ok(form.$('.o_field_many2manytags .badge .dropdown-toggle:contains("red")').length, "should contain newly added tag 'red'"); @@ -766,34 +758,34 @@ QUnit.module('relational_fields', { "should have fetched the color of added tag"); // remove tag with id 14 - form.$('.o_field_many2manytags .badge[data-id=14] .o_delete').click(); - assert.strictEqual(form.$('.o_field_many2manytags .badge .dropdown-toggle').length, 2, + testUtils.dom.click(form.$('.o_field_many2manytags .badge[data-id=14] .o_delete')); + assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 2, "should contain 2 tags"); assert.ok(!form.$('.o_field_many2manytags .badge .dropdown-toggle:contains("silver")').length, "should not contain tag 'silver' anymore"); // save the record (should do the write RPC with the correct commands) - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // checkbox 'Hide in Kanban' $input = form.$('.o_field_many2manytags .badge[data-id=13] .dropdown-toggle'); // selects 'red' tag - $input.click(); // opens the colorpicker dropdown + testUtils.dom.click($input); var $checkBox = form.$('.o_field_many2manytags .badge[data-id=13] .custom-checkbox input'); assert.strictEqual($checkBox.length, 1, "should have a checkbox in the colorpicker dropdown menu"); assert.notOk($checkBox.is(':checked'), "should have unticked checkbox in colorpicker dropdown menu"); - $checkBox.mousedown().click(); + testUtils.fields.editAndTrigger($checkBox, null,['mouseenter','mousedown']); $input = form.$('.o_field_many2manytags .badge[data-id=13] .dropdown-toggle'); // refresh - $input.click(); + testUtils.dom.click($input); $checkBox = form.$('.o_field_many2manytags .badge[data-id=13] .custom-checkbox input'); // refresh assert.equal($input.parent().data('color'), "0", "should become transparent when toggling on checkbox"); assert.ok($checkBox.is(':checked'), "should have a ticked checkbox in colorpicker dropdown menu after mousedown"); - $checkBox.mousedown().click(); + testUtils.fields.editAndTrigger($checkBox, null,['mouseenter','mousedown']); $input = form.$('.o_field_many2manytags .badge[data-id=13] .dropdown-toggle'); // refresh - $input.click(); + testUtils.dom.click($input); $checkBox = form.$('.o_field_many2manytags .badge[data-id=13] .custom-checkbox input'); // refresh assert.equal($input.parent().data('color'), "8", "should revert to old color when toggling off checkbox"); assert.notOk($checkBox.is(':checked'), "should have an unticked checkbox in colorpicker dropdown menu after 2nd click"); @@ -828,22 +820,22 @@ QUnit.module('relational_fields', { return this._super.apply(this, arguments); } }); - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 1, + assert.containsOnce(form, '.o_field_many2manytags .badge', "should contain 1 tag"); assert.ok(form.$('.badge:contains(gold)').length, 'should have fetched and rendered gold partner tag'); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // add an other existing tag var $input = form.$('.o_field_many2manytags input'); - $input.click(); // opens the dropdown + testUtils.fields.many2one.clickOpenDropdown('timmy'); assert.strictEqual($input.autocomplete('widget').find('li').length, 1, - "autocomplete dropdown should have 1 entry"); + "autocomplete dropdown should have 1 entry"); assert.strictEqual($input.autocomplete('widget').find('li a:contains("silver")').length, 1, - "autocomplete dropdown should contain 'silver'"); - $input.autocomplete('widget').find('li').click(); // add 'silver' - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 2, + "autocomplete dropdown should contain 'silver'"); + testUtils.fields.many2one.clickHighlightedItem('timmy'); + assert.containsN(form, '.o_field_many2manytags .badge', 2, "should contain 2 tags"); assert.ok(form.$('.o_field_many2manytags .badge:contains("silver")').length, "should contain newly added tag 'silver'"); @@ -871,20 +863,20 @@ QUnit.module('relational_fields', { return this._super.apply(this, arguments); } }); - assert.ok(form.$('.o_form_view').hasClass('o_form_editable'), "form should be in edit mode"); + assert.hasClass(form.$('.o_form_view'),'o_form_editable', "form should be in edit mode"); - var $input = form.$('.o_field_many2manytags input'); - $input.click(); // opens the dropdown - assert.strictEqual($input.autocomplete('widget').find('li').length, 3, + testUtils.fields.many2one.clickOpenDropdown('timmy'); + assert.strictEqual(form.$('.o_field_many2manytags input').autocomplete('widget').find('li').length, 3, "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')"); - $input.autocomplete('widget').find('li:first()').click(); // adds a tag - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 1, + testUtils.fields.many2one.clickHighlightedItem('timmy'); + + assert.containsOnce(form, '.o_field_many2manytags .badge', "should contain 1 tag"); assert.ok(form.$('.o_field_many2manytags .badge:contains("gold")').length, "should contain newly added tag 'gold'"); // save the record (should do the write RPC with the correct commands) - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -918,15 +910,15 @@ QUnit.module('relational_fields', { // Update the color in readonly color = 1; - form.$('.badge:first() .dropdown-toggle').click(); + testUtils.dom.click(form.$('.badge:first() .dropdown-toggle')); $('.o_colorpicker a[data-color="' + color + '"]').trigger('mousedown'); // choose color 1 assert.strictEqual(form.$('.badge:first()').data('color'), color, 'should have correctly updated the color (in readonly)'); // Update the color in edit color = 6; - form.$buttons.find('.o_form_button_edit').click(); - form.$('.badge:first() .dropdown-toggle').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.badge:first() .dropdown-toggle')); $('.o_colorpicker a[data-color="' + color + '"]').trigger('mousedown'); // choose color 6 assert.strictEqual(form.$('.badge:first()').data('color'), color, 'should have correctly updated the color (in edit)'); @@ -957,33 +949,32 @@ QUnit.module('relational_fields', { } }); - assert.strictEqual(list.$('.o_data_row:first .o_field_many2manytags .badge').length, 1, + assert.containsOnce(list, '.o_data_row:first .o_field_many2manytags .badge', "m2m field should contain one tag"); // edit first row - list.$('.o_data_row:first td:nth(2)').click(); + testUtils.dom.click(list.$('.o_data_row:first td:nth(2)')); var $m2o = list.$('.o_data_row:first .o_field_many2manytags .o_field_many2one'); assert.strictEqual($m2o.length, 1, "a many2one widget should have been instantiated"); // add a tag - var $input = $m2o.find('input'); - $input.click(); - $input.autocomplete('widget').find('li:first()').click(); // adds a tag + testUtils.fields.many2one.clickOpenDropdown('timmy'); + testUtils.fields.many2one.clickHighlightedItem('timmy'); - assert.strictEqual(list.$('.o_data_row:first .o_field_many2manytags .badge').length, 2, + assert.containsN(list, '.o_data_row:first .o_field_many2manytags .badge', 2, "m2m field should contain 2 tags"); // leave edition - list.$('.o_data_row:nth(1) td:nth(2)').click(); + testUtils.dom.click(list.$('.o_data_row:nth(1) td:nth(2)')); - assert.strictEqual(list.$('.o_data_row:first .o_field_many2manytags .badge').length, 2, + assert.containsN(list, '.o_data_row:first .o_field_many2manytags .badge', 2, "m2m field should contain 2 tags"); list.destroy(); }); - QUnit.test('search more in many2one: group and use the pager', function (assert) { + QUnit.test('search more in many2one: group and use the pager', async function (assert) { assert.expect(2); this.data.partner.records.push({ @@ -1030,19 +1021,16 @@ QUnit.module('relational_fields', { mode: 'edit', }, }); + testUtils.fields.many2one.clickOpenDropdown('trululu'); + await testUtils.fields.many2one.clickItem('trululu', 'Search'); + testUtils.dom.click($('.modal .o_search_options .fa-bars')); + testUtils.dom.click($('.modal .o_search_options .o_group_by_menu a:contains(Bar)')); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').click(); - $dropdown.find('.o_m2o_dropdown_option:contains(Search)').mouseenter().click(); // Open Search More - - $('.modal .o_search_options .fa-bars').click(); - $('.modal .o_search_options .o_group_by_menu a:contains(Bar)').click(); // group by 'Bar' - - $('.modal .o_group_header:first').click(); + testUtils.dom.click($('.modal .o_group_header:first')); assert.strictEqual($('.modal tbody:nth(1) .o_data_row').length, 7, "should display 7 records in the first page"); - $('.modal .o_group_header:first .o_pager_next').click(); + testUtils.dom.click($('.modal .o_group_header:first .o_pager_next')); assert.strictEqual($('.modal tbody:nth(1) .o_data_row').length, 1, "should display 1 record in the second page"); @@ -1067,7 +1055,7 @@ QUnit.module('relational_fields', { '', res_id: 1, }); - assert.strictEqual(form.$('.o_field_widget[name="partner_ids"] .badge').length, 100, + assert.containsN(form, '.o_field_widget[name="partner_ids"] .badge', 100, 'should have rendered 100 tags'); form.destroy(); }); @@ -1091,30 +1079,32 @@ QUnit.module('relational_fields', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, '.o_field_many2manytags .badge', "should contain one tag"); // update foo, which will trigger an onchange and update timmy // -> m2mtags input should not have taken the focus form.$('input:first').focus(); - form.$('input:first').val('trigger onchange').trigger('input'); - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 0, + testUtils.fields.editInput(form.$('input:first'), 'trigger onchange'); + assert.containsNone(form, '.o_field_many2manytags .badge', "should contain no tags"); assert.strictEqual(form.$('input:first').get(0), document.activeElement, "foo input should have kept the focus"); // add a tag -> m2mtags input should still have the focus - form.$('.o_field_many2manytags input').click(); // opens the dropdown - form.$('.o_field_many2manytags input').autocomplete('widget').find('li:first').click(); - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 1, + testUtils.fields.many2one.clickOpenDropdown('timmy'); + testUtils.fields.many2one.clickHighlightedItem('timmy'); + + + assert.containsOnce(form, '.o_field_many2manytags .badge', "should contain a tag"); assert.strictEqual(form.$('.o_field_many2manytags input').get(0), document.activeElement, "m2m tags input should have kept the focus"); // remove a tag -> m2mtags input should still have the focus - form.$('.o_field_many2manytags .o_delete').click(); - assert.strictEqual(form.$('.o_field_many2manytags .badge').length, 0, + testUtils.dom.click(form.$('.o_field_many2manytags .o_delete')); + assert.containsNone(form, '.o_field_many2manytags .badge', "should contain no tags"); assert.strictEqual(form.$('.o_field_many2manytags input').get(0), document.activeElement, "m2m tags input should have kept the focus"); @@ -1174,13 +1164,13 @@ QUnit.module('relational_fields', { "colorpicker should be closed"); // click on the badge to open colorpicker - form.$('.o_field_many2manytags .badge .dropdown-toggle').click(); + testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle')); assert.strictEqual($('.o_colorpicker:visible').length, 1, "colorpicker should be open"); // click on the badge again to close colorpicker - form.$('.o_field_many2manytags .badge .dropdown-toggle').click(); + testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle')); assert.strictEqual($('.o_field_many2manytags .badge').data('color'), 0, "tag should still have color 0"); @@ -1188,13 +1178,13 @@ QUnit.module('relational_fields', { "colorpicker should be closed"); // click on the badge to open colorpicker - form.$('.o_field_many2manytags .badge .dropdown-toggle').click(); + testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle')); assert.strictEqual($('.o_colorpicker:visible').length, 1, "colorpicker should be open"); // click on the colorpicker, but not on a color - form.$('.o_colorpicker').click(); + testUtils.dom.click(form.$('.o_colorpicker')); assert.strictEqual($('.o_field_many2manytags .badge').data('color'), 0, "tag should still have color 0"); @@ -1202,7 +1192,7 @@ QUnit.module('relational_fields', { "colorpicker should be closed"); // click on the badge to open colorpicker - form.$('.o_field_many2manytags .badge .dropdown-toggle').click(); + testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle')); // click on a color in the colorpicker form.$('.o_colorpicker .o_tag_color_2').trigger('mousedown'); @@ -1230,15 +1220,15 @@ QUnit.module('relational_fields', { }); assert.ok(form.$('div.o_radio_item').length, "should have rendered outer div"); - assert.strictEqual(form.$('input.o_radio_input').length, 2, "should have 2 possible choices"); + assert.containsN(form, 'input.o_radio_input', 2, "should have 2 possible choices"); assert.ok(form.$('label.o_form_label:contains(xphone)').length, "one of them should be xphone"); - assert.strictEqual(form.$('input:checked').length, 0, "none of the input should be checked"); + assert.containsNone(form, 'input:checked', "none of the input should be checked"); - form.$("input.o_radio_input:first").click(); + testUtils.dom.click(form.$("input.o_radio_input:first")); - assert.strictEqual(form.$('input:checked').length, 1, "one of the input should be checked"); + assert.containsOnce(form, 'input:checked', "one of the input should be checked"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); var newRecord = _.last(this.data.partner.records); assert.strictEqual(newRecord.product_id, 37, "should have saved record with correct value"); @@ -1264,12 +1254,12 @@ QUnit.module('relational_fields', { '', }); - form.$("input[type='checkbox']").click(); - assert.strictEqual(form.$('input.o_radio_input[data-value="37"]:checked').length, 1, "one of the input should be checked"); - assert.strictEqual(form.$('input.o_radio_input[data-value="black"]:checked').length, 1, "the other of the input should be checked"); - form.$("input[type='checkbox']").click(); - assert.strictEqual(form.$('input.o_radio_input[data-value="41"]:checked').length, 1, "the other of the input should be checked"); - assert.strictEqual(form.$('input.o_radio_input[data-value="red"]:checked').length, 1, "one of the input should be checked"); + testUtils.dom.click(form.$("input[type='checkbox']")); + assert.containsOnce(form, 'input.o_radio_input[data-value="37"]:checked', "one of the input should be checked"); + assert.containsOnce(form, 'input.o_radio_input[data-value="black"]:checked', "the other of the input should be checked"); + testUtils.dom.click(form.$("input[type='checkbox']")); + assert.containsOnce(form, 'input.o_radio_input[data-value="41"]:checked', "the other of the input should be checked"); + assert.containsOnce(form, 'input.o_radio_input[data-value="red"]:checked', "one of the input should be checked"); form.destroy(); }); @@ -1288,13 +1278,13 @@ QUnit.module('relational_fields', { assert.ok(form.$('div.o_radio_item').length, "should have rendered outer div"); - assert.strictEqual(form.$('input.o_radio_input').length, 2, "should have 2 possible choices"); + assert.containsN(form, 'input.o_radio_input', 2, "should have 2 possible choices"); assert.ok(form.$('label.o_form_label:contains(Red)').length, "one of them should be Red"); // click on 2nd option - form.$("input.o_radio_input").eq(1).click(); + testUtils.dom.click(form.$("input.o_radio_input").eq(1)); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); var newRecord = _.last(this.data.partner.records); assert.strictEqual(newRecord.color, 'black', "should have saved record with correct value"); @@ -1355,21 +1345,21 @@ QUnit.module('relational_fields', { assert.strictEqual(form.$('.o_field_widget').text(), '', "field should be unset"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_radio_input:checked').length, 0, + assert.containsNone(form, '.o_radio_input:checked', "no value should be checked"); - form.$("input.o_radio_input:nth(1)").click(); // click on 2nd option + testUtils.dom.click(form.$("input.o_radio_input:nth(1)")); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget').text(), 'Black', "value should be 'Black'"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_radio_input[data-index=1]:checked').length, 1, + assert.containsOnce(form, '.o_radio_input[data-index=1]:checked', "'Black' should be checked"); form.destroy(); @@ -1415,13 +1405,13 @@ QUnit.module('relational_fields', { }, }); - assert.strictEqual(form.$('.o_field_widget[name=trululu] .o_radio_item').length, 3, + assert.containsN(form, '.o_field_widget[name=trululu] .o_radio_item', 3, "should be 3 radio buttons"); // trigger an onchange that will update the domain - form.$('.o_field_widget[name=int_field]').val(2).trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2); - assert.strictEqual(form.$('.o_field_widget[name=trululu] .o_radio_item').length, 0, + assert.containsNone(form, '.o_field_widget[name=trululu] .o_radio_item', "should be no more radio button"); form.destroy(); @@ -1443,15 +1433,15 @@ QUnit.module('relational_fields', { }); assert.ok(form.$('span.o_selection_badge').length, "should have rendered outer div"); - assert.strictEqual(form.$('span.o_selection_badge').length, 2, "should have 2 possible choices"); + assert.containsN(form, 'span.o_selection_badge', 2, "should have 2 possible choices"); assert.ok(form.$('span.o_selection_badge:contains(xphone)').length, "one of them should be xphone"); - assert.strictEqual(form.$('span.active').length, 0, "none of the input should be checked"); + assert.containsNone(form, 'span.active', "none of the input should be checked"); - $("span.o_selection_badge:first").click(); + testUtils.dom.click($("span.o_selection_badge:first")); - assert.strictEqual(form.$('span.active').length, 1, "one of the input should be checked"); + assert.containsOnce(form, 'span.active', "one of the input should be checked"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); var newRecord = _.last(this.data.partner.records); assert.strictEqual(newRecord.product_id, 37, "should have saved record with correct value"); @@ -1471,13 +1461,13 @@ QUnit.module('relational_fields', { }); assert.ok(form.$('span.o_selection_badge').length, "should have rendered outer div"); - assert.strictEqual(form.$('span.o_selection_badge').length, 2, "should have 2 possible choices"); + assert.containsN(form, 'span.o_selection_badge', 2, "should have 2 possible choices"); assert.ok(form.$('span.o_selection_badge:contains(Red)').length, "one of them should be Red"); // click on 2nd option - form.$("span.o_selection_badge").eq(1).click(); + testUtils.dom.click(form.$("span.o_selection_badge").eq(1)); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); var newRecord = _.last(this.data.partner.records); assert.strictEqual(newRecord.color, 'black', "should have saved record with correct value"); @@ -1496,7 +1486,7 @@ QUnit.module('relational_fields', { '', }); - assert.strictEqual(form.$('span.o_readonly_modifier').length, 1, "should have 1 possible value in readonly mode"); + assert.containsOnce(form, 'span.o_readonly_modifier', "should have 1 possible value in readonly mode"); form.destroy(); }); @@ -1516,7 +1506,7 @@ QUnit.module('relational_fields', { res_id: 1, }); - assert.strictEqual(form.$('div.o_field_widget div.custom-checkbox').length, 2, + assert.containsN(form, 'div.o_field_widget div.custom-checkbox', 2, "should have fetched and displayed the 2 values of the many2many"); assert.ok(form.$('div.o_field_widget div.custom-checkbox input').eq(0).prop('checked'), @@ -1527,23 +1517,23 @@ QUnit.module('relational_fields', { assert.ok(form.$('div.o_field_widget div.custom-checkbox input').prop('disabled'), "the checkboxes should be disabled"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').prop('disabled'), "the checkboxes should not be disabled"); // add a m2m value by clicking on input - form.$('div.o_field_widget div.custom-checkbox input').eq(1).click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(1)); + testUtils.form.clickSave(form); assert.deepEqual(this.data.partner.records[0].timmy, [12, 14], "should have added the second element to the many2many"); - assert.strictEqual(form.$('input:checked').length, 2, + assert.containsN(form, 'input:checked', 2, "both checkboxes should be checked"); // remove a m2m value by clinking on label - form.$buttons.find('.o_form_button_edit').click(); - form.$('div.o_field_widget div.custom-checkbox > label').eq(0).click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox > label').eq(0)); + testUtils.form.clickSave(form); assert.deepEqual(this.data.partner.records[0].timmy, [14], "should have removed the first element to the many2many"); assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').eq(0).prop('checked'), @@ -1569,9 +1559,9 @@ QUnit.module('relational_fields', { viewOptions: {mode: 'edit'}, }); - form.$('div.o_field_widget div.custom-checkbox input').eq(0).click(); - form.$('div.o_field_widget div.custom-checkbox input').eq(1).click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(0)); + testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(1)); + testUtils.form.clickSave(form); assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').eq(0).prop('checked'), "first checkbox should not be checked"); assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').eq(1).prop('checked'), @@ -1622,29 +1612,29 @@ QUnit.module('relational_fields', { }, }); - assert.strictEqual(form.$('div.o_field_widget.oe_fileupload').length, 1, + assert.containsOnce(form, 'div.o_field_widget.oe_fileupload', "there should be the attachment widget"); assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .oe_attachments').children().length, 1, "there should be no attachment"); - assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .o_attach').length, 0, + assert.containsNone(form, 'div.o_field_widget.oe_fileupload .o_attach', "there should not be an Add button (readonly)"); - assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .oe_attachment .oe_delete').length, 0, + assert.containsNone(form, 'div.o_field_widget.oe_fileupload .oe_attachment .oe_delete', "there should not be a Delete button (readonly)"); // to edit mode - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .o_attach').length, 1, + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'div.o_field_widget.oe_fileupload .o_attach', "there should be an Add button"); assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .o_attach').text().trim(), "Pictures", "the button should be correctly named"); - assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .o_hidden_input_file form').length, 1, + assert.containsOnce(form, 'div.o_field_widget.oe_fileupload .o_hidden_input_file form', "there should be a hidden form to upload attachments"); // TODO: add an attachment // no idea how to test this // delete the attachment - form.$('div.o_field_widget.oe_fileupload .oe_attachment .oe_delete').click(); + testUtils.dom.click(form.$('div.o_field_widget.oe_fileupload .oe_attachment .oe_delete')); assert.verifySteps([ @@ -1652,7 +1642,7 @@ QUnit.module('relational_fields', { '/web/dataset/call_kw/ir.attachment/read', ]); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .oe_attachments').children().length, 0, "there should be no attachment"); @@ -1660,13 +1650,9 @@ QUnit.module('relational_fields', { form.destroy(); }); - QUnit.test('name_create in form dialog', function (assert) { - var done = assert.async(); + QUnit.test('name_create in form dialog', async function (assert) { assert.expect(2); - var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - var form = createView({ View: FormView, model: 'partner', @@ -1691,18 +1677,13 @@ QUnit.module('relational_fields', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - var $dropdown = $('.modal .o_field_many2one input').autocomplete('widget'); - $('.modal input').val('new record').trigger('keydown'); - concurrency.delay(0).then(function () { - $dropdown.find('li:first()').click(); // quick create 'new record' - assert.verifySteps(['name_create']); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + await testUtils.fields.many2one.searchAndClickItem('product_id', + {selector:'.modal', search:'new record'}); - relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY; - form.destroy(); - done(); - }); + assert.verifySteps(['name_create']); + + form.destroy(); }); QUnit.module('FieldReference'); @@ -1737,7 +1718,7 @@ QUnit.module('relational_fields', { assert.equal($cell_o2m.text(), 'second record', 'the list should have one record'); - $cell_o2m.click(); + testUtils.dom.click($cell_o2m); // In modal var $modal = $('.modal-lg'); @@ -1747,7 +1728,7 @@ QUnit.module('relational_fields', { assert.equal($modal.find('.o_form_uri.o_field_widget[name=reference]').text(), 'xpad', 'The field reference in the modal should have the right value'); - $modal.find('.o_form_button_cancel').click(); + testUtils.dom.click($modal.find('.o_form_button_cancel')); form.destroy(); }); @@ -1775,7 +1756,7 @@ QUnit.module('relational_fields', { }); // current form - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var $fieldRef = form.$('.o_field_widget.o_field_many2one[name=reference]'); assert.equal($fieldRef.find('option:selected').text(), 'Product', @@ -1783,7 +1764,7 @@ QUnit.module('relational_fields', { assert.equal($fieldRef.find('.o_input.ui-autocomplete-input').val(), 'xphone', 'The reference field\'s record should be xphone'); - form.$('.o_data_cell').click(); + testUtils.dom.click(form.$('.o_data_cell')); // In modal var $modal = $('.modal-lg'); @@ -1846,20 +1827,20 @@ QUnit.module('relational_fields', { }, }); - testUtils.intercept(form, 'do_action', function (event) { + testUtils.mock.intercept(form, 'do_action', function (event) { assert.strictEqual(event.data.action.res_id, 17, "should do a do_action with correct parameters"); }); assert.strictEqual(form.$('a.o_form_uri:contains(xphone)').length, 1, "should contain a link"); - form.$('a.o_form_uri').click(); // click on the link in readonly mode (should trigger do_action) + testUtils.dom.click(form.$('a.o_form_uri')); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_widget').length, 2, + assert.containsN(form, '.o_field_widget', 2, "should contain two field widgets (selection and many2one)"); - assert.strictEqual(form.$('.o_field_many2one').length, 1, + assert.containsOnce(form, '.o_field_many2one', "should contain one many2one"); assert.strictEqual(form.$('.o_field_widget select').val(), "product", "widget should contain one select with the model"); @@ -1872,22 +1853,21 @@ QUnit.module('relational_fields', { assert.deepEqual(options, ['', 'product', 'partner_type', 'partner'], "the options should be correctly set"); - form.$('.o_external_button').click(); // click on the external button (should do an RPC) + 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"); - $('.modal .o_form_button_cancel').click(); + testUtils.dom.click($('.modal .o_form_button_cancel')); - form.$('.o_field_widget select').val('partner_type').trigger('change'); + testUtils.fields.editSelect(form.$('.o_field_widget select'), 'partner_type'); assert.strictEqual(form.$('.o_field_widget input').val(), "", "many2one value should be reset after model change"); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - // change the value of the m2o with a suggestion of the dropdown - form.$('.o_field_many2one input').click(); // will trigger a name_search on partner_type model - $dropdown.find('li:first()').click(); + testUtils.fields.many2one.clickOpenDropdown('reference'); + testUtils.fields.many2one.clickHighlightedItem('reference'); - form.$buttons.find('.o_form_button_save').click(); + + testUtils.form.clickSave(form); assert.strictEqual(form.$('a.o_form_uri:contains(gold)').length, 1, "should contain a link with the new value"); @@ -1936,7 +1916,7 @@ QUnit.module('relational_fields', { "reference field value should be correctly set"); // trigger onchange - form.$('.o_field_widget[name=int_field]').val(12).trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 12); assert.verifySteps(['product', 'partner_type'], "the second name_get should have been done"); assert.strictEqual(form.$('.o_field_widget[name="reference"] select').val(), "partner_type", @@ -2019,7 +1999,7 @@ QUnit.module('relational_fields', { "foo field should be correctly set"); // trigger onchange - form.$('.o_field_widget[name=int_field]').val(41).trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 41); assert.strictEqual(nbNameGet, 2, "the second name_get should have been done"); @@ -2039,7 +2019,7 @@ QUnit.module('relational_fields', { }); // edit first row - list.$('.o_data_row .o_data_cell').first().click(); + testUtils.dom.click(list.$('.o_data_row .o_data_cell').first()); assert.strictEqual(list.$('.o_data_row:eq(0) .o_field_widget[name="reference"] input')[0], document.activeElement, 'input of first data row should be selected'); @@ -2082,20 +2062,20 @@ QUnit.module('relational_fields', { } }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var x2mList = form.$('.o_field_x2many_list[name=p]'); // Add a record in the list - x2mList.find('.o_field_x2many_list_row_add a').click(); + 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]'); - nameInput.val('michelangelo').trigger('input'); + testUtils.fields.editInput(nameInput, 'michelangelo'); // Save the record in the modal (though it is still virtual) - modal.find('.btn-primary').first().click(); + 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'); @@ -2108,7 +2088,7 @@ QUnit.module('relational_fields', { 'The display name field should have the right value'); // Save the whole thing - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); x2mList = form.$('.o_field_x2many_list[name=p]'); @@ -2154,18 +2134,18 @@ QUnit.module('relational_fields', { '', res_id: 1, }); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_many2one[name="product_id"] input').click(); - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); - assert.strictEqual(form.$('th').length, 1, + 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')); + 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'); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - form.$('.o_field_boolean[name="bar"] input').click(); - assert.strictEqual(form.$('th').length, 1, + testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); + assert.containsOnce(form, 'th', "should be 1 column after the value change"); form.destroy(); }); @@ -2200,19 +2180,19 @@ QUnit.module('relational_fields', { }); // bar is false so there should be 1 column - assert.strictEqual(form.$('th').length, 1, + assert.containsOnce(form, 'th', "should be only 1 column ('foo') in the one2many"); - assert.strictEqual(form.$('.o_list_view .o_data_row').length, 1, "should contain one row"); + assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // add a new o2m record - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.$('.o_field_one2many input:first').focus(); - form.$('.o_field_one2many input:first').val('New line').trigger('input'); - form.$el.click(); // click outside to save a line + testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line'); + testUtils.dom.click(form.$el); - assert.strictEqual(form.$('th').length, 2, "should be 2 columns('foo' + 'int_field')"); + assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')"); form.destroy(); }); @@ -2246,18 +2226,18 @@ QUnit.module('relational_fields', { '', }, }); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_many2one[name="product_id"] input').click(); - $('li.ui-menu-item a:contains(xpad)').trigger('mouseenter').click(); - assert.strictEqual(form.$('th').length, 1, + 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')); + 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'); - assert.strictEqual(form.$('th').length, 2, + assert.containsN(form, 'th', 2, "should be 2 columns in the one2many when product_id is not set"); - form.$('.o_field_boolean[name="bar"] input').click(); - assert.strictEqual(form.$('th').length, 1, + testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input')); + assert.containsOnce(form, 'th', "should be 1 column after the value change"); form.destroy(); }); @@ -2343,7 +2323,7 @@ QUnit.module('relational_fields', { which: $.ui.keyCode.TAB, keyCode: $.ui.keyCode.TAB, })); - document.activeElement.click(); + testUtils.dom.click(document.activeElement); assert.strictEqual(assert.strictEqual(form.$el.find('input[name="turtle_foo"]')[0], document.activeElement, "after tab, the focus should be on the many2one")); @@ -2500,16 +2480,16 @@ QUnit.module('relational_fields', { }); // add a new line - form.$el.find('.o_field_x2many_list_row_add>a').click(); + testUtils.dom.click(form.$el.find('.o_field_x2many_list_row_add>a')); // open the field turtle_trululu (one2many) var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY; relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0; - form.$el.find('.o_input_dropdown>input').click(); + testUtils.dom.click(form.$el.find('.o_input_dropdown>input')); concurrency.delay(0).then(function () { // click create and edit - $('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter').click(); + testUtils.dom.click($('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter')); // hit escape immediately var escapeKey = $.ui.keyCode.ESCAPE; diff --git a/addons/web/static/tests/fields/special_fields.js b/addons/web/static/tests/fields/special_fields.js index f9df1a6f4e3..8654c3e0a9f 100644 --- a/addons/web/static/tests/fields/special_fields.js +++ b/addons/web/static/tests/fields/special_fields.js @@ -208,7 +208,7 @@ QUnit.module('special_fields', { '' + '', }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('select').length, 1, "should have the select field"); form.destroy(); }); diff --git a/addons/web/static/tests/fields/upgrade_fields_tests.js b/addons/web/static/tests/fields/upgrade_fields_tests.js index 15c32eeeaf0..65de67a7951 100644 --- a/addons/web/static/tests/fields/upgrade_fields_tests.js +++ b/addons/web/static/tests/fields/upgrade_fields_tests.js @@ -32,7 +32,7 @@ QUnit.module('upgrade_fields', { arch: '
', }); - form.$('input:checkbox').click(); + testUtils.dom.click(form.$('input:checkbox')); assert.strictEqual($('.modal').length, 1, "the 'Upgrade to Enterprise' dialog should be opened"); @@ -52,9 +52,9 @@ QUnit.module('upgrade_fields', { '', }); - assert.strictEqual(form.$('.o_field .badge').length, 0, + assert.containsNone(form, '.o_field .badge', "the upgrade badge shouldn't be inside the field section"); - assert.strictEqual(form.$('.o_label .badge').length, 1, + assert.containsOnce(form, '.o_label .badge', "the upgrade badge should be inside the label section"); assert.strictEqual(form.$('.o_label').text(), "Bar EnterpriseCoucou", "the upgrade label should be inside the label section"); diff --git a/addons/web/static/tests/helpers/qunit_asserts.js b/addons/web/static/tests/helpers/qunit_asserts.js new file mode 100644 index 00000000000..bce6ef2a777 --- /dev/null +++ b/addons/web/static/tests/helpers/qunit_asserts.js @@ -0,0 +1,229 @@ +odoo.define('web.qunit_asserts', function (require) { +"use strict"; + +/** + * In this file, we extend QUnit by adding some specialized assertions. The goal + * of these new assertions is twofold: + * - ease of use: they should allow us to simplify some common complex assertions + * - safer: these assertions will fail when some preconditions are not met. + * + * For example, the assert.isVisible assertion will also check that the target + * matches exactly one element. + */ + +var Widget = require('web.Widget'); + +//------------------------------------------------------------------------------ +// Private functions +//------------------------------------------------------------------------------ + +/** + * Helper function, to check if a given element + * - is unique (if it is a jquery node set) + * - has (or has not) a css class + * + * @private + * @param {Widget|jQuery|HTMLElement} w + * @param {string} className + * @param {boolean} shouldHaveClass + * @param {string} [msg] + */ +function _checkClass(w, className, shouldHaveClass, msg) { + var $el = w instanceof Widget ? w.$el : + w instanceof HTMLElement ? $(w) : + w; // jquery element + + if ($el.length !== 1) { + var descr = `${shouldHaveClass ? 'hasClass' : 'doesNotHaveClass'} ${className}`; + QUnit.assert.ok(false, `Assertion '${descr}' targets ${$el.length} elements instead of 1`); + } else { + msg = msg || `target ${$el.selector || ''} should ${shouldHaveClass ? '' : 'not'} have class ${className}`; + var hasClass = $el.hasClass(className); + var condition = shouldHaveClass ? hasClass : !hasClass; + QUnit.assert.ok(condition, msg); + } +} + +/** + * Helper function, to check if a given element + * - is unique (if it is a jquery node set) + * - is (or not) visible + * + * @private + * @param {Widget|jQuery|HTMLElement} w + * @param {boolean} shouldBeVisible + * @param {string} [msg] + */ +function _checkVisible(w, shouldBeVisible, msg) { + var $el = w instanceof Widget ? w.$el : + w instanceof HTMLElement ? $(w) : + w; // jquery element + + if ($el.length !== 1) { + var descr = `${shouldBeVisible ? 'isVisible' : 'isNotVisible'}`; + QUnit.assert.ok(false, `Assertion '${descr}' targets ${$el.length} elements instead of 1`); + } else { + msg = msg || `target ${$el.selector} should ${shouldBeVisible ? '' : 'not'} be visible`; + var isVisible = $el.is(':visible'); + var condition = shouldBeVisible ? isVisible : !isVisible; + QUnit.assert.ok(condition, msg); + } +} + +//------------------------------------------------------------------------------ +// Public functions +//------------------------------------------------------------------------------ + +/** + * Checks that the target element (described by widget/jquery or html element) + * contains exactly n matches for the selector. + * + * Example: assert.containsN(document.body, '.modal', 0) + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} selector + * @param {number} n + * @param {string} [msg] + */ +function containsN(w, selector, n, msg) { + if (typeof n !== 'number') { + throw Error("containsN assert should be called with a number as third argument"); + } + var $el = w instanceof Widget ? w.$el : + w instanceof HTMLElement ? $(w) : + w; // jquery element + + var $matches = $el.find(selector); + if (!msg) { + msg = `Selector '${selector}' should have exactly ${n} matches`; + if ($el.selector) { + msg += ` (inside '${$el.selector}')`; + } + } + QUnit.assert.strictEqual($matches.length, n, msg); +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * contains exactly 1 match for the selector. + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} selector + * @param {string} [msg] + */ +function containsOnce(w, selector, msg) { + containsN(w, selector, 1, msg); +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * contains exactly 0 match for the selector. + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} selector + * @param {string} [msg] + */ +function containsNone(w, selector, msg) { + containsN(w, selector, 0, msg); +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is unique + * - has the given class (specified by className) + * + * Note that it uses the hasClass jQuery method, so it can be used to check the + * presence of more than one class ('some-class other-class'), but it is a + * little brittle, because it depends on the order of these classes: + * + * div.a.b.c: has class 'a b c', but does not have class 'a c b' + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} className + * @param {string} [msg] + */ +function hasClass(w, className, msg) { + _checkClass(w, className, true, msg); +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is unique + * - does not have the given class (specified by className) + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} className + * @param {string} [msg] + */ +function doesNotHaveClass(w, className, msg) { + _checkClass(w, className, false, msg); +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is unique + * - has the given attribute with the proper value + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} attr + * @param {string} value + * @param {string} [msg] + */ +function hasAttrValue(w, attr, value, msg) { + var $el = w instanceof Widget ? w.$el : + w instanceof HTMLElement ? $(w) : + w; // jquery element + + if ($el.length !== 1) { + var descr = `hasAttrValue (${attr}: ${value})`; + QUnit.assert.ok(false, `Assertion '${descr}' targets ${$el.length} elements instead of 1`); + } else { + msg = msg || `attribute '${attr}' of target ${$el.selector || ''} should be '${value}'`; + QUnit.assert.strictEqual($el.attr(attr), value, msg); + } +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is visible (as far as jQuery can tell: not in display none, ...) + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} [msg] + */ +function isVisible(w, msg) { + _checkVisible(w, true, msg); +} + +/** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is not visible (as far as jQuery can tell: display none, ...) + * + * @param {Widget|jQuery|HTMLElement} w + * @param {string} [msg] + */ +function isNotVisible(w, msg) { + _checkVisible(w, false, msg); +} + +//------------------------------------------------------------------------------ +// Exposed API +//------------------------------------------------------------------------------ + +QUnit.assert.containsOnce = containsOnce; +QUnit.assert.containsNone = containsNone; +QUnit.assert.containsN = containsN; + +QUnit.assert.hasClass = hasClass; +QUnit.assert.doesNotHaveClass = doesNotHaveClass; + +QUnit.assert.hasAttrValue = hasAttrValue; + +QUnit.assert.isVisible = isVisible; +QUnit.assert.isNotVisible = isNotVisible; + +}); diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js index ab46c05cfa8..2ecc30b3872 100644 --- a/addons/web/static/tests/helpers/test_utils.js +++ b/addons/web/static/tests/helpers/test_utils.js @@ -10,928 +10,18 @@ odoo.define('web.test_utils', function (require) { * instance of a view, appended in the dom, ready to be tested. */ -var ActionManager = require('web.ActionManager'); var ajax = require('web.ajax'); -var basic_fields = require('web.basic_fields'); -var config = require('web.config'); -var ControlPanel = require('web.ControlPanel'); var core = require('web.core'); -var DebugManager = require('web.DebugManager'); -var dom = require('web.dom'); var session = require('web.session'); -var MockServer = require('web.MockServer'); -var Widget = require('web.Widget'); - -var DebouncedField = basic_fields.DebouncedField; - -/** - * intercepts an event bubbling up the widget hierarchy. The event intercepted - * must be a "custom event", i.e. an event generated by the method 'trigger_up'. - * - * Note that this method really intercepts the event if @propagate is not set. - * It will not be propagated further, and even the handlers on the target will - * not fire. - * - * @param {Widget} widget the target widget (any Odoo widget) - * @param {string} eventName description of the event - * @param {function} fn callback executed when the even is intercepted - * @param {boolean} [propagate=false] - */ -function intercept(widget, eventName, fn, propagate) { - var _trigger_up = widget._trigger_up.bind(widget); - widget._trigger_up = function (event) { - if (event.name === eventName) { - fn(event); - if (!propagate) { return; } - } - _trigger_up(event); - }; -} - -/** - * logs all event going through the target widget. - * - * @param {Widget} widget - */ -function observe(widget) { - var _trigger_up = widget._trigger_up.bind(widget); - widget._trigger_up = function (event) { - console.log('%c[event] ' + event.name, 'color: blue; font-weight: bold;', event); - _trigger_up(event); - }; -} - -/** - * create and return an instance of ActionManager with all rpcs going through a - * mock method using the data, actions and archs objects as sources. - * - * @param {Object} [params] - * @param {Object} [params.actions] the actions given to the mock server - * @param {Object} [params.archs] this archs given to the mock server - * @param {Object} [params.data] the business data given to the mock server - * @param {boolean} [params.debug] - * @param {function} [params.mockRPC] - * @returns {ActionManager} - */ -var createActionManager = function (params) { - params = params || {}; - var $target = $('#qunit-fixture'); - if (params.debug) { - $target = $('body'); - $target.addClass('debug'); - } - - var widget = new Widget(); - // when 'document' addon is installed, the sidebar does a 'search_read' on - // model 'ir_attachment' each time a record is open, so we monkey-patch - // 'mockRPC' to mute those RPCs, so that the tests can be written uniformly, - // whether or not 'document' is installed - var mockRPC = params.mockRPC; - _.extend(params, { - mockRPC: function (route, args) { - if (args.model === 'ir.attachment') { - return $.when([]); - } - if (mockRPC) { - return mockRPC.apply(this, arguments); - } - return this._super.apply(this, arguments); - }, - }); - addMockEnvironment(widget, _.defaults(params, { debounce: false })); - widget.prependTo($target); - widget.$el.addClass('o_web_client'); - if (config.device.isMobile) { - widget.$el.addClass('o_touch_device'); - } - - var userContext = params.context && params.context.user_context || {}; - var actionManager = new ActionManager(widget, userContext); - - var originalDestroy = ActionManager.prototype.destroy; - actionManager.destroy = function () { - actionManager.destroy = originalDestroy; - widget.destroy(); - }; - actionManager.appendTo(widget.$el); - - return actionManager; -}; -/** - * Create and return an instance of DebugManager with all rpcs going through a - * mock method, assuming that the user has access rights, and is an admin. - * - * @param {Object} [params={}] - */ -var createDebugManager = function (params) { - params = params || {}; - var mockRPC = params.mockRPC; - _.extend(params, { - mockRPC: function (route, args) { - if (args.method === 'check_access_rights') { - return $.when(true); - } - if (args.method === 'xmlid_to_res_id') { - return $.when(true); - } - if (mockRPC) { - return mockRPC.apply(this, arguments); - } - return this._super.apply(this, arguments); - }, - session: { - user_has_group: function (group) { - if (group === 'base.group_no_one') { - return $.when(true); - } - return this._super.apply(this, arguments); - }, - }, - }); - var debugManager = new DebugManager(); - addMockEnvironment(debugManager, params); - return debugManager; -}; - -/** - * performs a fields_view_get, and mocks the postprocessing done by the - * data_manager to return an equivalent structure. - * - * @param {MockServer} server - * @param {Object} params - * @param {string} params.model - * @returns {Object} an object with 3 keys: arch, fields and viewFields - */ -function fieldsViewGet(server, params) { - var fieldsView = server.fieldsViewGet(params); - // mock the structure produced by the DataManager - fieldsView.viewFields = fieldsView.fields; - fieldsView.fields = server.fieldsGet(params.model); - return fieldsView; -} - -/** - * create a view synchronously. This method uses the createAsyncView method. - * Most views are synchronous, so the deferred can be resolved immediately and - * this method will work. - * - * Be careful, if for some reason a view is async, this method will crash. - * @see createAsyncView - * - * @param {Object} params will be given to createAsyncView - * @returns {AbstractView} - */ -function createView(params) { - var view; - createAsyncView(params).then(function (result) { - view = result; - }); - if (!view) { - throw "The view that you are trying to create is async. Please use createAsyncView instead"; - } - return view; -} - -/** - * create a view from various parameters. Here, a view means a javascript - * instance of an AbstractView class, such as a form view, a list view or a - * kanban view. - * - * It returns the instance of the view, properly created, with all rpcs going - * through a mock method using the data object as source, and already loaded/ - * started. - * - * Most views can be tested synchronously (@see createView), but some view have - * external dependencies (like lazy loaded libraries). In that case, it is - * necessary to use this method. - * - * @param {Object} params - * @param {string} params.arch the xml (arch) of the view to be instantiated - * @param {any[]} [params.domain] the initial domain for the view - * @param {Object} [params.context] the initial context for the view - * @param {Object} [params.debug=false] if true, the widget will be appended in - * the DOM. Also, RPCs and uncaught OdooEvent will be logged - * @param {string[]} [params.groupBy] the initial groupBy for the view - * @param {integer} [params.fieldDebounce=0] the debounce value to use for the - * duration of the test. - * @param {AbstractView} params.View the class that will be instantiated - * @param {string} params.model a model name, will be given to the view - * @param {Object} params.intercepts an object with event names as key, and - * callback as value. Each key,value will be used to intercept the event. - * Note that this is particularly useful if you want to intercept events going - * up in the init process of the view, because there are no other way to do it - * after this method returns - * @returns {Deferred} resolves with the instance of the view - */ -function createAsyncView(params) { - var $target = $('#qunit-fixture'); - var widget = new Widget(); - if (params.debug) { - $target = $('body'); - $target.addClass('debug'); - } - - // add mock environment: mock server, session, fieldviewget, ... - var mockServer = addMockEnvironment(widget, params); - var viewInfo = fieldsViewGet(mockServer, params); - // create the view - var viewOptions = { - modelName: params.model || 'foo', - ids: 'res_id' in params ? [params.res_id] : undefined, - currentId: 'res_id' in params ? params.res_id : undefined, - domain: params.domain || [], - context: params.context || {}, - groupBy: params.groupBy || [], - }; - if (params.hasSelectors) { - viewOptions.hasSelectors = params.hasSelectors; - } - - _.extend(viewOptions, params.viewOptions); - - var view = new params.View(viewInfo, viewOptions); - - // reproduce the DOM environment of views - var $web_client = $('
').addClass('o_web_client').prependTo($target); - var controlPanel = new ControlPanel(widget); - controlPanel.appendTo($web_client); - var $content = $('
').addClass('o_content').appendTo($web_client); - - if (params.interceptsPropagate) { - _.each(params.interceptsPropagate, function (cb, name) { - intercept(widget, name, cb, true); - }); - } - - return view.getController(widget).then(function (view) { - // override the view's 'destroy' so that it calls 'destroy' on the widget - // instead, as the widget is the parent of the view and the mockServer. - view.__destroy = view.destroy; - view.destroy = function () { - // remove the override to properly destroy the view and its children - // when it will be called the second time (by its parent) - delete view.destroy; - widget.destroy(); - }; - - // link the view to the control panel - view.set_cp_bus(controlPanel.get_bus()); - - // render the view in a fragment as they must be able to render correctly - // without being in the DOM - var fragment = document.createDocumentFragment(); - return view.appendTo(fragment).then(function () { - dom.append($content, fragment, { - callbacks: [{ widget: view }], - in_DOM: true, - }); - view.$el.on('click', 'a', function (ev) { - ev.preventDefault(); - }); - - return view; - }); - }); -} - -/** - * Patch window.Date so that the time starts its flow from the provided Date. - * - * Usage: - * - * ``` - * var unpatchDate = testUtils.patchDate(2018, 0, 10, 17, 59, 30) - * new window.Date(); // "Wed Jan 10 2018 17:59:30 GMT+0100 (Central European Standard Time)" - * ... // 5 hours delay - * new window.Date(); // "Wed Jan 10 2018 22:59:30 GMT+0100 (Central European Standard Time)" - * ... - * unpatchDate(); - * new window.Date(); // actual current date time - * ``` - * - * @param {integer} year - * @param {integer} month index of the month, starting from zero. - * @param {integer} day the day of the month. - * @param {integer} hours the digits for hours (24h) - * @param {integer} minutes - * @param {integer} seconds - * @returns {function} a callback to unpatch window.Date. - */ -function patchDate(year, month, day, hours, minutes, seconds) { - var RealDate = window.Date; - var actualDate = new RealDate(); - var fakeDate = new RealDate(year, month, day, hours, minutes, seconds); - var timeInterval = actualDate.getTime() - (fakeDate.getTime()); - - Date = (function (NativeDate) { - function Date(Y, M, D, h, m, s, ms) { - var length = arguments.length; - if (arguments.length > 0) { - var date = length == 1 && String(Y) === Y ? // isString(Y) - // We explicitly pass it through parse: - new NativeDate(Date.parse(Y)) : - // We have to manually make calls depending on argument - // length here - length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : - length >= 6 ? new NativeDate(Y, M, D, h, m, s) : - length >= 5 ? new NativeDate(Y, M, D, h, m) : - length >= 4 ? new NativeDate(Y, M, D, h) : - length >= 3 ? new NativeDate(Y, M, D) : - length >= 2 ? new NativeDate(Y, M) : - length >= 1 ? new NativeDate(Y) : - new NativeDate(); - // Prevent mixups with unfixed Date object - date.constructor = Date; - return date; - } else { - var date = new NativeDate(); - var time = date.getTime(); - time -= timeInterval; - date.setTime(time); - return date; - } - } - - // Copy any custom methods a 3rd party library may have added - for (var key in NativeDate) { - Date[key] = NativeDate[key]; - } - - // Copy "native" methods explicitly; they may be non-enumerable - Date.now = NativeDate.now; - Date.UTC = NativeDate.UTC; - Date.prototype = NativeDate.prototype; - Date.prototype.constructor = Date; - - // Upgrade Date.parse to handle simplified ISO 8601 strings - Date.parse = NativeDate.parse; - return Date; - })(Date); - - return function () { window.Date = RealDate; }; -} - -/** - * Add a mock environment to a widget. This helper function can simulate - * various kind of side effects, such as mocking RPCs, changing the session, - * or the translation settings. - * - * The simulated environment lasts for the lifecycle of the widget, meaning it - * disappears when the widget is destroyed. It is particularly relevant for the - * session mocks, because the previous session is restored during the destroy - * call. So, it means that you have to be careful and make sure that it is - * properly destroyed before another test is run, otherwise you risk having - * interferences between tests. - * - * @param {Widget} widget - * @param {Object} params - * @param {Object} [params.archs] a map of string [model,view_id,view_type] to - * a arch object. It is used to mock answers to 'load_views' custom events. - * This is useful when the widget instantiate a formview dialog that needs - * to load a particular arch. - * @param {string} [params.currentDate] a string representation of the current - * date. It is given to the mock server. - * @param {Object} params.data the data given to the created mock server. It is - * used to generate mock answers for every kind of routes supported by odoo - * @param {number} [params.debug] if set to true, logs RPCs and uncaught Odoo - * events. - * @param {function} [params.mockRPC] a function that will be used to override - * the _performRpc method from the mock server. It is really useful to add - * some custom rpc mocks, or to check some assertions. - * @param {Object} [params.session] if it is given, it will be used as answer - * for all calls to this.getSession() by the widget, of its children. Also, - * it will be used to extend the current, real session. This side effect is - * undone when the widget is destroyed. - * @param {Object} [params.translateParameters] if given, it will be used to - * extend the core._t.database.parameters object. After the widget - * destruction, the original parameters will be restored. - * @param {Object} [params.intercepts] an object with event names as key, and - * callback as value. Each key,value will be used to intercept the event. - * Note that this is particularly useful if you want to intercept events going - * up in the init process of the view, because there are no other way to do it - * after this method returns. Some events ('call_service', "load_views", - * "get_session", "load_filters") have a special treatment beforehand. - * @param {Object} [params.services={}] list of services to load in - * addition to the ajax service. For instance, if a test needs the local - * storage service in order to work, it can provide a mock version of it. - * @param {boolean} [debounce=true] set to false to completely remove the - * debouncing, forcing the handler to be called directly (not on the next - * execution stack, like it does with delay=0). - * @param {boolean} [throttle=false] set to true to keep the throttling, which - * is completely removed by default. - * - * @returns {MockServer} the instance of the mock server, created by this - * function. It is necessary for createAsyncView so that method can call some - * other methods on it. - */ -function addMockEnvironment(widget, params) { - var Server = MockServer; - params.services = params.services || {}; - if (params.mockRPC) { - Server = MockServer.extend({ _performRpc: params.mockRPC }); - } - if (params.debug) { - observe(widget); - var separator = window.location.href.indexOf('?') !== -1 ? "&" : "?"; - var url = window.location.href + separator + 'testId=' + QUnit.config.current.testId; - console.log('%c[debug] debug mode activated', 'color: blue; font-weight: bold;', url); - } - - var mockServer = new Server(params.data, { - actions: params.actions, - archs: params.archs, - currentDate: params.currentDate, - debug: params.debug, - widget: widget, - }); - - // make sure images do not trigger a GET on the server - $('body').on('DOMNodeInserted.removeSRC', function (event) { - removeSrcAttribute(event.target, widget); - }); - - // make sure the debounce value for input fields is set to 0 - var initialDebounceValue = DebouncedField.prototype.DEBOUNCE; - DebouncedField.prototype.DEBOUNCE = params.fieldDebounce || 0; - var initialSession, initialConfig, initialParameters, initialDebounce, initialThrottle; - initialSession = _.extend({}, session); - session.getTZOffset = function () { - return 0; // by default, but may be overriden in specific tests - }; - if ('session' in params) { - _.extend(session, params.session); - } - if ('config' in params) { - initialConfig = _.clone(config); - initialConfig.device = _.clone(config.device); - if ('device' in params.config) { - _.extend(config.device, params.config.device); - } - if ('debug' in params.config) { - config.debug = params.config.debug; - } - } - if ('translateParameters' in params) { - initialParameters = _.extend({}, core._t.database.parameters); - _.extend(core._t.database.parameters, params.translateParameters); - } - if (params.debounce === false) { - initialDebounce = _.debounce; - _.debounce = function (func) { - return func; - }; - } - if (!('throttle' in params) || !params.throttle) { - initialThrottle = _.throttle; - _.throttle = function (func) { - return func; - }; - } - - var widgetDestroy = widget.destroy; - widget.destroy = function () { - // clear the caches (e.g. data_manager, ModelFieldSelector) when the - // widget is destroyed, at the end of each test to avoid collisions - core.bus.trigger('clear_cache'); - - DebouncedField.prototype.DEBOUNCE = initialDebounceValue; - if (params.debounce === false) { - _.debounce = initialDebounce; - } - if (!('throttle' in params) || !params.throttle) { - _.throttle = initialThrottle; - } - - var key; - if ('session' in params) { - for (key in session) { - delete session[key]; - } - } - _.extend(session, initialSession); - if ('config' in params) { - for (key in config) { - delete config[key]; - } - _.extend(config, initialConfig); - } - if ('translateParameters' in params) { - for (key in core._t.database.parameters) { - delete core._t.database.parameters[key]; - } - _.extend(core._t.database.parameters, initialParameters); - } - - $('body').off('DOMNodeInserted.removeSRC'); - $('.blockUI').remove(); - - widgetDestroy.call(this); - }; - - // Dispatch service calls - // Note: some services could call other services at init, - // Which is why we have to init services after that - var services = {}; - intercept(widget, 'call_service', function (ev) { - var args, result; - if (services[ev.data.service]) { - var service = services[ev.data.service]; - args = (ev.data.args || []); - result = service[ev.data.method].apply(service, args); - } else if (ev.data.service === 'ajax') { - // use ajax service that is mocked by the server - var route = ev.data.args[0]; - args = ev.data.args[1]; - result = mockServer.performRpc(route, args); - } - ev.data.callback(result); - }); - - intercept(widget, 'load_action', function (event) { - mockServer.performRpc('/web/action/load', { - kwargs: { - action_id: event.data.actionID, - additional_context: event.data.context, - }, - }).then(function (action) { - event.data.on_success(action); - }); - }); - - intercept(widget, "load_views", function (event) { - mockServer.performRpc('/web/dataset/call_kw/' + event.data.modelName, { - args: [], - kwargs: { - context: event.data.context, - options: event.data.options, - views: event.data.views, - }, - method: 'load_views', - model: event.data.modelName, - }).then(function (views) { - views = _.mapObject(views, function (viewParams) { - return fieldsViewGet(mockServer, viewParams); - }); - event.data.on_success(views); - }); - }); - - intercept(widget, "get_session", function (event) { - event.data.callback(session); - }); - - intercept(widget, "load_filters", function (event) { - if (params.debug) { - console.log('[mock] load_filters', event.data); - } - event.data.on_success([]); - }); - - // make sure all Odoo events bubbling up are intercepted - if ('intercepts' in params) { - _.each(params.intercepts, function (cb, name) { - intercept(widget, name, cb); - }); - } - - // Deploy services - var done = false; - var servicesToDeploy = _.clone(params.services); - if (!servicesToDeploy.ajax) { - services.ajax = null; // use mocked ajax from mocked server - } - while (!done) { - var serviceName = _.findKey(servicesToDeploy, function (Service) { - return !_.some(Service.prototype.dependencies, function (depName) { - return !_.has(services, depName); - }); - }); - if (serviceName) { - var Service = servicesToDeploy[serviceName]; - var service = services[serviceName] = new Service(widget); - delete servicesToDeploy[serviceName]; - - intercept(service, "get_session", function (event) { - event.data.callback(session); - }); - - service.start(); - } else { - var serviceNames = _.keys(servicesToDeploy); - if (serviceNames.length) { - console.warn("Non loaded services:", serviceNames); - } - done = true; - } - } - - return mockServer; -} - -/** - * create a model from given parameters. - * - * @param {Object} params This object will be given to addMockEnvironment, so - * any parameters from that method applies - * @param {Class} params.Model the model class to use - * @returns {Model} - */ -function createModel(params) { - var widget = new Widget(); - - var model = new params.Model(widget); - - addMockEnvironment(widget, params); - - // override the model's 'destroy' so that it calls 'destroy' on the widget - // instead, as the widget is the parent of the model and the mockServer. - model.destroy = function () { - // remove the override to properly destroy the model when it will be - // called the second time (by its parent) - delete model.destroy; - widget.destroy(); - }; - - return model; -} - -/** - * create a widget parent from given parameters. - * - * @param {Object} params This object will be given to addMockEnvironment, so - * any parameters from that method applies - * @returns {Widget} - */ -function createParent(params) { - var widget = new Widget(); - addMockEnvironment(widget, params); - return widget; -} - -/** - * simulate a drag and drop operation between 2 jquery nodes: $el and $to. - * This is a crude simulation, with only the mousedown, mousemove and mouseup - * events, but it is enough to help test drag and drop operations with jqueryUI - * sortable. - * - * @param {jqueryElement} $el - * @param {jqueryElement} $to - * @param {Object} [options] - * @param {string|Object} [options.position='center'] target position: - * can either be one of {'top', 'bottom', 'left', 'right'} or - * an object with two attributes (top and left)) - * @param {boolean} [options.disableDrop=false] whether to trigger the drop action - * @param {boolean} [options.continueMove=false] whether to trigger the - * mousedown action (will only work after another call of this function with - * without this option) - */ -function dragAndDrop($el, $to, options) { - var position = (options && options.position) || 'center'; - var elementCenter = $el.offset(); - var toOffset = $to.offset(); - - if (_.isObject(position)) { - toOffset.top += position.top; - toOffset.left += position.left; - } else { - toOffset.top += $to.outerHeight() / 2; - toOffset.left += $to.outerWidth() / 2; - var vertical_offset = (toOffset.top < elementCenter.top) ? -1 : 1; - if (position === 'top') { - toOffset.top -= $to.outerHeight() / 2 + vertical_offset; - } else if (position === 'bottom') { - toOffset.top += $to.outerHeight() / 2 - vertical_offset; - } else if (position === 'left') { - toOffset.left -= $to.outerWidth() / 2; - } else if (position === 'right') { - toOffset.left += $to.outerWidth() / 2; - } - } - - if ($to[0].ownerDocument !== document) { - // we are in an iframe - var bound = $('iframe')[0].getBoundingClientRect(); - toOffset.left += bound.left; - toOffset.top += bound.top; - } - $el.trigger($.Event("mouseenter")); - if (!(options && options.continueMove)) { - elementCenter.left += $el.outerWidth() / 2; - elementCenter.top += $el.outerHeight() / 2; - - $el.trigger($.Event("mousedown", { - which: 1, - pageX: elementCenter.left, - pageY: elementCenter.top - })); - } - - $el.trigger($.Event("mousemove", { - which: 1, - pageX: toOffset.left, - pageY: toOffset.top - })); - - if (!(options && options.disableDrop)) { - $el.trigger($.Event("mouseup", { - which: 1, - pageX: toOffset.left, - pageY: toOffset.top - })); - } else { - // It's impossible to drag another element when one is already - // being dragged. So it's necessary to finish the drop when the test is - // over otherwise it's impossible for the next tests to drag and - // drop elements. - $el.on("remove", function () { - $el.trigger($.Event("mouseup")); - }); - } -} - -/** - * simulate a mouse event with a custom event who add the item position. This is - * sometimes necessary because the basic way to trigger an event (such as - * $el.trigger('mousemove')); ) is too crude for some uses. - * - * @param {jqueryElement} $el - * @param {string} type a mouse event type, such as 'mousedown' or 'mousemove' - */ -function triggerMouseEvent($el, type) { - var pos = $el.offset(); - var e = new $.Event(type); - e.pageX = e.layerX = e.screenX = pos.left; - e.pageY = e.layerY = e.screenY = pos.top; - e.which = 1; - $el.trigger(e); -} - -/** - * simulate a mouse event with a custom event on a position x and y. This is - * sometimes necessary because the basic way to trigger an event (such as - * $el.trigger('mousemove')); ) is too crude for some uses. - * - * @param {integer} x - * @param {integer} y - * @param {string} type a mouse event type, such as 'mousedown' or 'mousemove' - */ -function triggerPositionalMouseEvent(x, y, type) { - var ev = document.createEvent("MouseEvent"); - var el = document.elementFromPoint(x, y); - ev.initMouseEvent( - type, - true /* bubble */, - true /* cancelable */, - window, null, - x, y, x, y, /* coordinates */ - false, false, false, false, /* modifier keys */ - 0 /*left button*/, null - ); - el.dispatchEvent(ev); - return el; -} - -/** - * simulate a keypress event for a given character - * @param {string} the character - */ -function triggerKeypressEvent(char) { - var keycode; - if (char === "Enter") { - keycode = $.ui.keyCode.ENTER; - } else { - keycode = char.charCodeAt(0); - } - return $('body').trigger($.Event('keypress', { which: keycode, keyCode: keycode })); -} - -/** - * Removes the src attribute on images and iframes to prevent not found errors, - * and optionally triggers an rpc with the src url as route on a widget. - * This method is critical and must be fastest (=> no jQuery, no underscore) - * - * @param {DOM Node} el - * @param {[Widget]} widget the widget on which the rpc should be performed - */ -function removeSrcAttribute(el, widget) { - var nodes; - if (el.nodeName === 'IMG' || el.nodeName === 'IFRAME') { - nodes = [el]; - } else { - nodes = Array.prototype.slice.call(el.getElementsByTagName('img')) - .concat(Array.prototype.slice.call(el.getElementsByTagName('iframe'))); - } - var node; - while (node = nodes.pop()) { - var src = node.attributes.src && node.attributes.src.value; - if (src && src !== 'about:blank') { - var $el = $(node); - node.setAttribute('data-src', src); - if (node.nodeName === 'IMG') { - node.attributes.removeNamedItem('src'); - } else { - node.setAttribute('src', 'about:blank'); - } - if (widget) { - widget._rpc({ route: src }); - } - } - } -} - -var patches = {}; -/** - * Patches a given Class or Object with the given properties. - * - * @param {Class|Object} target - * @param {Object} props - */ -function patch(target, props) { - var patchID = _.uniqueId('patch_'); - target.__patchID = patchID; - patches[patchID] = { - target: target, - otherPatchedProps: [], - ownPatchedProps: [], - }; - if (target.prototype) { - _.each(props, function (value, key) { - if (target.prototype.hasOwnProperty(key)) { - patches[patchID].ownPatchedProps.push({ - key: key, - initialValue: target.prototype[key], - }); - } else { - patches[patchID].otherPatchedProps.push(key); - } - }); - target.include(props); - } else { - _.each(props, function (value, key) { - if (key in target) { - var oldValue = target[key]; - patches[patchID].ownPatchedProps.push({ - key: key, - initialValue: oldValue, - }); - if (typeof value === 'function') { - target[key] = function () { - var oldSuper = this._super; - this._super = oldValue; - var result = value.apply(this, arguments); - if (oldSuper === undefined) { - delete this._super; - } else { - this._super = oldSuper; - } - return result; - }; - } else { - target[key] = value; - } - } else { - patches[patchID].otherPatchedProps.push(key); - target[key] = value; - } - }); - } -} - -/** - * Unpatches a given Class or Object. - * - * @param {Class|Object} target - */ -function unpatch(target) { - var patchID = target.__patchID; - var patch = patches[patchID]; - if (target.prototype) { - _.each(patch.ownPatchedProps, function (p) { - target.prototype[p.key] = p.initialValue; - }); - _.each(patch.otherPatchedProps, function (key) { - delete target.prototype[key]; - }); - } else { - _.each(patch.ownPatchedProps, function (p) { - target[p.key] = p.initialValue; - }); - _.each(patch.otherPatchedProps, function (key) { - delete target[key]; - }); - } - delete patches[patchID]; - delete target.__patchID; -} - -/** - * Opens the datepicker of a given element. - * - * @param {jQuery} $datepickerEl element to which a datepicker is attached - */ -function openDatepicker($datepickerEl) { - $datepickerEl.find('.o_datepicker_input').trigger('focus.datetimepicker'); -} +var testUtilsCreate = require('web.test_utils_create'); +var testUtilsDom = require('web.test_utils_dom'); +var testUtilsFields = require('web.test_utils_fields'); +var testUtilsForm = require('web.test_utils_form'); +var testUtilsGraph = require('web.test_utils_graph'); +var testUtilsKanban = require('web.test_utils_kanban'); +var testUtilsMock = require('web.test_utils_mock'); +var testUtilsModal = require('web.test_utils_modal'); +var testUtilsPivot = require('web.test_utils_pivot'); // Loading static files cannot be properly simulated when their real content is // really needed. This is the case for static XML files so we load them here, @@ -948,25 +38,67 @@ return $.when( QUnit.start(); }, 0); return { - addMockEnvironment: addMockEnvironment, - createActionManager: createActionManager, - createDebugManager: createDebugManager, - createAsyncView: createAsyncView, - createModel: createModel, - createParent: createParent, - createView: createView, - dragAndDrop: dragAndDrop, - fieldsViewGet: fieldsViewGet, - intercept: intercept, - observe: observe, - openDatepicker: openDatepicker, - patch: patch, - patchDate: patchDate, - removeSrcAttribute: removeSrcAttribute, - triggerKeypressEvent: triggerKeypressEvent, - triggerMouseEvent: triggerMouseEvent, - triggerPositionalMouseEvent: triggerPositionalMouseEvent, - unpatch: unpatch, + mock: { + addMockEnvironment: testUtilsMock.addMockEnvironment, + intercept: testUtilsMock.intercept, + patch: testUtilsMock.patch, + patchDate: testUtilsMock.patchDate, + unpatch: testUtilsMock.unpatch, + fieldsViewGet: testUtilsMock.fieldsViewGet, + }, + dom: { + triggerKeypressEvent: testUtilsDom.triggerKeypressEvent, + triggerMouseEvent: testUtilsDom.triggerMouseEvent, + triggerPositionalMouseEvent: testUtilsDom.triggerPositionalMouseEvent, + dragAndDrop: testUtilsDom.dragAndDrop, + openDatepicker: testUtilsDom.openDatepicker, + click: testUtilsDom.click, + clickFirst: testUtilsDom.clickFirst, + clickLast: testUtilsDom.clickLast, + }, + form: { + clickEdit: testUtilsForm.clickEdit, + clickSave: testUtilsForm.clickSave, + clickCreate: testUtilsForm.clickCreate, + clickDiscard: testUtilsForm.clickDiscard, + reload: testUtilsForm.reload, + }, + graph: { + reload: testUtilsGraph.reload, + }, + kanban: { + reload: testUtilsKanban.reload, + clickCreate: testUtilsKanban.clickCreate, + quickCreate: testUtilsKanban.quickCreate, + toggleGroupSettings: testUtilsKanban.toggleGroupSettings, + toggleRecordDropdown: testUtilsKanban.toggleRecordDropdown, + }, + modal: { + clickButton: testUtilsModal.clickButton, + }, + pivot: { + clickMeasure: testUtilsPivot.clickMeasure, + toggleMeasuresDropdown: testUtilsPivot.toggleMeasuresDropdown, + reload: testUtilsPivot.reload, + }, + fields: { + many2one: { + clickOpenDropdown: testUtilsFields.clickOpenM2ODropdown, + clickHighlightedItem: testUtilsFields.clickM2OHighlightedItem, + clickItem: testUtilsFields.clickM2OItem, + searchAndClickItem: testUtilsFields.searchAndClickM2OItem, + }, + editInput: testUtilsFields.editInput, + editSelect: testUtilsFields.editSelect, + editAndTrigger: testUtilsFields.editAndTrigger, + }, + + createActionManager: testUtilsCreate.createActionManager, + createDebugManager: testUtilsCreate.createDebugManager, + createAsyncView: testUtilsCreate.createAsyncView, + createView: testUtilsCreate.createView, + createModel: testUtilsCreate.createModel, + createParent: testUtilsCreate.createParent, }; }); diff --git a/addons/web/static/tests/helpers/test_utils_create.js b/addons/web/static/tests/helpers/test_utils_create.js new file mode 100644 index 00000000000..d4d4e2a6b55 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_create.js @@ -0,0 +1,288 @@ +odoo.define('web.test_utils_create', function (require) { +"use strict"; + +/** + * Create Test Utils + * + * This module defines various utility functions to help creating mock widgets + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + +var ActionManager = require('web.ActionManager'); +var config = require('web.config'); +var ControlPanel = require('web.ControlPanel'); +var dom = require('web.dom'); +var DebugManager = require('web.DebugManager'); +var testUtilsMock = require('web.test_utils_mock'); +var Widget = require('web.Widget'); + +/** + * create and return an instance of ActionManager with all rpcs going through a + * mock method using the data, actions and archs objects as sources. + * + * @param {Object} [params] + * @param {Object} [params.actions] the actions given to the mock server + * @param {Object} [params.archs] this archs given to the mock server + * @param {Object} [params.data] the business data given to the mock server + * @param {boolean} [params.debug] + * @param {function} [params.mockRPC] + * @returns {ActionManager} + */ +function createActionManager (params) { + params = params || {}; + var $target = $('#qunit-fixture'); + if (params.debug) { + $target = $('body'); + $target.addClass('debug'); + } + + var widget = new Widget(); + // when 'document' addon is installed, the sidebar does a 'search_read' on + // model 'ir_attachment' each time a record is open, so we monkey-patch + // 'mockRPC' to mute those RPCs, so that the tests can be written uniformly, + // whether or not 'document' is installed + var mockRPC = params.mockRPC; + _.extend(params, { + mockRPC: function (route, args) { + if (args.model === 'ir.attachment') { + return $.when([]); + } + if (mockRPC) { + return mockRPC.apply(this, arguments); + } + return this._super.apply(this, arguments); + }, + }); + testUtilsMock.addMockEnvironment(widget, _.defaults(params, { debounce: false })); + widget.prependTo($target); + widget.$el.addClass('o_web_client'); + if (config.device.isMobile) { + widget.$el.addClass('o_touch_device'); + } + + var userContext = params.context && params.context.user_context || {}; + var actionManager = new ActionManager(widget, userContext); + + var originalDestroy = ActionManager.prototype.destroy; + actionManager.destroy = function () { + actionManager.destroy = originalDestroy; + widget.destroy(); + }; + actionManager.appendTo(widget.$el); + + return actionManager; +} + +/** + * create a view from various parameters. Here, a view means a javascript + * instance of an AbstractView class, such as a form view, a list view or a + * kanban view. + * + * It returns the instance of the view, properly created, with all rpcs going + * through a mock method using the data object as source, and already loaded/ + * started. + * + * Most views can be tested synchronously (@see createView), but some view have + * external dependencies (like lazy loaded libraries). In that case, it is + * necessary to use this method. + * + * @param {Object} params + * @param {string} params.arch the xml (arch) of the view to be instantiated + * @param {any[]} [params.domain] the initial domain for the view + * @param {Object} [params.context] the initial context for the view + * @param {Object} [params.debug=false] if true, the widget will be appended in + * the DOM. Also, RPCs and uncaught OdooEvent will be logged + * @param {string[]} [params.groupBy] the initial groupBy for the view + * @param {integer} [params.fieldDebounce=0] the debounce value to use for the + * duration of the test. + * @param {AbstractView} params.View the class that will be instantiated + * @param {string} params.model a model name, will be given to the view + * @param {Object} params.intercepts an object with event names as key, and + * callback as value. Each key,value will be used to intercept the event. + * Note that this is particularly useful if you want to intercept events going + * up in the init process of the view, because there are no other way to do it + * after this method returns + * @returns {Deferred} resolves with the instance of the view + */ +function createAsyncView(params) { + var $target = $('#qunit-fixture'); + var widget = new Widget(); + if (params.debug) { + $target = $('body'); + $target.addClass('debug'); + } + + // add mock environment: mock server, session, fieldviewget, ... + var mockServer = testUtilsMock.addMockEnvironment(widget, params); + var viewInfo = testUtilsMock.fieldsViewGet(mockServer, params); + // create the view + var viewOptions = { + modelName: params.model || 'foo', + ids: 'res_id' in params ? [params.res_id] : undefined, + currentId: 'res_id' in params ? params.res_id : undefined, + domain: params.domain || [], + context: params.context || {}, + groupBy: params.groupBy || [], + }; + if (params.hasSelectors) { + viewOptions.hasSelectors = params.hasSelectors; + } + + _.extend(viewOptions, params.viewOptions); + + var view = new params.View(viewInfo, viewOptions); + + // reproduce the DOM environment of views + var $web_client = $('
').addClass('o_web_client').prependTo($target); + var controlPanel = new ControlPanel(widget); + controlPanel.appendTo($web_client); + var $content = $('
').addClass('o_content').appendTo($web_client); + + if (params.interceptsPropagate) { + _.each(params.interceptsPropagate, function (cb, name) { + testUtilsMock.intercept(widget, name, cb, true); + }); + } + + return view.getController(widget).then(function (view) { + // override the view's 'destroy' so that it calls 'destroy' on the widget + // instead, as the widget is the parent of the view and the mockServer. + view.__destroy = view.destroy; + view.destroy = function () { + // remove the override to properly destroy the view and its children + // when it will be called the second time (by its parent) + delete view.destroy; + widget.destroy(); + }; + + // link the view to the control panel + view.set_cp_bus(controlPanel.get_bus()); + + // render the view in a fragment as they must be able to render correctly + // without being in the DOM + var fragment = document.createDocumentFragment(); + return view.appendTo(fragment).then(function () { + dom.append($content, fragment, { + callbacks: [{ widget: view }], + in_DOM: true, + }); + view.$el.on('click', 'a', function (ev) { + ev.preventDefault(); + }); + + return view; + }); + }); +} + +/** + * Create and return an instance of DebugManager with all rpcs going through a + * mock method, assuming that the user has access rights, and is an admin. + * + * @param {Object} [params={}] + */ +function createDebugManager (params) { + params = params || {}; + var mockRPC = params.mockRPC; + _.extend(params, { + mockRPC: function (route, args) { + if (args.method === 'check_access_rights') { + return $.when(true); + } + if (args.method === 'xmlid_to_res_id') { + return $.when(true); + } + if (mockRPC) { + return mockRPC.apply(this, arguments); + } + return this._super.apply(this, arguments); + }, + session: { + user_has_group: function (group) { + if (group === 'base.group_no_one') { + return $.when(true); + } + return this._super.apply(this, arguments); + }, + }, + }); + var debugManager = new DebugManager(); + testUtilsMock.addMockEnvironment(debugManager, params); + return debugManager; +} + +/** + * create a model from given parameters. + * + * @param {Object} params This object will be given to addMockEnvironment, so + * any parameters from that method applies + * @param {Class} params.Model the model class to use + * @returns {Model} + */ +function createModel(params) { + var widget = new Widget(); + + var model = new params.Model(widget); + + testUtilsMock.addMockEnvironment(widget, params); + + // override the model's 'destroy' so that it calls 'destroy' on the widget + // instead, as the widget is the parent of the model and the mockServer. + model.destroy = function () { + // remove the override to properly destroy the model when it will be + // called the second time (by its parent) + delete model.destroy; + widget.destroy(); + }; + + return model; +} + +/** + * create a widget parent from given parameters. + * + * @param {Object} params This object will be given to addMockEnvironment, so + * any parameters from that method applies + * @returns {Widget} + */ +function createParent(params) { + var widget = new Widget(); + testUtilsMock.addMockEnvironment(widget, params); + return widget; +} + +/** + * create a view synchronously. This method uses the createAsyncView method. + * Most views are synchronous, so the deferred can be resolved immediately and + * this method will work. + * + * Be careful, if for some reason a view is async, this method will crash. + * @see createAsyncView + * + * @param {Object} params will be given to createAsyncView + * @returns {AbstractView} + */ +function createView(params) { + var view; + createAsyncView(params).then(function (result) { + view = result; + }); + if (!view) { + throw "The view that you are trying to create is async. Please use createAsyncView instead"; + } + return view; +} + + +return { + createActionManager: createActionManager, + createAsyncView: createAsyncView, + createDebugManager: createDebugManager, + createModel: createModel, + createParent: createParent, + createView: createView, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_dom.js b/addons/web/static/tests/helpers/test_utils_dom.js new file mode 100644 index 00000000000..b89f5a8eb5f --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_dom.js @@ -0,0 +1,235 @@ +odoo.define('web.test_utils_dom', function () { +"use strict"; + +/** + * DOM Test Utils + * + * This module defines various utility functions to help simulate DOM events. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + + +/** + * simulate a drag and drop operation between 2 jquery nodes: $el and $to. + * This is a crude simulation, with only the mousedown, mousemove and mouseup + * events, but it is enough to help test drag and drop operations with jqueryUI + * sortable. + * + * @param {jqueryElement} $el + * @param {jqueryElement} $to + * @param {Object} [options] + * @param {string|Object} [options.position='center'] target position: + * can either be one of {'top', 'bottom', 'left', 'right'} or + * an object with two attributes (top and left)) + * @param {boolean} [options.disableDrop=false] whether to trigger the drop action + * @param {boolean} [options.continueMove=false] whether to trigger the + * mousedown action (will only work after another call of this function with + * without this option) + */ +function dragAndDrop($el, $to, options) { + var position = (options && options.position) || 'center'; + var elementCenter = $el.offset(); + var toOffset = $to.offset(); + + if (_.isObject(position)) { + toOffset.top += position.top; + toOffset.left += position.left; + } else { + toOffset.top += $to.outerHeight() / 2; + toOffset.left += $to.outerWidth() / 2; + var vertical_offset = (toOffset.top < elementCenter.top) ? -1 : 1; + if (position === 'top') { + toOffset.top -= $to.outerHeight() / 2 + vertical_offset; + } else if (position === 'bottom') { + toOffset.top += $to.outerHeight() / 2 - vertical_offset; + } else if (position === 'left') { + toOffset.left -= $to.outerWidth() / 2; + } else if (position === 'right') { + toOffset.left += $to.outerWidth() / 2; + } + } + + if ($to[0].ownerDocument !== document) { + // we are in an iframe + var bound = $('iframe')[0].getBoundingClientRect(); + toOffset.left += bound.left; + toOffset.top += bound.top; + } + $el.trigger($.Event("mouseenter")); + if (!(options && options.continueMove)) { + elementCenter.left += $el.outerWidth() / 2; + elementCenter.top += $el.outerHeight() / 2; + + $el.trigger($.Event("mousedown", { + which: 1, + pageX: elementCenter.left, + pageY: elementCenter.top + })); + } + + $el.trigger($.Event("mousemove", { + which: 1, + pageX: toOffset.left, + pageY: toOffset.top + })); + + if (!(options && options.disableDrop)) { + $el.trigger($.Event("mouseup", { + which: 1, + pageX: toOffset.left, + pageY: toOffset.top + })); + } else { + // It's impossible to drag another element when one is already + // being dragged. So it's necessary to finish the drop when the test is + // over otherwise it's impossible for the next tests to drag and + // drop elements. + $el.on("remove", function () { + $el.trigger($.Event("mouseup")); + }); + } +} + +/** + * simulate a mouse event with a custom event who add the item position. This is + * sometimes necessary because the basic way to trigger an event (such as + * $el.trigger('mousemove')); ) is too crude for some uses. + * + * @param {jqueryElement} $el + * @param {string} type a mouse event type, such as 'mousedown' or 'mousemove' + */ +function triggerMouseEvent($el, type) { + var pos = $el.offset(); + var e = new $.Event(type); + e.pageX = e.layerX = e.screenX = pos.left; + e.pageY = e.layerY = e.screenY = pos.top; + e.which = 1; + $el.trigger(e); +} + +/** + * simulate a mouse event with a custom event on a position x and y. This is + * sometimes necessary because the basic way to trigger an event (such as + * $el.trigger('mousemove')); ) is too crude for some uses. + * + * @param {integer} x + * @param {integer} y + * @param {string} type a mouse event type, such as 'mousedown' or 'mousemove' + */ +function triggerPositionalMouseEvent(x, y, type) { + var ev = document.createEvent("MouseEvent"); + var el = document.elementFromPoint(x, y); + ev.initMouseEvent( + type, + true /* bubble */, + true /* cancelable */, + window, null, + x, y, x, y, /* coordinates */ + false, false, false, false, /* modifier keys */ + 0 /*left button*/, null + ); + el.dispatchEvent(ev); + return el; +} + +/** + * simulate a keypress event for a given character + * + * @param {string} char the character, or 'ENTER' + */ +function triggerKeypressEvent(char) { + var keycode; + if (char === "Enter") { + keycode = $.ui.keyCode.ENTER; + } else { + keycode = char.charCodeAt(0); + } + return $('body').trigger($.Event('keypress', { which: keycode, keyCode: keycode })); +} + +/** + * Opens the datepicker of a given element. + * + * @param {jQuery} $datepickerEl element to which a datepicker is attached + */ +function openDatepicker($datepickerEl) { + $datepickerEl.find('.o_datepicker_input').trigger('focus.datetimepicker'); +} + +/** + * Click on a specified element. If the option first or last is not specified, + * this method also check the unicity and the visibility of the target. + * + * @param {string|NodeList|jQuery} el (if string: it is a (jquery) selector) + * @param {Object} [options] + * @param {boolean} [options.first=false] if true, clicks on the first element + * @param {boolean} [options.last=false] if true, clicks on the last element + */ +function click(el, options) { + options = options || {}; + var matches = typeof el === 'string' ? $(el) : el; + var selectorMsg = el.selector ? `(selector: ${el.selector})` : ''; + if (!matches.filter) { // it might be an array of dom elements + matches = $(matches); + } + + var visibleMatches = matches.filter(':visible'); + if (options.first) { + if (visibleMatches.length === 1) { + throw new Error(`There should be more than one visible target ${selectorMsg}. If` + + ' you are sure that there is exactly one target, please use the ' + + 'click function instead of the clickFirst function'); + } + visibleMatches = visibleMatches.first(); + } else if (options.last) { + if (visibleMatches.length === 1) { + throw new Error(`There should be more than one visible target ${selectorMsg}. If` + + ' you are sure that there is exactly one target, please use the ' + + 'click function instead of the clickLast function'); + } + visibleMatches = visibleMatches.last(); + } + if (visibleMatches.length === 0 && matches.length > 0) { + throw new Error(`Element to click on is not visible ${selectorMsg}`); + } else if (visibleMatches.length !== 1) { + throw new Error(`Found ${visibleMatches.length} elements to click on, instead of 1 ${selectorMsg}`); + } + visibleMatches.click(); +} + +/** + * Click on the first element of a list of elements. Note that if the list has + * only one visible element, we trigger an error. In that case, it is better to + * use the click helper instead. + * + * @param {string|NodeList|jQuery} el (if string: it is a (jquery) selector) + */ +function clickFirst(el) { + click(el, {first: true}); +} + +/** + * Click on the last element of a list of elements. Note that if the list has + * only one visible element, we trigger an error. In that case, it is better to + * use the click helper instead. + * + * @param {string|NodeList|jQuery} el + */ +function clickLast(el) { + click(el, {last: true}); +} + +return { + triggerKeypressEvent: triggerKeypressEvent, + triggerMouseEvent: triggerMouseEvent, + triggerPositionalMouseEvent: triggerPositionalMouseEvent, + dragAndDrop: dragAndDrop, + openDatepicker: openDatepicker, + click: click, + clickFirst: clickFirst, + clickLast: clickLast, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_fields.js b/addons/web/static/tests/helpers/test_utils_fields.js new file mode 100644 index 00000000000..f7d8829ce82 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_fields.js @@ -0,0 +1,172 @@ +odoo.define('web.test_utils_fields', function (require) { +"use strict"; + +/** + * Field Test Utils + * + * This module defines various utility functions to help testing field widgets. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + +var concurrency = require('web.concurrency'); + +//------------------------------------------------------------------------------ +// Public functions +//------------------------------------------------------------------------------ + +/** + * Sets the value of an element and then, trigger all specified events. + * Note that this helper also checks the unicity of the target. + * + * Example: + * testUtils.fields.editAndTrigger($('selector'), 'test', ['input', 'change']); + * + * @param {jQuery} $el should target an input, textarea or select + * @param {string|number} value + * @param {string[]} events + */ +function editAndTrigger($el, value, events) { + if ($el.length !== 1) { + throw new Error(`target ${$el.selector} has length ${$el.length} instead of 1`); + } + $el.val(value); + events.forEach(function (event) { + $el.trigger(event); + }); +} + +/** + * Sets the value of an input. + * + * Note that this helper also checks the unicity of the target. + * + * Example: + * testUtils.fields.editInput($('selector'), 'somevalue'); + * + * @param {jQuery} $el + * @param {string|number} value + */ +function editInput($el, value) { + editAndTrigger($el, value, ['input']); +} + +/** + * Sets the value of a select. + * + * Note that this helper also checks the unicity of the target. + * + * Example: + * testUtils.fields.editSelect($('selector'), 'somevalue'); + * + * @param {jQuery} $el + * @param {string|number} value + */ +function editSelect($el, value) { + editAndTrigger($el, value, ['change']); +} + +/** + * Click to open the dropdown on a many2one + * + * @param {string} fieldName + * @param {[string]} selector if set, this will restrict the search for the m2o + * input + * @returns {HTMLInputElement} the main many2one input + */ +function clickOpenM2ODropdown(fieldName, selector) { + var m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`; + var matches = document.querySelectorAll(m2oSelector); + if (matches.length !== 1) { + throw new Error(`cannot open m2o: selector ${selector} has been found ${matches.length} instead of 1`); + } + matches[0].click(); + return matches[0]; +} + +/** + * Click on the active (highlighted) selection in a m2o dropdown. + * + * @param {string} fieldName + * @param {[string]} selector if set, this will restrict the search for the m2o + * input + */ +function clickM2OHighlightedItem(fieldName, selector) { + var m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`; + var $dropdown = $(m2oSelector).autocomplete('widget'); + // clicking on an li (no matter which one), will select the focussed one + $dropdown.find('li:first()').click(); +} + +/** + * Click on a menuitem in the m2o dropdown. This helper will target an element + * which contains some specific text. Note that it assumes that the dropdown + * is currently open. + * + * Example: + * testUtils.fields.many2one.clickM2OItem('partner_id', 'George'); + * + * @param {string} fieldName + * @param {string} searchText + */ +function clickM2OItem(fieldName, searchText) { + var m2oSelector = `.o_field_many2one[name=${fieldName}] input`; + var $dropdown = $(m2oSelector).autocomplete('widget'); + var $target = $dropdown.find(`li:contains(${searchText})`).first(); + if ($target.length !== 1 || !$target.is(':visible')) { + throw new Error('Menu item should be unique and visible'); + } + $target.mouseenter().click(); +} + +/** + * This helper is useful to test many2one fields. Here is what it does: + * - click to open the dropdown + * - enter a search string in the input + * - wait for the selection + * - click on the active menuitem + * + * Example: + * testUtils.fields.many2one.searchAndClickM2OItem('partner_id', 'George'); + * + * @param {string} fieldName + * @param {[Object]} options + * @param {[string]} options.selector + * @param {[string]} options.search + * @returns {Promise} + */ +function searchAndClickM2OItem(fieldName, options) { + options = options || {}; + + var input = clickOpenM2ODropdown(fieldName, options.selector); + + var def; + if (options.search) { + // jquery autocomplete refines the search in a setTimeout() parameterized + // with a delay, so we force this delay to 0 s.t. the dropdown is filtered + // directly on the next tick + var $input = $(input); + var delay = $input.autocomplete('option', 'delay'); + $input.autocomplete('option', 'delay', 0); + input.value = options.search; + input.dispatchEvent(new Event('input')); + $input.autocomplete('option', 'delay', delay); + def = concurrency.delay(0); + } + + return $.when(def).then(function () { + clickM2OHighlightedItem(fieldName, options.selector); + }); +} +return { + clickOpenM2ODropdown: clickOpenM2ODropdown, + clickM2OHighlightedItem: clickM2OHighlightedItem, + clickM2OItem: clickM2OItem, + editAndTrigger: editAndTrigger, + editInput: editInput, + editSelect: editSelect, + searchAndClickM2OItem: searchAndClickM2OItem, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_form.js b/addons/web/static/tests/helpers/test_utils_form.js new file mode 100644 index 00000000000..379350e1ca6 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_form.js @@ -0,0 +1,74 @@ +odoo.define('web.test_utils_form', function (require) { +"use strict"; + +/** + * Form Test Utils + * + * This module defines various utility functions to help test form views. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + +var testUtilsDom = require('web.test_utils_dom'); + +/** + * Clicks on the Edit button in a form view, to set it to edit mode. Note that + * it checks that the button is visible, so calling this method in edit mode + * will fail. + * + * @param {FormController} form + */ +function clickEdit(form) { + testUtilsDom.click(form.$buttons.find('.o_form_button_edit')); +} + +/** + * Clicks on the Save button in a form view. Note that this method checks that + * the Save button is visible. + * + * @param {FormController} form + */ +function clickSave(form) { + testUtilsDom.click(form.$buttons.find('.o_form_button_save')); +} + +/** + * Clicks on the Create button in a form view. Note that this method checks that + * the Create button is visible. + * + * @param {FormController} form + */ +function clickCreate(form) { + testUtilsDom.click(form.$buttons.find('.o_form_button_create')); +} + +/** + * Clicks on the Discard button in a form view. Note that this method checks that + * the Discard button is visible. + * + * @param {FormController} form + */ +function clickDiscard(form) { + testUtilsDom.click(form.$buttons.find('.o_form_button_cancel')); +} + +/** + * Reloads a form view. + * + * @param {FormController} form + * @param {[Object]} params given to the controller reload method + */ +function reload(form, params) { + form.reload(params); +} + +return { + clickEdit: clickEdit, + clickSave: clickSave, + clickCreate: clickCreate, + clickDiscard: clickDiscard, + reload: reload, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_graph.js b/addons/web/static/tests/helpers/test_utils_graph.js new file mode 100644 index 00000000000..8867f82c349 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_graph.js @@ -0,0 +1,28 @@ +odoo.define('web.test_utils_graph', function () { +"use strict"; + +/** + * Graph Test Utils + * + * This module defines various utility functions to help test graph views. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + + +/** + * Reloads a graph view. + * + * @param {GraphController} graph + * @param {[Object]} params given to the controller reload method + */ +function reload(graph, params) { + graph.reload(params); +} + +return { + reload: reload, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_kanban.js b/addons/web/static/tests/helpers/test_utils_kanban.js new file mode 100644 index 00000000000..166ae2a2572 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_kanban.js @@ -0,0 +1,97 @@ +odoo.define('web.test_utils_kanban', function (require) { +"use strict"; + +/** + * Kanban Test Utils + * + * This module defines various utility functions to help testing kanban views. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + +var testUtilsDom = require('web.test_utils_dom'); +var testUtilsFields = require('web.test_utils_fields'); + +/** + * Clicks on the Create button in a kanban view. Note that this method checks that + * the Create button is visible. + * + * @param {KanbanController} kanban + */ +function clickCreate(kanban) { + testUtilsDom.click(kanban.$buttons.find('.o-kanban-button-new')); +} + +/** + * Open the settings menu for a column (in a grouped kanban view) + * + * @param {jQuery} $column + */ +function toggleGroupSettings($column) { + var $dropdownToggler = $column.find('.o_kanban_config > a.dropdown-toggle'); + if (!$dropdownToggler.is(':visible')) { + $dropdownToggler.css('display', 'block'); + } + testUtilsDom.click($dropdownToggler); +} + +/** + * Edit a value in a quickcreate form view (this method assumes that the quick + * create feature is active, and a sub form view is open) + * + * @param {kanbanController} kanban + * @param {string|number} value + * @param {[string]} fieldName + */ +function quickCreate(kanban, value, fieldName) { + var additionalSelector = fieldName ? ('[name=' + fieldName + ']'): ''; + var enterEvent = $.Event( + 'keydown', + { + which: $.ui.keyCode.ENTER, + keyCode: $.ui.keyCode.ENTER, + } + ); + testUtilsFields.editAndTrigger( + kanban.$('.o_kanban_quick_create input' + additionalSelector), + value, + ['input', enterEvent] + ); +} + +/** + * Reloads a kanban view. + * + * @param {KanbanController} kanban + * @param {[Object]} params given to the controller reload method + */ +function reload(kanban, params) { + kanban.reload(params); +} + +/** + * Open the setting dropdown of a kanban record. Note that the template of a + * kanban record is not standardized, so this method will fail if the template + * does not comply with the usual dom structure. + * + * @param {jQuery} $record + */ +function toggleRecordDropdown($record) { + var $dropdownToggler = $record.find('.o_dropdown_kanban > a.dropdown-toggle'); + if (!$dropdownToggler.is(':visible')) { + $dropdownToggler.css('display', 'block'); + } + testUtilsDom.click($dropdownToggler); +} + + +return { + clickCreate: clickCreate, + quickCreate: quickCreate, + reload: reload, + toggleGroupSettings: toggleGroupSettings, + toggleRecordDropdown: toggleRecordDropdown, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_mock.js b/addons/web/static/tests/helpers/test_utils_mock.js new file mode 100644 index 00000000000..769c179472a --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_mock.js @@ -0,0 +1,545 @@ +odoo.define('web.test_utils_mock', function (require) { +"use strict"; + +/** + * Mock Test Utils + * + * This module defines various utility functions to help mocking data. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + +var basic_fields = require('web.basic_fields'); +var config = require('web.config'); +var core = require('web.core'); +var MockServer = require('web.MockServer'); +var session = require('web.session'); + +var DebouncedField = basic_fields.DebouncedField; + +//------------------------------------------------------------------------------ +// Private functions +//------------------------------------------------------------------------------ + +/** + * logs all event going through the target widget. + * + * @param {Widget} widget + */ +function _observe(widget) { + var _trigger_up = widget._trigger_up.bind(widget); + widget._trigger_up = function (event) { + console.log('%c[event] ' + event.name, 'color: blue; font-weight: bold;', event); + _trigger_up(event); + }; +} + +//------------------------------------------------------------------------------ +// Public functions +//------------------------------------------------------------------------------ + +/** + * Removes the src attribute on images and iframes to prevent not found errors, + * and optionally triggers an rpc with the src url as route on a widget. + * This method is critical and must be fastest (=> no jQuery, no underscore) + * + * @param {DOM Node} el + * @param {[Widget]} widget the widget on which the rpc should be performed + */ +function removeSrcAttribute(el, widget) { + var nodes; + if (el.nodeName === 'IMG' || el.nodeName === 'IFRAME') { + nodes = [el]; + } else { + nodes = Array.prototype.slice.call(el.getElementsByTagName('img')) + .concat(Array.prototype.slice.call(el.getElementsByTagName('iframe'))); + } + var node; + while (node = nodes.pop()) { + var src = node.attributes.src && node.attributes.src.value; + if (src && src !== 'about:blank') { + node.setAttribute('data-src', src); + if (node.nodeName === 'IMG') { + node.attributes.removeNamedItem('src'); + } else { + node.setAttribute('src', 'about:blank'); + } + if (widget) { + widget._rpc({ route: src }); + } + } + } +} + +/** + * Add a mock environment to a widget. This helper function can simulate + * various kind of side effects, such as mocking RPCs, changing the session, + * or the translation settings. + * + * The simulated environment lasts for the lifecycle of the widget, meaning it + * disappears when the widget is destroyed. It is particularly relevant for the + * session mocks, because the previous session is restored during the destroy + * call. So, it means that you have to be careful and make sure that it is + * properly destroyed before another test is run, otherwise you risk having + * interferences between tests. + * + * @param {Widget} widget + * @param {Object} params + * @param {Object} [params.archs] a map of string [model,view_id,view_type] to + * a arch object. It is used to mock answers to 'load_views' custom events. + * This is useful when the widget instantiate a formview dialog that needs + * to load a particular arch. + * @param {string} [params.currentDate] a string representation of the current + * date. It is given to the mock server. + * @param {Object} params.data the data given to the created mock server. It is + * used to generate mock answers for every kind of routes supported by odoo + * @param {number} [params.debug] if set to true, logs RPCs and uncaught Odoo + * events. + * @param {function} [params.mockRPC] a function that will be used to override + * the _performRpc method from the mock server. It is really useful to add + * some custom rpc mocks, or to check some assertions. + * @param {Object} [params.session] if it is given, it will be used as answer + * for all calls to this.getSession() by the widget, of its children. Also, + * it will be used to extend the current, real session. This side effect is + * undone when the widget is destroyed. + * @param {Object} [params.translateParameters] if given, it will be used to + * extend the core._t.database.parameters object. After the widget + * destruction, the original parameters will be restored. + * @param {Object} [params.intercepts] an object with event names as key, and + * callback as value. Each key,value will be used to intercept the event. + * Note that this is particularly useful if you want to intercept events going + * up in the init process of the view, because there are no other way to do it + * after this method returns. Some events ('call_service', "load_views", + * "get_session", "load_filters") have a special treatment beforehand. + * @param {Object} [params.services={}] list of services to load in + * addition to the ajax service. For instance, if a test needs the local + * storage service in order to work, it can provide a mock version of it. + * @param {boolean} [debounce=true] set to false to completely remove the + * debouncing, forcing the handler to be called directly (not on the next + * execution stack, like it does with delay=0). + * @param {boolean} [throttle=false] set to true to keep the throttling, which + * is completely removed by default. + * + * @returns {MockServer} the instance of the mock server, created by this + * function. It is necessary for createAsyncView so that method can call some + * other methods on it. + */ +function addMockEnvironment(widget, params) { + var Server = MockServer; + params.services = params.services || {}; + if (params.mockRPC) { + Server = MockServer.extend({ _performRpc: params.mockRPC }); + } + if (params.debug) { + _observe(widget); + var separator = window.location.href.indexOf('?') !== -1 ? "&" : "?"; + var url = window.location.href + separator + 'testId=' + QUnit.config.current.testId; + console.log('%c[debug] debug mode activated', 'color: blue; font-weight: bold;', url); + } + + var mockServer = new Server(params.data, { + actions: params.actions, + archs: params.archs, + currentDate: params.currentDate, + debug: params.debug, + widget: widget, + }); + + // make sure images do not trigger a GET on the server + $('body').on('DOMNodeInserted.removeSRC', function (event) { + removeSrcAttribute(event.target, widget); + }); + + // make sure the debounce value for input fields is set to 0 + var initialDebounceValue = DebouncedField.prototype.DEBOUNCE; + DebouncedField.prototype.DEBOUNCE = params.fieldDebounce || 0; + var initialSession, initialConfig, initialParameters, initialDebounce, initialThrottle; + initialSession = _.extend({}, session); + session.getTZOffset = function () { + return 0; // by default, but may be overriden in specific tests + }; + if ('session' in params) { + _.extend(session, params.session); + } + if ('config' in params) { + initialConfig = _.clone(config); + initialConfig.device = _.clone(config.device); + if ('device' in params.config) { + _.extend(config.device, params.config.device); + } + if ('debug' in params.config) { + config.debug = params.config.debug; + } + } + if ('translateParameters' in params) { + initialParameters = _.extend({}, core._t.database.parameters); + _.extend(core._t.database.parameters, params.translateParameters); + } + if (params.debounce === false) { + initialDebounce = _.debounce; + _.debounce = function (func) { + return func; + }; + } + if (!('throttle' in params) || !params.throttle) { + initialThrottle = _.throttle; + _.throttle = function (func) { + return func; + }; + } + + var widgetDestroy = widget.destroy; + widget.destroy = function () { + // clear the caches (e.g. data_manager, ModelFieldSelector) when the + // widget is destroyed, at the end of each test to avoid collisions + core.bus.trigger('clear_cache'); + + DebouncedField.prototype.DEBOUNCE = initialDebounceValue; + if (params.debounce === false) { + _.debounce = initialDebounce; + } + if (!('throttle' in params) || !params.throttle) { + _.throttle = initialThrottle; + } + + var key; + if ('session' in params) { + for (key in session) { + delete session[key]; + } + } + _.extend(session, initialSession); + if ('config' in params) { + for (key in config) { + delete config[key]; + } + _.extend(config, initialConfig); + } + if ('translateParameters' in params) { + for (key in core._t.database.parameters) { + delete core._t.database.parameters[key]; + } + _.extend(core._t.database.parameters, initialParameters); + } + + $('body').off('DOMNodeInserted.removeSRC'); + $('.blockUI').remove(); + + widgetDestroy.call(this); + }; + + // Dispatch service calls + // Note: some services could call other services at init, + // Which is why we have to init services after that + var services = {}; + intercept(widget, 'call_service', function (ev) { + var args, result; + if (services[ev.data.service]) { + var service = services[ev.data.service]; + args = (ev.data.args || []); + result = service[ev.data.method].apply(service, args); + } else if (ev.data.service === 'ajax') { + // use ajax service that is mocked by the server + var route = ev.data.args[0]; + args = ev.data.args[1]; + result = mockServer.performRpc(route, args); + } + ev.data.callback(result); + }); + + intercept(widget, 'load_action', function (event) { + mockServer.performRpc('/web/action/load', { + kwargs: { + action_id: event.data.actionID, + additional_context: event.data.context, + }, + }).then(function (action) { + event.data.on_success(action); + }); + }); + + intercept(widget, "load_views", function (event) { + mockServer.performRpc('/web/dataset/call_kw/' + event.data.modelName, { + args: [], + kwargs: { + context: event.data.context, + options: event.data.options, + views: event.data.views, + }, + method: 'load_views', + model: event.data.modelName, + }).then(function (views) { + views = _.mapObject(views, function (viewParams) { + return fieldsViewGet(mockServer, viewParams); + }); + event.data.on_success(views); + }); + }); + + intercept(widget, "get_session", function (event) { + event.data.callback(session); + }); + + intercept(widget, "load_filters", function (event) { + if (params.debug) { + console.log('[mock] load_filters', event.data); + } + event.data.on_success([]); + }); + + // make sure all Odoo events bubbling up are intercepted + if ('intercepts' in params) { + _.each(params.intercepts, function (cb, name) { + intercept(widget, name, cb); + }); + } + + // Deploy services + var done = false; + var servicesToDeploy = _.clone(params.services); + if (!servicesToDeploy.ajax) { + services.ajax = null; // use mocked ajax from mocked server + } + while (!done) { + var serviceName = _.findKey(servicesToDeploy, function (Service) { + return !_.some(Service.prototype.dependencies, function (depName) { + return !_.has(services, depName); + }); + }); + if (serviceName) { + var Service = servicesToDeploy[serviceName]; + var service = services[serviceName] = new Service(widget); + delete servicesToDeploy[serviceName]; + + intercept(service, "get_session", function (event) { + event.data.callback(session); + }); + + service.start(); + } else { + var serviceNames = _.keys(servicesToDeploy); + if (serviceNames.length) { + console.warn("Non loaded services:", serviceNames); + } + done = true; + } + } + + return mockServer; +} + +/** + * performs a fields_view_get, and mocks the postprocessing done by the + * data_manager to return an equivalent structure. + * + * @param {MockServer} server + * @param {Object} params + * @param {string} params.model + * @returns {Object} an object with 3 keys: arch, fields and viewFields + */ +function fieldsViewGet(server, params) { + var fieldsView = server.fieldsViewGet(params); + // mock the structure produced by the DataManager + fieldsView.viewFields = fieldsView.fields; + fieldsView.fields = server.fieldsGet(params.model); + return fieldsView; +} + +/** + * intercepts an event bubbling up the widget hierarchy. The event intercepted + * must be a "custom event", i.e. an event generated by the method 'trigger_up'. + * + * Note that this method really intercepts the event if @propagate is not set. + * It will not be propagated further, and even the handlers on the target will + * not fire. + * + * @param {Widget} widget the target widget (any Odoo widget) + * @param {string} eventName description of the event + * @param {function} fn callback executed when the even is intercepted + * @param {boolean} [propagate=false] + */ +function intercept(widget, eventName, fn, propagate) { + var _trigger_up = widget._trigger_up.bind(widget); + widget._trigger_up = function (event) { + if (event.name === eventName) { + fn(event); + if (!propagate) { return; } + } + _trigger_up(event); + }; +} + +/** + * Patch window.Date so that the time starts its flow from the provided Date. + * + * Usage: + * + * ``` + * var unpatchDate = testUtils.mock.patchDate(2018, 0, 10, 17, 59, 30) + * new window.Date(); // "Wed Jan 10 2018 17:59:30 GMT+0100 (Central European Standard Time)" + * ... // 5 hours delay + * new window.Date(); // "Wed Jan 10 2018 22:59:30 GMT+0100 (Central European Standard Time)" + * ... + * unpatchDate(); + * new window.Date(); // actual current date time + * ``` + * + * @param {integer} year + * @param {integer} month index of the month, starting from zero. + * @param {integer} day the day of the month. + * @param {integer} hours the digits for hours (24h) + * @param {integer} minutes + * @param {integer} seconds + * @returns {function} a callback to unpatch window.Date. + */ +function patchDate(year, month, day, hours, minutes, seconds) { + var RealDate = window.Date; + var actualDate = new RealDate(); + var fakeDate = new RealDate(year, month, day, hours, minutes, seconds); + var timeInterval = actualDate.getTime() - (fakeDate.getTime()); + + Date = (function (NativeDate) { + function Date(Y, M, D, h, m, s, ms) { + var length = arguments.length; + if (arguments.length > 0) { + var date = length == 1 && String(Y) === Y ? // isString(Y) + // We explicitly pass it through parse: + new NativeDate(Date.parse(Y)) : + // We have to manually make calls depending on argument + // length here + length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) : + length >= 6 ? new NativeDate(Y, M, D, h, m, s) : + length >= 5 ? new NativeDate(Y, M, D, h, m) : + length >= 4 ? new NativeDate(Y, M, D, h) : + length >= 3 ? new NativeDate(Y, M, D) : + length >= 2 ? new NativeDate(Y, M) : + length >= 1 ? new NativeDate(Y) : + new NativeDate(); + // Prevent mixups with unfixed Date object + date.constructor = Date; + return date; + } else { + var date = new NativeDate(); + var time = date.getTime(); + time -= timeInterval; + date.setTime(time); + return date; + } + } + + // Copy any custom methods a 3rd party library may have added + for (var key in NativeDate) { + Date[key] = NativeDate[key]; + } + + // Copy "native" methods explicitly; they may be non-enumerable + Date.now = NativeDate.now; + Date.UTC = NativeDate.UTC; + Date.prototype = NativeDate.prototype; + Date.prototype.constructor = Date; + + // Upgrade Date.parse to handle simplified ISO 8601 strings + Date.parse = NativeDate.parse; + return Date; + })(Date); + + return function () { window.Date = RealDate; }; +} + +var patches = {}; +/** + * Patches a given Class or Object with the given properties. + * + * @param {Class|Object} target + * @param {Object} props + */ +function patch(target, props) { + var patchID = _.uniqueId('patch_'); + target.__patchID = patchID; + patches[patchID] = { + target: target, + otherPatchedProps: [], + ownPatchedProps: [], + }; + if (target.prototype) { + _.each(props, function (value, key) { + if (target.prototype.hasOwnProperty(key)) { + patches[patchID].ownPatchedProps.push({ + key: key, + initialValue: target.prototype[key], + }); + } else { + patches[patchID].otherPatchedProps.push(key); + } + }); + target.include(props); + } else { + _.each(props, function (value, key) { + if (key in target) { + var oldValue = target[key]; + patches[patchID].ownPatchedProps.push({ + key: key, + initialValue: oldValue, + }); + if (typeof value === 'function') { + target[key] = function () { + var oldSuper = this._super; + this._super = oldValue; + var result = value.apply(this, arguments); + if (oldSuper === undefined) { + delete this._super; + } else { + this._super = oldSuper; + } + return result; + }; + } else { + target[key] = value; + } + } else { + patches[patchID].otherPatchedProps.push(key); + target[key] = value; + } + }); + } +} + +/** + * Unpatches a given Class or Object. + * + * @param {Class|Object} target + */ +function unpatch(target) { + var patchID = target.__patchID; + var patch = patches[patchID]; + if (target.prototype) { + _.each(patch.ownPatchedProps, function (p) { + target.prototype[p.key] = p.initialValue; + }); + _.each(patch.otherPatchedProps, function (key) { + delete target.prototype[key]; + }); + } else { + _.each(patch.ownPatchedProps, function (p) { + target[p.key] = p.initialValue; + }); + _.each(patch.otherPatchedProps, function (key) { + delete target[key]; + }); + } + delete patches[patchID]; + delete target.__patchID; +} + + +return { + addMockEnvironment: addMockEnvironment, + fieldsViewGet: fieldsViewGet, + intercept: intercept, + patchDate: patchDate, + patch: patch, + unpatch: unpatch, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_modal.js b/addons/web/static/tests/helpers/test_utils_modal.js new file mode 100644 index 00000000000..d2162aebfa0 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_modal.js @@ -0,0 +1,34 @@ +odoo.define('web.test_utils_modal', function (require) { +"use strict"; + +/** + * Modal Test Utils + * + * This module defines various utility functions to help test pivot views. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + +var core = require('web.core'); + +/** + * Click on a button in the footer of a modal (which contains a given string). + * Note that this method checks the unicity of the button. + * + * @param {string} text (in english: this method will perform the translation) + */ +function clickButton(text) { + var selector = `.modal-footer button:contains(${core._t(text)})`; + var $button = $(selector); + if ($button.length !== 1) { + throw new Error(`Found ${$button.length} button(s) containing '${text}'`); + } + $button.click(); +} + +return { + clickButton: clickButton, +}; + +}); diff --git a/addons/web/static/tests/helpers/test_utils_pivot.js b/addons/web/static/tests/helpers/test_utils_pivot.js new file mode 100644 index 00000000000..18a5a7307f3 --- /dev/null +++ b/addons/web/static/tests/helpers/test_utils_pivot.js @@ -0,0 +1,57 @@ +odoo.define('web.test_utils_pivot', function (require) { +"use strict"; + +var testUtilsDom = require('web.test_utils_dom'); + +/** + * Pivot Test Utils + * + * This module defines various utility functions to help test pivot views. + * + * Note that all methods defined in this module are exported in the main + * testUtils file. + */ + + +/** + * Select a measure by clicking on the corresponding dropdown item (in the + * control panel 'Measure' submenu). + * + * Note that this method assumes that the dropdown menu is open. + * @see toggleMeasuresDropdown + * + * @param {PivotController} pivot + * @param {string} measure + */ +function clickMeasure(pivot, measure) { + testUtilsDom.click(pivot.$buttons.find(`.dropdown-item[data-field=${measure}]`)); +} + +/** + * Open the 'Measure' dropdown menu (in the control panel) + * + * @see clickMeasure + * + * @param {PivotController} pivot + */ +function toggleMeasuresDropdown(pivot) { + testUtilsDom.click(pivot.$buttons.filter('.btn-group:first').find('> button')); +} + +/** + * Reloads a graph view. + * + * @param {PivotController} pivot + * @param {[Object]} params given to the controller reload method + */ +function reload(pivot, params) { + pivot.reload(params); +} + +return { + clickMeasure: clickMeasure, + reload: reload, + toggleMeasuresDropdown: toggleMeasuresDropdown, +}; + +}); diff --git a/addons/web/static/tests/services/notification_service_tests.js b/addons/web/static/tests/services/notification_service_tests.js index df3c1657c92..04c7ea5e1ef 100644 --- a/addons/web/static/tests/services/notification_service_tests.js +++ b/addons/web/static/tests/services/notification_service_tests.js @@ -11,7 +11,7 @@ var createView = testUtils.createView; QUnit.module('Services', { beforeEach: function () { - testUtils.patch(Notification, { + testUtils.mock.patch(Notification, { _autoCloseDelay: 0, _animationDelay: 0, }); @@ -31,7 +31,7 @@ QUnit.module('Services', { }; }, afterEach: function () { - testUtils.unpatch(Notification); + testUtils.mock.unpatch(Notification); } }, function () { QUnit.module('Notification'); @@ -91,7 +91,7 @@ QUnit.module('Services', { setTimeout(function () { assert.strictEqual($notification.is(':hidden'), false, "should not hide the notification automatically"); - $notification.find('.o_close').click(); + testUtils.dom.click($notification.find('.o_close')); setTimeout(function () { assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notification"); view.destroy(); @@ -125,8 +125,8 @@ QUnit.module('Services', { var done = assert.async(); assert.expect(2); - testUtils.unpatch(Notification); - testUtils.patch(Notification, { + testUtils.mock.unpatch(Notification); + testUtils.mock.patch(Notification, { _autoCloseDelay: 2500, _animationDelay: 0, }); @@ -142,7 +142,7 @@ QUnit.module('Services', { } }); assert.strictEqual(close, 0, "should wait to call onClose method once"); - $('body .o_notification_manager .o_notification .o_close').click(); + testUtils.dom.click($('body .o_notification_manager .o_notification .o_close')); setTimeout(function () { assert.strictEqual(close, 1, "should call onClose method once"); view.destroy(); @@ -189,14 +189,9 @@ QUnit.module('Services', { "
a0
b0
", "should display notification"); - $notification.find('.o_buttons button:contains(accept0)').click(); - $notification.find('.o_buttons button:contains(accept0)').click(); - $notification.find('.o_buttons button:contains(refuse0)').click(); - $notification.eq(0).find('.o_close').click(); - - $notification.find('.o_buttons button:contains(refuse1)').click(); - - $notification.eq(2).find('.o_close').click(); + testUtils.dom.click($notification.find('.o_buttons button:contains(accept0)')); + testUtils.dom.click($notification.find('.o_buttons button:contains(refuse1)')); + testUtils.dom.click($notification.eq(2).find('.o_close')); setTimeout(function () { assert.strictEqual($notification.is(':hidden'), true, "should hide the notification"); @@ -211,8 +206,8 @@ QUnit.module('Services', { var done = assert.async(); assert.expect(2); - testUtils.unpatch(Notification); - testUtils.patch(Notification, { + testUtils.mock.unpatch(Notification); + testUtils.mock.patch(Notification, { _autoCloseDelay: 2500, _animationDelay: 0, }); diff --git a/addons/web/static/tests/tools/debug_manager_tests.js b/addons/web/static/tests/tools/debug_manager_tests.js index cf31d085a50..6929d55cce5 100644 --- a/addons/web/static/tests/tools/debug_manager_tests.js +++ b/addons/web/static/tests/tools/debug_manager_tests.js @@ -81,7 +81,8 @@ QUnit.module('DebugManager', {}, function () { assert.strictEqual($attachmentMenu.length, 1, "should have Manage Attachments menu item"); assert.strictEqual($attachmentMenu.text().trim(), "Manage Attachments", "should have correct menu item text"); - $attachmentMenu.click(); + testUtils.dom.click(debugManager.$('> a')); // open dropdown + testUtils.dom.click($attachmentMenu); debugManager.destroy(); }); @@ -152,14 +153,15 @@ QUnit.module('DebugManager', {}, function () { debugManager.update('action', action, form); // click on set_defaults dropdown - debugManager.$('a[data-action="set_defaults"]').click(); + testUtils.dom.click(debugManager.$('> a')); // open dropdown + testUtils.dom.click(debugManager.$('a[data-action="set_defaults"]')); var $modal = $('.modal-content'); assert.strictEqual($modal.length, 1, 'One modal present'); $modal.find('select[id=formview_default_fields] option[value=foo]').prop('selected', true); // Save - $modal.find('.modal-footer button').eq(1).click(); + testUtils.dom.click($modal.find('.modal-footer button').eq(1)); form.destroy(); debugManager.destroy(); diff --git a/addons/web/static/tests/views/abstract_controller_tests.js b/addons/web/static/tests/views/abstract_controller_tests.js index c9b7daa45dc..cf5810219c7 100644 --- a/addons/web/static/tests/views/abstract_controller_tests.js +++ b/addons/web/static/tests/views/abstract_controller_tests.js @@ -64,8 +64,8 @@ odoo.define("base.abstract_controller_tests", function(require) { } } }); - view.$(".simple").click(); - view.$(".with-child span").click(); + testUtils.dom.click(view.$(".simple")); + testUtils.dom.click(view.$(".with-child span")); assert.verifySteps(["a1", "a2"]); } ); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 7ed0c3914ee..9f421e9c6e9 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -172,15 +172,15 @@ QUnit.module('Views', { // test view scales - assert.strictEqual(calendar.$('.fc-event').length, 9, "should display 9 events on the week (4 event + 5 days event)"); + assert.containsN(calendar, '.fc-event', 9, "should display 9 events on the week (4 event + 5 days event)"); assert.strictEqual($sidebar.find('.o_selected_range').length, 7, "week scale should highlight 7 days in mini calendar"); calendar.$buttons.find('.o_calendar_button_day').trigger('click'); // display only one day - assert.strictEqual(calendar.$('.fc-event').length, 2, "should display 2 events on the day"); + assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day"); assert.strictEqual($sidebar.find('.o_selected_range').length, 1, "should highlight the target day in mini calendar"); calendar.$buttons.find('.o_calendar_button_month').trigger('click'); // display all the month - assert.strictEqual(calendar.$('.fc-event').length, 7, "should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')"); + assert.containsN(calendar, '.fc-event', 7, "should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')"); assert.strictEqual($sidebar.find('.o_selected_range').length, 31, "month scale should highlight all days in mini calendar"); // test filters @@ -200,12 +200,12 @@ QUnit.module('Views', { assert.strictEqual($attendeesFilter.find('.o_calendar_filter_item').length, 3, "should display 3 filter items for 'attendees' who use write_model (2 saved + Everything)"); assert.ok($attendeesFilter.find('.o_field_many2one').length, "should display one2many search bar for 'attendees' filter"); - assert.strictEqual(calendar.$('.fc-event').length, 7, + assert.containsN(calendar, '.fc-event', 7, "should display 7 events ('event 5' counts for 2 because it spans two weeks and thus generate two fc-event elements)"); - calendar.$('.o_calendar_filter .custom-checkbox input').first().click(); // Disable first filter - assert.strictEqual(calendar.$('.fc-event').length, 4, "should now only display 4 event"); - calendar.$('.o_calendar_filter .custom-checkbox input').eq(1).click(); // Disable second filter - assert.strictEqual(calendar.$('.fc-event').length, 0, "should not display any event anymore"); + testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').first()); + assert.containsN(calendar, '.fc-event', 4, "should now only display 4 event"); + testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').eq(1)); + assert.containsNone(calendar, '.fc-event', "should not display any event anymore"); // test search bar in filter $sidebar.find('input[type="text"]').trigger('click'); @@ -257,12 +257,12 @@ QUnit.module('Views', { 'Meetings Test (Dec 11 – 17, 2016)', "should display the current week"); // switch to day mode - actionManager.controlPanel.$('.o_calendar_button_day').click(); + testUtils.dom.click(actionManager.controlPanel.$('.o_calendar_button_day')); assert.strictEqual(actionManager.controlPanel.$('.breadcrumb-item').text(), 'Meetings Test (December 12, 2016)', "should display the current day"); // switch to month mode - actionManager.controlPanel.$('.o_calendar_button_month').click(); + testUtils.dom.click(actionManager.controlPanel.$('.o_calendar_button_month')); assert.strictEqual(actionManager.controlPanel.$('.breadcrumb-item').text(), 'Meetings Test (December 2016)', "should display the current month"); @@ -308,7 +308,7 @@ QUnit.module('Views', { assert.ok($('.modal-body').length, "should switch the modal in edit mode"); assert.notOk($('.modal-footer button.btn:contains(Delete)').length, "formViewDialog should not have a delete button in edit mode"); - $('.modal-body input:first').val('event 4 modified').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'event 4 modified'); $('.modal-footer button.btn:contains(Save)').trigger('click'); assert.notOk($('.modal-body').length, "save button should close the modal"); @@ -318,21 +318,21 @@ QUnit.module('Views', { var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); assert.ok($('.modal-sm').length, "should open the quick create dialog"); - $('.modal-body input:first').val('new event in quick create').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create'); $('.modal-footer button.btn:contains(Create)').trigger('click').trigger('click'); assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1, "should display the new record after quick create"); - assert.strictEqual(calendar.$('td.fc-event-container[colspan]').length, 2, "should the new record have only one day"); + assert.containsN(calendar, 'td.fc-event-container[colspan]', 2, "should the new record have only one day"); // create a new event, quick create only (validated by pressing enter key) - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); assert.ok($('.modal-sm').length, "should open the quick create dialog"); @@ -348,12 +348,12 @@ QUnit.module('Views', { $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); assert.strictEqual($('.modal-sm').length, 1, "should open the quick create dialog"); - $('.modal-body input:first').val('coucou').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou'); $('.modal-footer button.btn:contains(Edit)').trigger('click'); assert.strictEqual($('.modal-lg .o_form_view').length, 1, "should open the slow create dialog"); @@ -370,11 +370,11 @@ QUnit.module('Views', { $cell = calendar.$('.fc-day-grid .fc-row:eq(3) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell.next(), "mousemove"); - testUtils.triggerMouseEvent($cell.next(), "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell.next(), "mousemove"); + testUtils.dom.triggerMouseEvent($cell.next(), "mouseup"); - $('.modal-dialog input:first').val('new event in quick create 2').trigger('input'); + testUtils.fields.editInput($('.modal-dialog input:first'), 'new event in quick create 2'); $('.modal-footer button.btn:contains(Edit)').trigger('click'); assert.strictEqual($('.modal-lg input:first').val(), 'new event in quick create 2', "should open the formViewDialog with default values"); @@ -384,7 +384,7 @@ QUnit.module('Views', { assert.notOk($('.modal').length, "should close dialogs"); var $newevent2 = calendar.$('.fc-event:contains(new event in quick create 2)'); assert.ok($newevent2.length, "should display the 2 days new record"); - assert.strictEqual($newevent2.closest('.fc-event-container').attr('colspan'), "2", "the new record should have 2 days"); + assert.hasAttrValue($newevent2.closest('.fc-event-container'), 'colspan', "2", "the new record should have 2 days"); // delete the a record @@ -394,11 +394,11 @@ QUnit.module('Views', { $('.modal-footer button.btn:contains(Ok)').trigger('click'); assert.notOk(calendar.$('.fc-event:contains(event 4) .fc-content').length, "the record should be deleted"); - assert.strictEqual(calendar.$('.fc-event-container .fc-event').length, 10, "should display 10 events"); + assert.containsN(calendar, '.fc-event-container .fc-event', 10, "should display 10 events"); // move to next month - calendar.$buttons.find('.o_calendar_button_next').click(); + testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_next')); - assert.strictEqual(calendar.$('.fc-event-container .fc-event').length, 0, "should display 0 events"); + assert.containsNone(calendar, '.fc-event-container .fc-event', "should display 0 events"); calendar.destroy(); }); @@ -440,13 +440,13 @@ QUnit.module('Views', { // create a new event var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); assert.strictEqual($('.modal-sm .modal-title').text(), 'Create: Events', "should open the quick create dialog"); - $('.modal-body input:first').val('new event in quick create').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create'); $('.modal-footer button.btn:contains(Create)').trigger('click').trigger('click'); // If the event is not default-prevented, a traceback will be raised, which we do not want @@ -515,20 +515,20 @@ QUnit.module('Views', { var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } - testUtils.triggerPositionalMouseEvent(left, top + 60, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove"); assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "08:00 - 10:00", "should display the time in the calendar sticker"); - testUtils.triggerPositionalMouseEvent(left, top + 60, "mouseup"); - $('.modal input:first').val('new event').trigger('input'); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup"); + testUtils.fields.editInput($('.modal input:first'), 'new event'); $('.modal button.btn:contains(Create)').trigger('click'); var $newevent = calendar.$('.fc-event:contains(new event)'); @@ -551,7 +551,7 @@ QUnit.module('Views', { $newevent.trigger('click'); $('.modal button.btn-secondary:contains(Delete)').trigger('click'); $('.modal button.btn-primary:contains(Ok)').trigger('click'); - assert.strictEqual(calendar.$('.fc-content').length, 0, "should delete the record"); + assert.containsNone(calendar, '.fc-content', "should delete the record"); calendar.destroy(); $view.remove(); @@ -624,15 +624,15 @@ QUnit.module('Views', { var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } - testUtils.triggerPositionalMouseEvent(left, top + 60, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top + 60, "mouseup"); - $('.modal input:first').val('new event').trigger('input'); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup"); + testUtils.fields.editInput($('.modal input:first'), 'new event'); $('.modal button.btn:contains(Edit)').trigger('click'); assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 08:00:00", @@ -649,14 +649,14 @@ QUnit.module('Views', { "should display the datetime from the date with the timezone"); // use datepicker to enter a date: 12/13/2016 08:00:00 - testUtils.openDatepicker($('.o_field_widget[name="start"].o_datepicker')); + testUtils.dom.openDatepicker($('.o_field_widget[name="start"].o_datepicker')); $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)').trigger('click'); $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click'); // use datepicker to enter a date: 12/13/2016 10:00:00 - testUtils.openDatepicker($('.o_field_widget[name="stop"].o_datepicker')); + testUtils.dom.openDatepicker($('.o_field_widget[name="stop"].o_datepicker')); $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)').trigger('click'); @@ -689,10 +689,10 @@ QUnit.module('Views', { "start": "2016-12-12 06:00:00", "stop": "2016-12-12 08:00:00" }; - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); left = calendar.$('.fc-day:eq(1)').offset().left + 5; - testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup"); // Move to "All day" expectedEvent = { @@ -700,10 +700,10 @@ QUnit.module('Views', { "start": "2016-12-12 00:00:00", "stop": "2016-12-12 00:00:00" }; - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); top = calendar.$('.fc-day:eq(1)').offset().top + 5; - testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup"); calendar.destroy(); $view.remove(); @@ -764,20 +764,20 @@ QUnit.module('Views', { var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } - testUtils.triggerPositionalMouseEvent(left, top + 60, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove"); assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "8:00am - 10:00am", "should display the time in the calendar sticker"); - testUtils.triggerPositionalMouseEvent(left, top + 60, "mouseup"); - $('.modal input:first').val('new event').trigger('input'); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup"); + testUtils.fields.editInput($('.modal input:first'), 'new event'); $('.modal button.btn:contains(Create)').trigger('click'); var $newevent = calendar.$('.fc-event:contains(new event)'); @@ -800,7 +800,7 @@ QUnit.module('Views', { $newevent.trigger('click'); $('.modal button.btn-secondary:contains(Delete)').trigger('click'); $('.modal button.btn-primary:contains(Ok)').trigger('click'); - assert.strictEqual(calendar.$('.fc-content').length, 0, "should delete the record"); + assert.containsNone(calendar, '.fc-content', "should delete the record"); calendar.destroy(); $view.remove(); @@ -873,15 +873,15 @@ QUnit.module('Views', { var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } - testUtils.triggerPositionalMouseEvent(left, top + 60, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top + 60, "mouseup"); - $('.modal input:first').val('new event').trigger('input'); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup"); + testUtils.fields.editInput($('.modal input:first'), 'new event'); $('.modal button.btn:contains(Edit)').trigger('click'); assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 08:00:00", @@ -898,14 +898,14 @@ QUnit.module('Views', { "should display the datetime from the date with the timezone"); // use datepicker to enter a date: 12/13/2016 08:00:00 - testUtils.openDatepicker($('.o_field_widget[name="start"].o_datepicker')); + testUtils.dom.openDatepicker($('.o_field_widget[name="start"].o_datepicker')); $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)').trigger('click'); $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click'); // use datepicker to enter a date: 12/13/2016 10:00:00 - testUtils.openDatepicker($('.o_field_widget[name="stop"].o_datepicker')); + testUtils.dom.openDatepicker($('.o_field_widget[name="stop"].o_datepicker')); $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click'); $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)').trigger('click'); @@ -938,10 +938,10 @@ QUnit.module('Views', { "start": "2016-12-12 06:00:00", "stop": "2016-12-12 08:00:00" }; - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); left = calendar.$('.fc-day:eq(1)').offset().left + 5; - testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup"); // Move to "All day" expectedEvent = { @@ -949,10 +949,10 @@ QUnit.module('Views', { "start": "2016-12-12 00:00:00", "stop": "2016-12-12 00:00:00" }; - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); top = calendar.$('.fc-day:eq(1)').offset().top + 5; - testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup"); calendar.destroy(); $view.remove(); @@ -1021,23 +1021,23 @@ QUnit.module('Views', { var pos = calendar.$('.fc-bg td:eq(4)').offset(); try { - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } pos = calendar.$('.fc-bg td:eq(5)').offset(); - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); - $('.modal input:first').val('new event').trigger('input'); + testUtils.fields.editInput($('.modal input:first'), 'new event'); $('.modal button.btn:contains(Create)').trigger('click'); var $newevent = calendar.$('.fc-event:contains(new event)'); assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "newevent", "should display the new event with time and title"); - assert.strictEqual($newevent.parent().attr('colspan'), "2", + assert.hasAttrValue($newevent.parent(), 'colspan', "2", "should appear over two days."); assert.deepEqual($newevent.data('fcSeg').event.record, @@ -1100,15 +1100,15 @@ QUnit.module('Views', { var pos = calendar.$('.fc-bg td:eq(4)').offset(); try { - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } pos = calendar.$('.fc-bg td:eq(5)').offset(); - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); calendar.destroy(); $view.remove(); @@ -1159,23 +1159,23 @@ QUnit.module('Views', { var pos = calendar.$('.fc-bg td:eq(20)').offset(); try { - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } pos = calendar.$('.fc-bg td:eq(21)').offset(); - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); - testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); - $('.modal input:first').val('new event').trigger('input'); + testUtils.fields.editInput($('.modal input:first'), 'new event'); $('.modal button.btn:contains(Create)').trigger('click'); var $newevent = calendar.$('.fc-event:contains(new event)'); assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "newevent", "should display the new event with time and title"); - assert.strictEqual($newevent.parent().attr('colspan'), "2", + assert.hasAttrValue($newevent.parent(), 'colspan', "2", "should appear over two days."); assert.deepEqual($newevent.data('fcSeg').event.record, { @@ -1218,26 +1218,26 @@ QUnit.module('Views', { }, }); - assert.strictEqual(calendar.$('.fc-agendaWeek-view').length, 1, "should be in week mode"); - assert.strictEqual(calendar.$('.fc-event').length, 9, "should display 9 events on the week (4 event + 5 days event)"); - calendar.$('.o_calendar_mini a:contains(19)').click(); + assert.containsOnce(calendar, '.fc-agendaWeek-view', "should be in week mode"); + assert.containsN(calendar, '.fc-event', 9, "should display 9 events on the week (4 event + 5 days event)"); + testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(19)')); // Clicking on a day in another week should switch to the other week view - assert.strictEqual(calendar.$('.fc-agendaWeek-view').length, 1, "should be in week mode"); - assert.strictEqual(calendar.$('.fc-event').length, 4, "should display 4 events on the week (1 event + 3 days event)"); + assert.containsOnce(calendar, '.fc-agendaWeek-view', "should be in week mode"); + assert.containsN(calendar, '.fc-event', 4, "should display 4 events on the week (1 event + 3 days event)"); // Clicking on a day in the same week should switch to that particular day view - calendar.$('.o_calendar_mini a:contains(18)').click(); - assert.strictEqual(calendar.$('.fc-agendaDay-view').length, 1, "should be in day mode"); - assert.strictEqual(calendar.$('.fc-event').length, 2, "should display 2 events on the day"); + testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)')); + assert.containsOnce(calendar, '.fc-agendaDay-view', "should be in day mode"); + assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day"); // Clicking on the same day should toggle between day, month and week views - calendar.$('.o_calendar_mini a:contains(18)').click(); - assert.strictEqual(calendar.$('.fc-month-view').length, 1, "should be in month mode"); - assert.strictEqual(calendar.$('.fc-event').length, 7, "should display 7 events on the month (event 5 is on multiple weeks and generates to .fc-event)"); - calendar.$('.o_calendar_mini a:contains(18)').click(); - assert.strictEqual(calendar.$('.fc-agendaWeek-view').length, 1, "should be in week mode"); - assert.strictEqual(calendar.$('.fc-event').length, 4, "should display 4 events on the week (1 event + 3 days event)"); - calendar.$('.o_calendar_mini a:contains(18)').click(); - assert.strictEqual(calendar.$('.fc-agendaDay-view').length, 1, "should be in day mode"); - assert.strictEqual(calendar.$('.fc-event').length, 2, "should display 2 events on the day"); + testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)')); + assert.containsOnce(calendar, '.fc-month-view', "should be in month mode"); + assert.containsN(calendar, '.fc-event', 7, "should display 7 events on the month (event 5 is on multiple weeks and generates to .fc-event)"); + testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)')); + assert.containsOnce(calendar, '.fc-agendaWeek-view', "should be in week mode"); + assert.containsN(calendar, '.fc-event', 4, "should display 4 events on the week (1 event + 3 days event)"); + testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)')); + assert.containsOnce(calendar, '.fc-agendaDay-view', "should be in day mode"); + assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day"); calendar.destroy(); }); @@ -1267,7 +1267,7 @@ QUnit.module('Views', { }, }); - assert.strictEqual(calendar.$('.o_calendar_filter_items .o_cal_avatar').length, 3, + assert.containsN(calendar, '.o_calendar_filter_items .o_cal_avatar', 3, "should have 3 avatars in the side bar"); var $event1Avatars = calendar.$('.fc-event .o_calendar_avatars').first(); @@ -1313,7 +1313,7 @@ QUnit.module('Views', { // click on an existing event to open the form view - testUtils.intercept(calendar, 'do_action', function (event) { + testUtils.mock.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, { type: "ir.actions.act_window", @@ -1330,11 +1330,11 @@ QUnit.module('Views', { // create a new event and edit it var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou'); - testUtils.intercept(calendar, 'do_action', function (event) { + testUtils.mock.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, { type: "ir.actions.act_window", @@ -1387,11 +1387,11 @@ QUnit.module('Views', { // create a new event and edit it var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou'); - testUtils.intercept(calendar, 'do_action', function (event) { + testUtils.mock.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, { type: "ir.actions.act_window", @@ -1444,11 +1444,11 @@ QUnit.module('Views', { }, }); - assert.strictEqual(calendar.$('.fc-resizer').length, 0, "should not have resize button"); + assert.containsNone(calendar, '.fc-resizer', "should not have resize button"); // click on an existing event to open the form view - testUtils.intercept(calendar, 'do_action', function (event) { + testUtils.mock.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, { type: "ir.actions.act_window", @@ -1465,11 +1465,11 @@ QUnit.module('Views', { // create a new event and edit it var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou'); - testUtils.intercept(calendar, 'do_action', function (event) { + testUtils.mock.intercept(calendar, 'do_action', function (event) { assert.deepEqual(event.data.action, { type: "ir.actions.act_window", @@ -1538,17 +1538,17 @@ QUnit.module('Views', { }, }); - assert.strictEqual(calendar.$('.fc-event').length, 9, + assert.containsN(calendar, '.fc-event', 9, "should display 9 events on the week"); // Select the events only associated with partner 2 - calendar.$('.o_calendar_filter_item[data-id=2] input').click(); - assert.strictEqual(calendar.$('.fc-event').length, 4, + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-id=2] input')); + assert.containsN(calendar, '.fc-event', 4, "should display 4 events on the week"); // Click on the 'all' filter to reload all events - calendar.$('.o_calendar_filter_item[data-value=all] input').click(); - assert.strictEqual(calendar.$('.fc-event').length, 9, + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=all] input')); + assert.containsN(calendar, '.fc-event', 9, "should display 9 events on the week"); calendar.destroy(); @@ -1586,29 +1586,29 @@ QUnit.module('Views', { var $view = $('#qunit-fixture').contents(); $view.prependTo('body'); // => select with click position - calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input')); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 5, "should display 5 filter items"); - assert.strictEqual(calendar.$('.fc-event').length, 3, "should display 3 events"); + assert.containsN(calendar, '.o_calendar_filter_item', 5, "should display 5 filter items"); + assert.containsN(calendar, '.fc-event', 3, "should display 3 events"); // quick create a record var left = calendar.$('.fc-bg td:eq(4)').offset().left+15; var top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } - testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou'); $('.modal-footer button.btn:contains(Create)').trigger('click'); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); - assert.strictEqual(calendar.$('.fc-event').length, 4, "should display the created item"); + assert.containsN(calendar, '.o_calendar_filter_item', 6, "should add the missing filter (active)"); + assert.containsN(calendar, '.fc-event', 4, "should display the created item"); // change default value for quick create an hide record this.data.event.fields.user_id.default = 4; @@ -1617,19 +1617,19 @@ QUnit.module('Views', { // quick create and other record left = calendar.$('.fc-bg td:eq(3)').offset().left+15; top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15; - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); - testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mouseup"); - $('.modal-body input:first').val('coucou 2').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou 2'); $('.modal-footer button.btn:contains(Create)').trigger('click'); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should have the same filters"); - assert.strictEqual(calendar.$('.fc-event').length, 4, "should not display the created item"); + assert.containsN(calendar, '.o_calendar_filter_item', 6, "should have the same filters"); + assert.containsN(calendar, '.fc-event', 4, "should not display the created item"); - calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input')); - assert.strictEqual(calendar.$('.fc-event').length, 11, "should display all records"); + assert.containsN(calendar, '.fc-event', 11, "should display all records"); calendar.destroy(); $view.remove(); @@ -1683,31 +1683,31 @@ QUnit.module('Views', { var $view = $('#qunit-fixture').contents(); $view.prependTo('body'); // => select with click position - calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input')); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 5, "should display 5 filter items"); - assert.strictEqual(calendar.$('.fc-event').length, 3, "should display 3 events"); + assert.containsN(calendar, '.o_calendar_filter_item', 5, "should display 5 filter items"); + assert.containsN(calendar, '.fc-event', 3, "should display 3 events"); // quick create a record var left = calendar.$('.fc-bg td:eq(4)').offset().left+15; var top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); } catch (e) { calendar.destroy(); $view.remove(); throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); } - testUtils.triggerPositionalMouseEvent(left, top + 200, "mousemove"); - testUtils.triggerPositionalMouseEvent(left, top + 200, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mousemove"); + testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mouseup"); - $('.modal-body input:first').val('coucou').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'coucou'); $('.modal-footer button.btn:contains(Edit)').trigger('click'); $('.modal-footer button.btn:contains(Save)').trigger('click'); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); - assert.strictEqual(calendar.$('.fc-event').length, 4, "should display the created item"); + assert.containsN(calendar, '.o_calendar_filter_item', 6, "should add the missing filter (active)"); + assert.containsN(calendar, '.fc-event', 4, "should display the created item"); calendar.destroy(); $view.remove(); @@ -1763,10 +1763,10 @@ QUnit.module('Views', { }, }); - calendar.$('.o_calendar_filter_item[data-value=4] input').click(); + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input')); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 5, "should display 5 filter items"); - assert.strictEqual(calendar.$('.fc-event').length, 3, "should display 3 events"); + assert.containsN(calendar, '.o_calendar_filter_item', 5, "should display 5 filter items"); + assert.containsN(calendar, '.fc-event', 3, "should display 3 events"); calendar.$('.fc-event:contains(event 2) .fc-content').trigger('click'); $('.modal button.btn:contains(Edit)').trigger('click'); @@ -1774,8 +1774,8 @@ QUnit.module('Views', { $('.ui-menu-item a:contains(user 5)').trigger('mouseenter').trigger('click'); $('.modal button.btn:contains(Save)').trigger('click'); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should add the missing filter (active)"); - assert.strictEqual(calendar.$('.fc-event').length, 3, "should display the updated item"); + assert.containsN(calendar, '.o_calendar_filter_item', 6, "should add the missing filter (active)"); + assert.containsN(calendar, '.fc-event', 3, "should display the updated item"); calendar.destroy(); }); @@ -1842,11 +1842,11 @@ QUnit.module('Views', { }, }); - calendar.$('.o_calendar_filter_item[data-value=4] input').click(); - $('.o_calendar_button_prev').click(); + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input')); + testUtils.dom.click($('.o_calendar_button_prev')); - assert.strictEqual(calendar.$('.o_calendar_filter_item').length, 6, "should display 6 filter items"); - assert.strictEqual(calendar.$('.fc-event').length, 2, "should display 2 events"); + assert.containsN(calendar, '.o_calendar_filter_item', 6, "should display 6 filter items"); + assert.containsN(calendar, '.fc-event', 2, "should display 2 events"); assert.strictEqual(calendar.$('.fc-event .o_field_name').text().replace(/\s/g, ''), "event7event8", "should display 2 events"); @@ -1868,10 +1868,10 @@ QUnit.module('Views', { }, }); - assert.strictEqual(calendar.$('.fc-event').length, 5, + assert.containsN(calendar, '.fc-event', 5, "should display 5 events"); - calendar.$('.o_calendar_filter_item[data-value=all] input[type=checkbox]').click(); - assert.strictEqual(calendar.$('.fc-event').length, 5, + testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=all] input[type=checkbox]')); + assert.containsN(calendar, '.fc-event', 5, "should display 5 events"); calendar.destroy(); }); @@ -1898,8 +1898,8 @@ QUnit.module('Views', { var top = calendar.$('.fc-axis:contains(0:00)').offset().top + 5; var left = calendar.$('.fc-day:eq(2)').offset().left + 5; try { - testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); - testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown"); + testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup"); } catch (e) { calendar.destroy(); $view.remove(); @@ -1910,7 +1910,7 @@ QUnit.module('Views', { "should open the quick create dialog"); // Creating the event - $('.modal-body input:first').val('new event in quick create').trigger('input'); + testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create'); $('.modal-footer button.btn:contains(Create)').trigger('click').trigger('click'); assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1, "should display the new record after quick create dialog"); @@ -1950,7 +1950,7 @@ QUnit.module('Views', { } }, }); - assert.strictEqual(calendar.$('.fc-day-grid .fc-event-container').length, 1, + assert.containsOnce(calendar, '.fc-day-grid .fc-event-container', "should be one event in the all day row"); assert.strictEqual(calendar.model.data.data[0].r_start.date(), 14, "the date should be 14"); @@ -1991,16 +1991,16 @@ QUnit.module('Views', { // create a new event var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); var $input = $('.modal input:first'); - $input.val('new event in quick create').trigger('input'); + testUtils.fields.editInput($input, 'new event in quick create'); // Simulate ENTER pressed on Create button (after a TAB) $input.trigger($.Event('keyup', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER, })); - $('.modal-footer button:first').click(); + testUtils.dom.click($('.modal-footer button:first')); def.resolve(); assert.strictEqual(createCount, 1, "should create only one event"); @@ -2012,7 +2012,7 @@ QUnit.module('Views', { assert.expect(1); var instanceNumber = 0; - testUtils.patch(mixins.ParentedMixin, { + testUtils.mock.patch(mixins.ParentedMixin, { init: function () { instanceNumber++; return this._super.apply(this, arguments); @@ -2062,14 +2062,14 @@ QUnit.module('Views', { calendar.destroy(); - testUtils.unpatch(mixins.ParentedMixin); + testUtils.mock.unpatch(mixins.ParentedMixin); }); QUnit.test('create an event (async dialog) [REQUIRE FOCUS]', function (assert) { assert.expect(3); var def = $.Deferred(); - testUtils.patch(Dialog, { + testUtils.mock.patch(Dialog, { open: function () { var _super = this._super.bind(this); def.then(_super); @@ -2099,8 +2099,8 @@ QUnit.module('Views', { // create an event var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); assert.strictEqual($('.modal').length, 0, "should not have opened the dialog yet"); @@ -2113,7 +2113,7 @@ QUnit.module('Views', { "should focus the input in the dialog"); calendar.destroy(); - testUtils.unpatch(Dialog); + testUtils.mock.unpatch(Dialog); }); QUnit.test('calendar is configured to hide the groupby menu', function (assert) { @@ -2178,7 +2178,7 @@ QUnit.module('Views', { assert.strictEqual($sidebar.find('.ui-datepicker-current-day').text(), "12", "should highlight the target day"); // go to previous day - $sidebar.find('.ui-datepicker-current-day').prev().click(); + testUtils.dom.click($sidebar.find('.ui-datepicker-current-day').prev()); assert.strictEqual($sidebar.find('.ui-datepicker-current-day').text(), "11", "should highlight the selected day"); @@ -2223,10 +2223,10 @@ QUnit.module('Views', { }); var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); var $input = $('.modal-body input:first'); - $input.val("It's just a fleshwound").trigger('input'); + testUtils.fields.editInput($input, "It's just a fleshwound"); $('.modal button.btn:contains(Create)').trigger('click'); calendar.destroy(); @@ -2270,10 +2270,10 @@ QUnit.module('Views', { }); var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)'); - testUtils.triggerMouseEvent($cell, "mousedown"); - testUtils.triggerMouseEvent($cell, "mouseup"); + testUtils.dom.triggerMouseEvent($cell, "mousedown"); + testUtils.dom.triggerMouseEvent($cell, "mouseup"); var $input = $('.modal-body input:first'); - $input.val("It's just a fleshwound").trigger('input'); + testUtils.fields.editInput($input, "It's just a fleshwound"); $('.modal button.btn:contains(Create)').trigger('click'); calendar.destroy(); diff --git a/addons/web/static/tests/views/form_benchmarks.js b/addons/web/static/tests/views/form_benchmarks.js index d664859ba2f..c6127f847ec 100644 --- a/addons/web/static/tests/views/form_benchmarks.js +++ b/addons/web/static/tests/views/form_benchmarks.js @@ -85,7 +85,7 @@ QUnit.module('Form View', { '' ''; this.run(assert, done, function (form) { - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); form.$('.o_data_cell:first').click(); form.$('input:first').val("tralala").trigger('input'); }); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index ada27d09afc..b73a1438f13 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -144,34 +144,25 @@ QUnit.module('Views', { '', res_id: 2, }); - assert.strictEqual(form.$('div.test').length, 1, - "should contain a div with some html"); - assert.strictEqual(form.$('div.test').css('opacity'), "0.5", - "should keep the inline style on html elements"); - assert.strictEqual(form.$('label:contains(Foo)').length, 1, - "should contain label Foo"); - assert.strictEqual(form.$('span:contains(blip)').length, 1, - "should contain span with field value"); - assert.strictEqual(form.$('.o_group .o_group:first').attr('style'), 'background-color: red', - "should apply style attribute on groups"); - assert.strictEqual(form.$('.o_field_widget[name=foo]').attr('style'), 'color: blue', - "should apply style attribute on fields"); - assert.strictEqual(form.$('label:contains(something_id)').length, 0, - "should not contain f3 string description"); - assert.strictEqual(form.$('label:contains(f3_description)').length, 1, - "should contain custom f3 string description"); - assert.strictEqual(form.$('div.o_field_one2many table').length, 1, - "should render a one2many relation"); + assert.containsOnce(form, 'div.test'); + assert.strictEqual(form.$('div.test').css('opacity'), '0.5', + "should keep the inline style on html elements"); + assert.containsOnce(form, 'label:contains(Foo)'); + assert.containsOnce(form, 'span:contains(blip)'); + assert.hasAttrValue(form.$('.o_group .o_group:first'), 'style', 'background-color: red', + "should apply style attribute on groups"); + assert.hasAttrValue(form.$('.o_field_widget[name=foo]'), 'style', 'color: blue', + "should apply style attribute on fields"); + assert.containsNone(form, 'label:contains(something_id)'); + assert.containsOnce(form, 'label:contains(f3_description)'); + assert.containsOnce(form, 'div.o_field_one2many table'); + assert.containsOnce(form, 'tbody td:not(.o_list_record_selector) .custom-checkbox input:checked'); + assert.strictEqual(form.get('title'), 'second record', + "title should be display_name of record"); + assert.containsNone(form, 'label.o_form_label_empty:contains(timmy)'); - assert.strictEqual(form.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 1, - "1 checkboxes should be checked"); - - assert.strictEqual(form.get('title'), "second record", - "title should be display_name of record"); - assert.strictEqual(form.$('label.o_form_label_empty:contains(timmy)').length, 0, - "the many2many label shouldn't be marked as empty"); form.destroy(); }); @@ -198,7 +189,7 @@ QUnit.module('Views', { '', res_id: 2, }).then(function (form) { - assert.strictEqual(form.$('.o_field_widget[name=foo]').attr('style'), 'color: blue', + assert.hasAttrValue(form.$('.o_field_widget[name=foo]'), 'style', 'color: blue', "should apply style attribute on fields"); form.destroy(); delete fieldRegistry.map.asyncwidget; @@ -220,10 +211,8 @@ QUnit.module('Views', { '', res_id: 2, }); - assert.ok(!form.$('span[name="display_name"]').hasClass('text-danger'), - 'field display name should not have decoration'); - assert.ok(form.$('span[name="foo"]').hasClass('text-danger'), - 'field foo should have decoration'); + assert.doesNotHaveClass(form.$('span[name="display_name"]'), 'text-danger'); + assert.hasClass(form.$('span[name="foo"]'), 'text-danger'); form.destroy(); }); @@ -241,11 +230,9 @@ QUnit.module('Views', { res_id: 2, viewOptions: {mode: 'edit'}, }); - assert.ok(!form.$('input[name="display_name"]').hasClass('text-danger'), - 'field display name should not have decoration'); - form.$('input[name="int_field"]').val(3).trigger('input'); - assert.ok(form.$('input[name="display_name"]').hasClass('text-danger'), - 'field display name should now have decoration'); + assert.doesNotHaveClass(form.$('input[name="display_name"]'), 'text-danger'); + testUtils.fields.editInput(form.$('input[name=int_field]'), 3); + assert.hasClass(form.$('input[name="display_name"]'), 'text-danger'); form.destroy(); }); @@ -262,11 +249,9 @@ QUnit.module('Views', { res_id: 2, viewOptions: {mode: 'edit'}, }); - assert.ok(!form.$('input[name="int_field"]').hasClass('text-danger'), - 'field should not have decoration'); - form.$('input[name="int_field"]').val(3).trigger('input'); - assert.ok(form.$('input[name="int_field"]').hasClass('text-danger'), - 'field should now have decoration'); + assert.doesNotHaveClass(form.$('input[name="int_field"]'), 'text-danger'); + testUtils.fields.editInput(form.$('input[name=int_field]'), 3); + assert.hasClass(form.$('input[name="int_field"]'), 'text-danger'); form.destroy(); }); @@ -311,8 +296,8 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('table.o_inner_group').length, 1, - "should contain an inner group"); + assert.containsOnce(form, 'table.o_inner_group'); + form.destroy(); }); @@ -339,14 +324,10 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('label.o_invisible_modifier:contains(Foo)').length, 1, - "should not contain label Foo"); - assert.strictEqual(form.$('span.o_invisible_modifier:contains(yop)').length, 1, - "should not contain span with field value"); - assert.strictEqual(form.$('.o_field_widget.o_invisible_modifier:contains(0.4)').length, 1, - "field qux should be invisible"); - assert.ok(form.$('.o_field_widget[name=p]').hasClass('o_invisible_modifier'), - "field p should be invisible"); + assert.containsOnce(form, 'label.o_invisible_modifier:contains(Foo)'); + assert.containsOnce(form, 'span.o_invisible_modifier:contains(yop)'); + assert.containsOnce(form, '.o_field_widget.o_invisible_modifier:contains(0.4)'); + assert.hasClass(form.$('.o_field_widget[name=p]'), 'o_invisible_modifier'); form.destroy(); }); @@ -375,21 +356,17 @@ QUnit.module('Views', { '', res_id: 1, }); - assert.strictEqual(form.$('.o_form_statusbar.o_invisible_modifier button:contains(coucou)').length, 1, - "should not display invisible header"); - assert.strictEqual(form.$('.o_notebook li.o_invisible_modifier a:contains(invisible)').length, 1, - "should not display tab invisible"); - assert.strictEqual(form.$('table.o_inner_group.o_invisible_modifier td:contains(invgroup)').length, 1, - "should not display invisible groups"); + assert.containsOnce(form, '.o_form_statusbar.o_invisible_modifier button:contains(coucou)'); + assert.containsOnce(form, '.o_notebook li.o_invisible_modifier a:contains(invisible)'); + assert.containsOnce(form, 'table.o_inner_group.o_invisible_modifier td:contains(invgroup)'); form.destroy(); }); - QUnit.test('invisible attrs on fields are re-evaluated on field change', function (assert) { + QUnit.test('invisible attrs on fields are re-evaluated on field change', async function (assert) { assert.expect(3); // we set the value bar to simulate a falsy boolean value. this.data.partner.records[0].bar = false; - var form = createView({ View: FormView, model: 'partner', @@ -405,16 +382,14 @@ QUnit.module('Views', { res_id: 1, }); - - form.$buttons.find('.o_form_button_edit').click(); - assert.ok(form.$('.foo_field').hasClass('o_invisible_modifier'), 'should not display foo field'); - assert.ok(form.$('.bar_field').hasClass('o_invisible_modifier'), 'should not display bar field'); + testUtils.form.clickEdit(form); + assert.hasClass(form.$('.foo_field'), 'o_invisible_modifier'); + assert.hasClass(form.$('.bar_field'), 'o_invisible_modifier'); // set a value on the m2o - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').click(); - $dropdown.find('li:first()').click(); - assert.ok(!form.$('.foo_field').hasClass('o_invisible_modifier'), 'should display foo field'); + await testUtils.fields.many2one.searchAndClickItem('product_id'); + assert.doesNotHaveClass(form.$('.foo_field'), 'o_invisible_modifier'); + form.destroy(); }); @@ -444,8 +419,7 @@ QUnit.module('Views', { '', res_id: 1, }).then(function (form) { - assert.ok(form.$('.o_field_widget[name="int_field"]').hasClass('o_invisible_modifier'), - 'int_field is invisible'); + assert.hasClass(form.$('.o_field_widget[name="int_field"]'), 'o_invisible_modifier'); form.destroy(); delete fieldRegistry.map.asyncwidget; }); @@ -473,10 +447,8 @@ QUnit.module('Views', { res_id: 1, }); - assert.ok(form.$('.o_notebook').hasClass('o_invisible_modifier'), - 'the notebook should handle modifiers (invisible)'); - assert.ok(form.$('.o_notebook').hasClass('new_class'), - 'the notebook should handle attributes'); + assert.hasClass(form.$('.o_notebook'), 'o_invisible_modifier'); + assert.hasClass(form.$('.o_notebook'), 'new_class'); form.destroy(); }); @@ -503,24 +475,16 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - assert.ok(form.$('.o_notebook .nav .nav-link:first()').hasClass('active'), - 'first tab should be active'); - assert.ok(!form.$('.o_notebook .nav .nav-item:first()').hasClass('o_invisible_modifier'), - 'first tab should be visible'); + testUtils.form.clickEdit(form); + assert.hasClass(form.$('.o_notebook .nav .nav-link:first()'), 'active'); + assert.doesNotHaveClass(form.$('.o_notebook .nav .nav-item:first()'), 'o_invisible_modifier'); // set a value on the m2o - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - form.$('.o_field_many2one input').click(); - $dropdown.find('li:first()').click(); - assert.ok(!form.$('.o_notebook .nav .nav-link:first()').hasClass('active'), - 'first tab should not be active'); - assert.ok(form.$('.o_notebook .nav .nav-item:first()').hasClass('o_invisible_modifier'), - 'first tab should be invisible'); - assert.ok(form.$('.o_notebook .nav .nav-link:nth(1)').hasClass('active'), - 'second tab should be active'); - assert.ok(form.$('.o_notebook .tab-content .tab-pane:nth(1)').hasClass('active'), - 'second page should be active'); + testUtils.fields.many2one.searchAndClickItem('product_id'); + assert.doesNotHaveClass(form.$('.o_notebook .nav .nav-link:first()'), 'active'); + assert.hasClass(form.$('.o_notebook .nav .nav-item:first()'), 'o_invisible_modifier'); + assert.hasClass(form.$('.o_notebook .nav .nav-link:nth(1)'), 'active'); + assert.hasClass(form.$('.o_notebook .tab-content .tab-pane:nth(1)'), 'active'); form.destroy(); }); @@ -549,8 +513,7 @@ QUnit.module('Views', { assert.notOk(form.$('.o_notebook .nav .nav-item:first()').is(':visible'), 'first tab should be invisible'); - assert.ok(form.$('.o_notebook .nav .nav-link:nth(1)').hasClass('active'), - 'second tab should be active'); + assert.hasClass(form.$('.o_notebook .nav .nav-link:nth(1)'), 'active'); form.destroy(); }); @@ -578,10 +541,8 @@ QUnit.module('Views', { res_id: 1, }); - assert.notOk(form.$('.o_notebook .nav .nav-link:first()').hasClass('active'), - 'first tab should not active'); - assert.ok(form.$('.o_notebook .nav .nav-link:nth(1)').hasClass('active'), - 'second tab should be active'); + assert.doesNotHaveClass(form.$('.o_notebook .nav .nav-link:first()'), 'active'); + assert.hasClass(form.$('.o_notebook .nav .nav-link:nth(1)'), 'active'); form.destroy(); }); @@ -606,10 +567,10 @@ QUnit.module('Views', { res_id: 1 }); - assert.strictEqual(form.$('div.o_group:visible').length, 1, "should display the group"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('div.o_group:hidden').length, 1, "should not display the group"); + assert.containsOnce(form, 'div.o_group:visible'); + testUtils.form.clickEdit(form); + testUtils.dom.click('.o_field_boolean input', form); + assert.containsOnce(form, 'div.o_group:hidden'); form.destroy(); }); @@ -633,8 +594,7 @@ QUnit.module('Views', { '', }); - assert.notOk(form.$('div.hello').is(':visible'), - "attrs invisible should have been computed and applied"); + assert.isNotVisible(form.$('div.hello')); form.destroy(); }); @@ -663,16 +623,14 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.$('button.oe_stat_button').length, 2, - "should have 2 stat buttons"); - assert.strictEqual(form.$('button.oe_stat_button.o_invisible_modifier').length, 1, - "should have 1 invisible stat buttons"); + assert.containsN(form, 'button.oe_stat_button', 2); + assert.containsOnce(form, 'button.oe_stat_button.o_invisible_modifier'); var count = 0; - testUtils.intercept(form, "execute_action", function () { + testUtils.mock.intercept(form, "execute_action", function () { count++; }); - form.$('.oe_stat_button').first().click(); + testUtils.dom.click('.oe_stat_button'); assert.strictEqual(count, 1, "should have triggered a execute action"); form.destroy(); }); @@ -695,8 +653,7 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.$('label.o_form_label:contains(customstring)').length, 1, - "should have 1 label with correct string"); + assert.containsOnce(form, 'label.o_form_label:contains(customstring)'); form.destroy(); }); @@ -717,18 +674,18 @@ QUnit.module('Views', { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('span[name="foo"]').length, 1, + assert.containsOnce(form, 'span[name="foo"]', "the foo field widget should be readonly"); - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('input[name="foo"]').length, 1, + testUtils.dom.click(form.$('.o_field_boolean input')); + assert.containsOnce(form, 'input[name="foo"]', "the foo field widget should have been rerendered to now be editable"); - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('span[name="foo"]').length, 1, + testUtils.dom.click(form.$('.o_field_boolean input')); + assert.containsOnce(form, 'span[name="foo"]', "the foo field widget should have been rerendered to now be readonly again"); - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('input[name="foo"]').length, 1, + testUtils.dom.click(form.$('.o_field_boolean input')); + assert.containsOnce(form, 'input[name="foo"]', "the foo field widget should have been rerendered to now be editable again"); form.destroy(); @@ -763,30 +720,30 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.$('.o_field_widget.o_field_empty').length, 2, + assert.containsN(form, '.o_field_widget.o_field_empty', 2, "should have 2 empty fields with correct class"); - assert.strictEqual(form.$('.o_form_label_empty').length, 2, + assert.containsN(form, '.o_form_label_empty', 2, "should have 2 muted labels (for the empty fieds) in readonly"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_empty').length, 1, + assert.containsOnce(form, '.o_field_empty', "in edit mode, only empty readonly fields should have the o_field_empty class"); - assert.strictEqual(form.$('.o_form_label_empty').length, 1, + assert.containsOnce(form, '.o_form_label_empty', "in edit mode, only labels associated to empty readonly fields should have the o_form_label_empty class"); - form.$('input[name="foo"]').val("test").trigger("input"); + testUtils.fields.editInput(form.$('input[name=foo]'), 'test'); - assert.strictEqual(form.$('.o_field_empty').length, 0, + assert.containsNone(form, '.o_field_empty', "after readonly modifier change, the o_field_empty class should have been removed"); - assert.strictEqual(form.$('.o_form_label_empty').length, 0, + assert.containsNone(form, '.o_form_label_empty', "after readonly modifier change, the o_form_label_empty class should have been removed"); - form.$('input[name="foo"]').val("hello").trigger("input"); + testUtils.fields.editInput(form.$('input[name=foo]'), 'hello'); - assert.strictEqual(form.$('.o_field_empty').length, 1, + assert.containsOnce(form, '.o_field_empty', "after value changed to false for a readonly field, the o_field_empty class should have been added"); - assert.strictEqual(form.$('.o_form_label_empty').length, 1, + assert.containsOnce(form, '.o_form_label_empty', "after value changed to false for a readonly field, the o_form_label_empty class should have been added"); form.destroy(); @@ -804,36 +761,33 @@ QUnit.module('Views', { model: 'partner', data: this.data, arch: '
' + - '' + - '' + - '' + - '' + - '' + - '' + + '' + + '' + + '' + + '' + '
', res_id: 2, }); - assert.strictEqual(form.$('.o_field_widget.o_field_empty').length, 2, - "should have 1 empty field with correct class"); - assert.strictEqual(form.$('.o_form_label_empty').length, 2, + assert.containsN(form, '.o_field_widget.o_field_empty', 2) + assert.containsN(form, '.o_form_label_empty', 2, "should have 1 muted label (for the empty fied) in readonly"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.o_field_empty').length, 0, + assert.containsNone(form, '.o_field_empty', "in edit mode, only empty readonly fields should have the o_field_empty class"); - assert.strictEqual(form.$('.o_form_label_empty').length, 0, + assert.containsNone(form, '.o_form_label_empty', "in edit mode, only labels associated to empty readonly fields should have the o_form_label_empty class"); - form.$('input[name="foo"]').val("readonly").trigger("input"); // display_name is now rerendered as readonly - form.$('input[name="foo"]').val("edit").trigger("input"); // display_name is now rerendered as editable - form.$('input[name="display_name"]').val('1').trigger("input"); // display_name is now set - form.$('input[name="foo"]').val("readonly").trigger("input"); // display_name is now rerendered as readonly + testUtils.fields.editInput(form.$('input[name=foo]'), 'readonly'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'edit'); + testUtils.fields.editInput(form.$('input[name=display_name]'), 'some name'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'readonly'); - assert.strictEqual(form.$('.o_field_empty').length, 0, + assert.containsNone(form, '.o_field_empty', "there still should not be any empty class on fields as the readonly one is now set"); - assert.strictEqual(form.$('.o_form_label_empty').length, 0, + assert.containsNone(form, '.o_form_label_empty', "there still should not be any empty class on labels as the associated readonly field is now set"); form.destroy(); @@ -857,9 +811,9 @@ QUnit.module('Views', { '' + '', }); - assert.strictEqual(form.$('.o_form_label_empty').length, 0, + assert.containsNone(form, '.o_form_label_empty', "no empty class on label"); - assert.strictEqual(form.$('.o_field_empty').length, 0, + assert.containsNone(form, '.o_field_empty', "no empty class on field"); form.destroy(); }); @@ -871,33 +825,24 @@ QUnit.module('Views', { View: FormView, model: 'partner', data: this.data, - arch: '
' + - '' + - '' + - '' + - '' + - '' + + arch: '' + + '' + '', res_id: 1, }); assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); - assert.ok(form.$('.o_form_view').hasClass('o_form_readonly'), - 'form view should be .o_form_readonly'); - assert.ok(form.$buttons.find('.o_form_buttons_view').is(':visible'), - 'readonly buttons should be visible'); - assert.ok(!form.$buttons.find('.o_form_buttons_edit').is(':visible'), - 'edit buttons should not be visible'); - form.$buttons.find('.o_form_button_edit').click(); + assert.hasClass(form.$('.o_form_view'), 'o_form_readonly'); + assert.isVisible(form.$buttons.find('.o_form_buttons_view')); + assert.isNotVisible(form.$buttons.find('.o_form_buttons_edit')); + + testUtils.form.clickEdit(form); + assert.strictEqual(form.mode, 'edit', 'form view should be in edit mode'); - assert.ok(form.$('.o_form_view').hasClass('o_form_editable'), - 'form view should be .o_form_editable'); - assert.ok(!form.$('.o_form_view').hasClass('o_form_readonly'), - 'form view should not be .o_form_readonly'); - assert.ok(!form.$buttons.find('.o_form_buttons_view').is(':visible'), - 'readonly buttons should not be visible'); - assert.ok(form.$buttons.find('.o_form_buttons_edit').is(':visible'), - 'edit buttons should be visible'); + assert.hasClass(form.$('.o_form_view'), 'o_form_editable'); + assert.doesNotHaveClass(form.$('.o_form_view'), 'o_form_readonly'); + assert.isNotVisible(form.$buttons.find('.o_form_buttons_view')); + assert.isVisible(form.$buttons.find('.o_form_buttons_edit')); form.destroy(); }); @@ -918,15 +863,15 @@ QUnit.module('Views', { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('input[name="foo"].o_required_modifier').length, 1, + assert.containsOnce(form, 'input[name="foo"].o_required_modifier', "the foo field widget should be required"); - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('input[name="foo"]:not(.o_required_modifier)').length, 1, + testUtils.dom.click('.o_field_boolean input'); + assert.containsOnce(form, 'input[name="foo"]:not(.o_required_modifier)', "the foo field widget should now have been marked as non-required"); - form.$('.o_field_boolean input').click(); - assert.strictEqual(form.$('input[name="foo"].o_required_modifier').length, 1, + testUtils.dom.click('.o_field_boolean input'); + assert.containsOnce(form, 'input[name="foo"].o_required_modifier', "the foo field widget should now have been marked as required again"); form.destroy(); @@ -950,12 +895,11 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('span.o_required_modifier').length, 1, - "should have 1 span with o_required_modifier class"); + assert.containsOnce(form, 'span.o_required_modifier', form); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input.o_required_modifier').length, 1, - "in edit mode, should have 1 input with o_required_modifier"); + testUtils.form.clickEdit(form); + assert.containsOnce(form, 'input.o_required_modifier', + "in edit mode, should have 1 input with o_required_modifier"); form.destroy(); }); @@ -980,23 +924,21 @@ QUnit.module('Views', { }, }); - assert.ok(form.$('input[name="qux"]').hasClass('o_required_modifier'), - "qux input is flagged as required"); + assert.hasClass(form.$('input[name="qux"]'), 'o_required_modifier'); assert.strictEqual(form.$('input[name="qux"]').val(), "0.0", "qux input is 0 by default (float field)"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); - assert.notOk(form.$('input[name="qux"]').hasClass('o_field_invalid'), - "qux input is not displayed as invalid"); + assert.containsNone(form.$('input[name="qux"]'), "should have switched to readonly"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('input[name="qux"]').val("1").trigger('input'); + testUtils.fields.editInput(form.$('input[name=qux]'), '1'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input[name="qux"]').val(), "1.0", "qux input is properly formatted"); @@ -1023,8 +965,7 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('div.o_horizontal_separator').length, 1, - "should contain a separator div"); + assert.containsOnce(form, 'div.o_horizontal_separator'); form.destroy(); }); @@ -1045,8 +986,9 @@ QUnit.module('Views', { '', res_id: 1, }); - assert.strictEqual(form.$('div.o_horizontal_separator').hasClass('o_invisible_modifier'), true, - "separator div should be hidden"); + + assert.hasClass(form.$('div.o_horizontal_separator'), 'o_invisible_modifier'); + form.destroy(); }); @@ -1062,8 +1004,9 @@ QUnit.module('Views', { arch: '
' + '' + '
' + - '
' + '' + '' + @@ -1077,35 +1020,31 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - assert.strictEqual(form.$('button.btn i.fa.fa-check').length, 1, - "should contain a button with correct content"); + assert.containsOnce(form, 'button.btn i.fa.fa-check'); + assert.containsN(form, '.o_form_statusbar button', 3); + assert.containsOnce(form, 'button.p[name="post"]:contains(Confirm)'); + assert.containsN(form, '.o_form_statusbar button:visible', 2); - assert.strictEqual(form.$('.o_form_statusbar button').length, 2, - "should have 2 buttons in the statusbar"); - assert.strictEqual(form.$('button[name="post"]').length, 1, - "'name' attribute of buttons is transmitted to the rendered html element"); - - assert.strictEqual(form.$('.o_form_statusbar button:visible').length, 1, - "should have only 1 visible button in the statusbar"); - - testUtils.intercept(form, 'execute_action', function (event) { - assert.strictEqual(event.data.action_data.name, "post", + testUtils.mock.intercept(form, 'execute_action', function (ev) { + assert.strictEqual(ev.data.action_data.name, 'post', "should trigger execute_action with correct method name"); - assert.deepEqual(event.data.env.currentID, 2, "should have correct id in event data"); - event.data.on_success(); - event.data.on_closed(); + assert.deepEqual(ev.data.env.currentID, 2, "should have correct id in ev data"); + ev.data.on_success(); + ev.data.on_closed(); }); rpcCount = 0; - form.$('.o_form_statusbar button.p').click(); + testUtils.dom.click('.o_form_statusbar button.p', form); assert.strictEqual(rpcCount, 1, "should have done 1 rpcs to reload"); - testUtils.intercept(form, 'execute_action', function (event) { - event.data.on_fail(); + testUtils.mock.intercept(form, 'execute_action', function (ev) { + ev.data.on_fail(); }); - form.$('.o_form_statusbar button.s').click(); + testUtils.dom.click('.o_form_statusbar button.s', form); + + assert.strictEqual(rpcCount, 1, + "should have done 1 rpc, because we do not reload anymore if the server action fails"); - assert.strictEqual(rpcCount, 1, "should have done 1 rpc, because we do not reload anymore if the server action fails"); form.destroy(); }); @@ -1142,38 +1081,22 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.$('button[name="0"]').attr('class'), 'btn btn-secondary', - "header buttons without any class should receive the correct classes"); - assert.strictEqual(form.$('button[name="1"]').attr('class'), 'btn btn-primary', - "header buttons with bootstrap primary class should receive the correct classes"); - assert.strictEqual(form.$('button[name="2"]').attr('class'), 'btn btn-primary', - "header buttons with oe_highlight class should receive the correct classes"); - assert.strictEqual(form.$('button[name="3"]').attr('class'), 'btn btn-secondary', - "header buttons with bootstrap default class should receive the correct classes"); - assert.strictEqual(form.$('button[name="4"]').attr('class'), 'btn btn-link', - "header buttons with bootstrap link class should receive the correct classes"); - assert.strictEqual(form.$('button[name="5"]').attr('class'), 'btn btn-link', - "header buttons with oe_link class should receive the correct classes"); - assert.strictEqual(form.$('button[name="6"]').attr('class'), 'btn btn-success', - "header buttons with bootstrap state class should receive the correct classes"); - assert.strictEqual(form.$('button[name="7"]').attr('class'), 'btn o_this_is_a_button btn-secondary', - "header buttons with custom classes should receive the correct classes"); - assert.strictEqual(form.$('button[name="8"]').attr('class'), 'btn btn-secondary', - "sheet header buttons without any class should receive the correct classes"); - assert.strictEqual(form.$('button[name="9"]').attr('class'), 'btn btn-primary', - "sheet buttons with bootstrap primary class should receive the correct classes"); - assert.strictEqual(form.$('button[name="10"]').attr('class'), 'btn btn-primary', - "sheet buttons with oe_highlight class should receive the correct classes"); - assert.strictEqual(form.$('button[name="11"]').attr('class'), 'btn btn-secondary', - "sheet buttons with bootstrap default class should receive the correct classes"); - assert.strictEqual(form.$('button[name="12"]').attr('class'), 'btn btn-link', - "sheet buttons with bootstrap link class should receive the correct classes"); - assert.strictEqual(form.$('button[name="13"]').attr('class'), 'btn btn-link', - "sheet buttons with oe_link class should receive the correct classes"); - assert.strictEqual(form.$('button[name="14"]').attr('class'), 'btn btn-success', - "sheet buttons with bootstrap state class should receive the correct classes"); - assert.strictEqual(form.$('button[name="15"]').attr('class'), 'btn o_this_is_a_button', - "sheet buttons with custom classes should receive the correct classes"); + assert.hasAttrValue(form.$('button[name="0"]'), 'class', 'btn btn-secondary'); + assert.hasAttrValue(form.$('button[name="1"]'), 'class', 'btn btn-primary'); + assert.hasAttrValue(form.$('button[name="2"]'), 'class', 'btn btn-primary'); + assert.hasAttrValue(form.$('button[name="3"]'), 'class', 'btn btn-secondary'); + assert.hasAttrValue(form.$('button[name="4"]'), 'class', 'btn btn-link'); + assert.hasAttrValue(form.$('button[name="5"]'), 'class', 'btn btn-link'); + assert.hasAttrValue(form.$('button[name="6"]'), 'class', 'btn btn-success'); + assert.hasAttrValue(form.$('button[name="7"]'), 'class', 'btn o_this_is_a_button btn-secondary'); + assert.hasAttrValue(form.$('button[name="8"]'), 'class', 'btn btn-secondary'); + assert.hasAttrValue(form.$('button[name="9"]'), 'class', 'btn btn-primary'); + assert.hasAttrValue(form.$('button[name="10"]'), 'class', 'btn btn-primary'); + assert.hasAttrValue(form.$('button[name="11"]'), 'class', 'btn btn-secondary'); + assert.hasAttrValue(form.$('button[name="12"]'), 'class', 'btn btn-link'); + assert.hasAttrValue(form.$('button[name="13"]'), 'class', 'btn btn-link'); + assert.hasAttrValue(form.$('button[name="14"]'), 'class', 'btn btn-success'); + assert.hasAttrValue(form.$('button[name="15"]'), 'class', 'btn o_this_is_a_button'); form.destroy(); }); @@ -1211,14 +1134,14 @@ QUnit.module('Views', { }, }); - testUtils.intercept(form, 'execute_action', function (event) { + testUtils.mock.intercept(form, 'execute_action', function (event) { assert.step('execute_action'); assert.deepEqual(event.data.env.currentID, resID, "execute action should be done on correct record id"); event.data.on_success(); event.data.on_closed(); }); - form.$('.o_form_statusbar button.p').click(); + testUtils.dom.click('.o_form_statusbar button.p', form); assert.verifySteps(['default_get', 'create', 'read', 'execute_action', 'read']); form.destroy(); @@ -1261,14 +1184,14 @@ QUnit.module('Views', { }, }); - testUtils.intercept(form, 'execute_action', function (event) { + testUtils.mock.intercept(form, 'execute_action', function (event) { assert.step('execute_action'); assert.deepEqual(event.data.env.currentID, resID, "execute action should be done on correct record id"); event.data.on_success(); event.data.on_closed(); }); - form.$('.o_form_statusbar button.p').click(); + testUtils.dom.click('.o_form_statusbar button.p', form); assert.verifySteps(['default_get', 'create', 'read', 'execute_action', 'read']); form.destroy(); @@ -1293,17 +1216,17 @@ QUnit.module('Views', { }); assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); - assert.strictEqual(form.$('span:contains(blip)').length, 1, + assert.containsOnce(form, 'span:contains(blip)', "should contain span with field value"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.mode, 'edit', 'form view should be in edit mode'); - form.$('input').val("tralala").trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); + testUtils.form.clickSave(form); assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); - assert.strictEqual(form.$('span:contains(tralala)').length, 1, + assert.containsOnce(form, 'span:contains(tralala)', "should contain span with field value"); form.destroy(); }); @@ -1327,17 +1250,16 @@ QUnit.module('Views', { res_id: 2, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input').val("tralala").trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - assert.strictEqual(form.$('span:contains(apple)').length, 1, + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); + testUtils.form.clickSave(form); + assert.containsOnce(form, 'span:contains(apple)', "should contain span with field value"); form.destroy(); }); QUnit.test('disable buttons until reload data from server', function (assert) { assert.expect(2); - var def; var form = createView({ View: FormView, @@ -1360,22 +1282,17 @@ QUnit.module('Views', { }); var def = $.Deferred(); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input').val("tralala").trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); + testUtils.form.clickSave(form); // Save button should be disabled - assert.strictEqual( - form.$buttons.find('.o_form_button_save').attr('disabled'), - 'disabled', 'buttons should be disabled') - + assert.hasAttrValue(form.$buttons.find('.o_form_button_save'), 'disabled', 'disabled'); // Release the 'read' call def.resolve(); // Edit button should be enabled after the reload - assert.strictEqual( - form.$buttons.find('.o_form_button_edit').attr('disabled'), - undefined, 'buttons should be enabled') + assert.hasAttrValue(form.$buttons.find('.o_form_button_edit'), 'disabled', undefined); form.destroy(); }); @@ -1398,14 +1315,14 @@ QUnit.module('Views', { res_id: 2, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('input').eq(1).val(), "9", + assert.strictEqual(form.$('input[name=int_field]').val(), "9", "should contain input with initial value"); - form.$('input').first().val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); - assert.strictEqual(form.$('input').eq(1).val(), "1007", + assert.strictEqual(form.$('input[name=int_field]').val(), "1007", "should contain input with onchange applied"); form.destroy(); }); @@ -1430,15 +1347,15 @@ QUnit.module('Views', { }); - assert.strictEqual(form.$('input').val(), "9", + assert.strictEqual(form.$('input[name=int_field]').val(), "9", "should contain input with initial value"); - form.$('input').val("666").trigger('input'); + testUtils.fields.editInput(form.$('input[name=int_field]'), '666'); - assert.strictEqual(form.$('input').val(), "14", + assert.strictEqual(form.$('input[name=int_field]').val(), "14", "value should have been set to 14 by onchange"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget[name=int_field]').text(), "14", "value should still be 14"); @@ -1481,8 +1398,8 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input:first').val("tralala").trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); form.destroy(); }); @@ -1519,17 +1436,17 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // add a o2m row - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click('.o_field_x2many_list_row_add a'); form.$('.o_field_one2many input:first').focus(); - form.$('.o_field_one2many input:first').val('valid line').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_one2many input[name=display_name]'), 'valid line'); form.$('.o_field_one2many input:last').focus(); - form.$('.o_field_one2many input:last').val('12.4').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_one2many input[name=qux]'), '12.4'); // trigger an onchange by modifying foo - form.$('input[name="foo"]:first').val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); form.destroy(); }); @@ -1590,12 +1507,12 @@ QUnit.module('Views', { }); var n = this.data.partner.records.length; - form.$buttons.find('.o_form_button_create').click(); + testUtils.form.clickCreate(form); assert.strictEqual(form.mode, 'edit', 'form view should be in edit mode'); assert.strictEqual(form.$('input:first').val(), "My little Foo Value", "should have correct default_get value"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); assert.strictEqual(this.data.partner.records.length, n + 1, "should have created a record"); form.destroy(); @@ -1648,11 +1565,12 @@ QUnit.module('Views', { res_id: 1, }); - assert.ok(!form.sidebar.$el.hasClass('o_hidden'), 'sidebar should be visible'); - form.$buttons.find('.o_form_button_edit').click(); - assert.ok(form.sidebar.$el.hasClass('o_hidden'), 'sidebar should be invisible'); - form.$buttons.find('.o_form_button_cancel').click(); - assert.ok(!form.sidebar.$el.hasClass('o_hidden'), 'sidebar should be visible'); + assert.isVisible(form.sidebar); + testUtils.form.clickEdit(form); + assert.isNotVisible(form.sidebar); + testUtils.form.clickDiscard(form); + assert.isVisible(form.sidebar); + form.destroy(); }); @@ -1675,7 +1593,7 @@ QUnit.module('Views', { }, }); - assert.strictEqual(form.$('input').val(), "default foo value", "should have correct default"); + assert.strictEqual(form.$('input[name=foo]').val(), "default foo value", "should have correct default"); assert.strictEqual(count, 1, "should do only one rpc"); form.destroy(); }); @@ -1710,11 +1628,11 @@ QUnit.module('Views', { return this._super(route, args); }, }); - assert.ok(form.$('td:contains(new foo1)').length, + assert.containsOnce(form, 'td:contains(new foo1)', "should have new foo1 value in one2many"); - assert.ok(form.$('td:contains(new foo2)').length, + assert.containsOnce(form, 'td:contains(new foo2)', "should have new foo2 value in one2many"); - assert.ok(form.$('td:contains(xphone)').length, + assert.containsOnce(form, 'td:contains(xphone)', "should have a cell with the name field 'product_id', set to xphone"); assert.strictEqual(nameGetCount, 1, "should have done only 1 nameget"); form.destroy(); @@ -1767,7 +1685,7 @@ QUnit.module('Views', { assert.strictEqual(form.get('title'), 'first record', "should have the display name of the record as title"); - form.$buttons.find('.o_form_button_create').click(); + testUtils.form.clickCreate(form); assert.strictEqual(form.get('title'), _t("New"), "should have the display name of the record as title"); form.destroy(); @@ -1789,7 +1707,9 @@ QUnit.module('Views', { assert.strictEqual(form.get('title'), 'first record', "should have the display name of the record as title"); - form.sidebar.$('a:contains(Duplicate)').click(); + + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); assert.strictEqual(form.get('title'), 'first record (copy)', "should have duplicated the record"); @@ -1821,7 +1741,8 @@ QUnit.module('Views', { }, }); - form.sidebar.$('a:contains(Duplicate)').click(); + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); form.destroy(); }); @@ -1842,7 +1763,7 @@ QUnit.module('Views', { assert.strictEqual(form.get('title'), 'first record', "should have the display name of the record as title"); - assert.ok(form.sidebar.$('a:contains(Duplicate)').length === 0, + assert.containsNone(form.sidebar, 'a:contains(Duplicate)', "should not contains a 'Duplicate' action"); form.destroy(); }); @@ -1865,8 +1786,8 @@ QUnit.module('Views', { viewOptions: {footerToButtons: true}, }); - assert.ok(form.$buttons.find('button.infooter').length, "footer button should be in footer"); - assert.ok(!form.$('button.infooter').length, "footer button should not be in form"); + assert.containsOnce(form.$buttons, 'button.infooter', "footer button should be in footer"); + assert.containsNone(form, 'button.infooter', "footer button should not be in form"); form.destroy(); }); @@ -1899,20 +1820,19 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var count = 0; - testUtils.intercept(form, "execute_action", function (event) { + testUtils.mock.intercept(form, "execute_action", function (event) { event.stopPropagation(); count++; }); - form.$('.oe_stat_button').first().click(); + testUtils.dom.click('.oe_stat_button'); assert.strictEqual(count, 1, "should have triggered a execute action"); assert.strictEqual(form.mode, "edit", "form view should be in edit mode"); - - form.$('input').val("tralala").trigger('input'); - form.$('.oe_stat_button').first().click(); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); + testUtils.dom.click('.oe_stat_button:first'); assert.strictEqual(form.mode, "edit", "form view should be in edit mode"); assert.strictEqual(count, 2, "should have triggered a execute action"); @@ -1952,10 +1872,10 @@ QUnit.module('Views', { assert.strictEqual(form.getTitle(), 'second record', "should have correct display_name"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input[name="name"]').val('some other name').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name=name]'), 'some other name'); - form.$('.oe_stat_button').first().click(); + testUtils.dom.click('.oe_stat_button'); assert.strictEqual(form.getTitle(), 'GOLDORAK', "should have correct display_name"); @@ -1985,24 +1905,22 @@ QUnit.module('Views', { return this._super(route, args); } }); - testUtils.intercept(form, "execute_action", function () { + testUtils.mock.intercept(form, "execute_action", function () { executeActionCount++; }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // make the record dirty - form.$('input').val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); - - form.$('button').eq(0).click(); + testUtils.dom.clickFirst(form.$('button')); assert.strictEqual(writeCount, 1, "should have triggered a write"); assert.strictEqual(executeActionCount, 1, "should have triggered a execute action"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input').val("abcdef").trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'abcdef'); - form.$('button').eq(1).click(); + testUtils.dom.click(form.$('button').eq(1)); assert.strictEqual(writeCount, 1, "should not have triggered a write"); assert.strictEqual(executeActionCount, 2, "should have triggered a execute action"); @@ -2035,8 +1953,8 @@ QUnit.module('Views', { }, }); - form.$('input').val("tralala").trigger('input'); // make the record dirty - form.$('button').click(); // click on Save + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); + testUtils.dom.click(form.$('button')); assert.verifySteps(['read', 'write', 'read', 'execute_action']); form.destroy(); @@ -2055,7 +1973,7 @@ QUnit.module('Views', { '', res_id: 1, }); - assert.strictEqual(form.$('.o_field_widget').length, 1, "should have rendered an abstract field"); + assert.containsOnce(form, '.o_field_widget'); form.destroy(); }); @@ -2081,18 +1999,18 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$("label.o_form_label").length, 2, "should have rendered only two label"); + assert.containsN(form, "label.o_form_label", 2); assert.strictEqual(form.$("label.o_form_label").first().text(), "Product", "one should be the one for the product field"); assert.strictEqual(form.$("label.o_form_label").eq(1).text(), "Bar", "one should be the one for the bar field"); - assert.strictEqual(form.$('.firstgroup td').first().attr('colspan'), undefined, + assert.hasAttrValue(form.$('.firstgroup td').first(), 'colspan', undefined, "foo td should have a default colspan (1)"); - assert.strictEqual(form.$('.secondgroup tr').length, 2, + assert.containsN(form, '.secondgroup tr', 2, "int_field and qux should have same tr"); - assert.strictEqual(form.$('.secondgroup tr:first td').length, 2, + assert.containsN(form, '.secondgroup tr:first td', 2, "product_id field should be on its own tr"); form.destroy(); }); @@ -2116,8 +2034,7 @@ QUnit.module('Views', { '', res_id: 1, }); - assert.strictEqual(form.$('td:contains(xphone)').length, 1, - "should display the name of the many2one"); + assert.containsOnce(form, 'td:contains(xphone)', "should display the name of the many2one"); form.destroy(); }); @@ -2151,18 +2068,17 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('td:contains(gold)').length, 1, + assert.containsOnce(form, 'td:contains(gold)', "should display the name of the many2many on the original form"); - form.$('td:contains(gold)').click(); + testUtils.dom.click(form.$('td:contains(gold)')); - assert.strictEqual($('.modal').length, 1, - 'The partner_type modal should have opened'); - assert.strictEqual($('.modal').find('td:contains(first record)').length, 1, + assert.containsOnce(document.body, '.modal'); + assert.containsOnce($('.modal'), 'td:contains(first record)', "should display the name of the many2many on the modal form"); - $('.modal').find('td:contains(first record)').click(); - assert.strictEqual($('.modal').length, 2, - 'There should be 2 modals (partner on top of partner_type) opened'); + testUtils.dom.click('.modal td:contains(first record)'); + assert.containsN(document.body, '.modal', 2, + "there should be 2 modals (partner on top of partner_type) opened"); form.destroy(); }); @@ -2186,12 +2102,12 @@ QUnit.module('Views', { }); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), 'yop', 'input should contain yop'); // click on discard - form.$buttons.find('.o_form_button_cancel').click(); - assert.ok(!$('.modal:visible').length, 'no confirm modal should be displayed'); + testUtils.form.clickDiscard(form); + assert.containsNone(document.body, '.modal', 'no confirm modal should be displayed'); assert.strictEqual(form.$('.o_field_widget').text(), 'yop', 'field in readonly should display yop'); assert.strictEqual(nbWrite, 0, 'no write RPC should have been done'); @@ -2217,21 +2133,21 @@ QUnit.module('Views', { }); // switch to edit mode and edit the foo field - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), 'yop', 'input should contain yop'); - form.$('input').val('new value').trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'new value'); assert.strictEqual(form.$('input').val(), 'new value', 'input should contain new value'); // click on discard and cancel the confirm request - form.$buttons.find('.o_form_button_cancel').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-secondary').click(); // click on cancel + testUtils.form.clickDiscard(form); + assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed"); + testUtils.dom.click('.modal-footer .btn-secondary'); assert.strictEqual(form.$('input').val(), 'new value', 'input should still contain new value'); // click on discard and confirm - form.$buttons.find('.o_form_button_cancel').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // click on confirm + testUtils.form.clickDiscard(form); + assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed"); + testUtils.dom.click('.modal-footer .btn-primary'); assert.strictEqual(form.$('.o_field_widget').text(), 'yop', 'field in readonly should display yop'); assert.strictEqual(nbWrite, 0, 'no write RPC should have been done'); @@ -2263,10 +2179,11 @@ QUnit.module('Views', { // really happens (mostly because the datepicker lib need that focus // event to properly focusout the input, otherwise it crashes later on // when the 'blur' event is triggered by the re-rendering) - form.$buttons.find('.o_form_button_cancel').focus().click(); - form.$buttons.find('.o_form_button_save').focus().click(); - assert.strictEqual(form.$('span:contains(2017)').length, 1, - "should have a span with the year somewhere"); + form.$buttons.find('.o_form_button_cancel').focus(); + testUtils.dom.click('.o_form_button_cancel'); + form.$buttons.find('.o_form_button_save').focus(); + testUtils.dom.click('.o_form_button_save'); + assert.containsOnce(form, 'span:contains(2017)'); form.destroy(); }); @@ -2274,7 +2191,6 @@ QUnit.module('Views', { QUnit.test('discard changes on relational data on new record', function (assert) { assert.expect(3); - var nbWrite = 0; var form = createView({ View: FormView, model: 'partner', @@ -2286,12 +2202,6 @@ QUnit.module('Views', { '' + '
' + '', - mockRPC: function (route) { - if (route === '/web/dataset/call_kw/partner/write') { - nbWrite++; - } - return this._super.apply(this, arguments); - }, intercepts: { history_back: function () { assert.ok(true, "should have sent correct event"); @@ -2304,18 +2214,16 @@ QUnit.module('Views', { }, }); - // switch to edit mode and edit the p field - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_field_many2one input').click(); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - $dropdown.find('li:first()').click(); + // edit the p field + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.fields.many2one.clickOpenDropdown('product_id'); + testUtils.fields.many2one.clickHighlightedItem('product_id'); assert.strictEqual(form.$('input').val(), 'xphone', 'input should contain xphone'); // click on discard and confirm - form.$buttons.find('.o_form_button_cancel').click(); - $('.modal-footer .btn-primary').click(); // click on confirm + testUtils.form.clickDiscard(form); + testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm assert.notOk(form.$el.prop('outerHTML').match('xphone'), "the string xphone should not be present after discarding"); @@ -2339,14 +2247,12 @@ QUnit.module('Views', { } }); - // switch to edit mode and edit the foo field - form.$buttons.find('.o_form_button_edit').click(); + // edit the foo field assert.strictEqual(form.$('input').val(), 'ABC', 'input should contain ABC'); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickDiscard(form); - assert.strictEqual($('.modal').length, 0, - 'there should not be a confirm modal'); + assert.containsNone(document.body, '.modal', 'there should not be a confirm modal'); form.destroy(); }); @@ -2374,22 +2280,21 @@ QUnit.module('Views', { }); // edit the foo field - assert.strictEqual(form.$('input').val(), 'ABC', 'input should contain ABC'); - form.$('input').val('DEF').trigger('input'); + assert.strictEqual(form.$('input').val(), 'ABC', 'input should contain ABC'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'DEF'); // discard the changes and check it has properly been discarded - form.$buttons.find('.o_form_button_cancel').click(); - assert.strictEqual($('.modal').length, 1, - 'there should be a confirm modal'); + testUtils.form.clickDiscard(form); + assert.containsOnce(document.body, '.modal', 'there should be a confirm modal'); assert.strictEqual(form.$('input').val(), 'DEF', 'input should be DEF'); - $('.modal-footer .btn-primary').click(); // click on confirm + testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm assert.strictEqual(form.$('input').val(), 'ABC', 'input should now be ABC'); // redirty and discard the field foo (to make sure initial changes haven't been lost) - form.$('input').val('GHI').trigger('input'); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.fields.editInput(form.$('input[name=foo]'), 'GHI'); + testUtils.form.clickDiscard(form); assert.strictEqual(form.$('input').val(), 'GHI', 'input should be GHI'); - $('.modal-footer .btn-primary').click(); // click on confirm + testUtils.dom.click('.modal-footer .btn-primary') // click on confirm assert.strictEqual(form.$('input').val(), 'ABC', 'input should now be ABC'); form.destroy(); @@ -2406,19 +2311,18 @@ QUnit.module('Views', { res_id: 1, viewOptions: {hasSidebar: true}, }); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); + testUtils.form.clickSave(form); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input').val("tralala").trigger('input'); - form.$buttons.find('.o_form_button_save').click(); - - form.sidebar.$('a:contains(Duplicate)').click(); + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); assert.strictEqual(form.$('input').val(), 'tralala', 'input should contain ABC'); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickDiscard(form); - assert.strictEqual($('.modal').length, 0, - 'there should not be a confirm modal'); + assert.containsNone(document.body, '.modal', 'there should not be a confirm modal'); form.destroy(); }); @@ -2449,24 +2353,24 @@ QUnit.module('Views', { assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2", 'pager limit should be 2'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), 'yop', 'input should contain yop'); // edit the foo field - form.$('input').val('new value').trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'new value'); assert.strictEqual(form.$('input').val(), 'new value', 'input should contain new value'); // click on the pager to switch to the next record and cancel the confirm request - form.pager.$('.o_pager_next').click(); // click on next - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-secondary').click(); // click on cancel + testUtils.dom.click('.o_pager_next'); // click on next + assert.containsOnce(document.body, '.modal', 'a confirm modal should be displayed'); + testUtils.dom.click('.modal-footer .btn-secondary'); // click on cancel assert.strictEqual(form.$('input').val(), 'new value', 'input should still contain new value'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should still be 1'); // click on the pager to switch to the next record and confirm - form.pager.$('.o_pager_next').click(); // click on next - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // click on confirm + testUtils.dom.click('.o_pager_next'); // click on next + assert.containsOnce(document.body, '.modal', 'a confirm modal should be displayed'); + testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm assert.strictEqual(form.$('input').val(), 'blip', 'input should contain blip'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); @@ -2494,43 +2398,43 @@ QUnit.module('Views', { assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), 'yop', 'input should contain yop'); // edit the foo field - form.$('input').val('new value').trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'new value'); assert.strictEqual(form.$('input').val(), 'new value', 'input should contain new value'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); // click on the pager to switch to the next record and cancel the confirm request - form.pager.$('.o_pager_next').click(); // click on next - assert.strictEqual($('.modal:visible').length, 0, 'no confirm modal should be displayed'); + testUtils.dom.click('.o_pager_next'); // click on next + assert.containsNone(document.body, '.modal:visible', 'no confirm modal should be displayed'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); - assert.strictEqual(form.$('.o_priority .fa-star-o').length, 2, + assert.containsN(form, '.o_priority .fa-star-o', 2, 'priority widget should have been rendered with correct value'); // edit the value in readonly - form.$('.o_priority .fa-star-o:first').click(); // click on the first star - assert.strictEqual(form.$('.o_priority .fa-star').length, 1, + testUtils.dom.click(form.$('.o_priority .fa-star-o:first')); // click on the first star + assert.containsOnce(form, '.o_priority .fa-star', 'priority widget should have been updated'); - form.pager.$('.o_pager_next').click(); // click on next - assert.strictEqual($('.modal:visible').length, 0, 'no confirm modal should be displayed'); + testUtils.dom.click('.o_pager_next'); // click on next + assert.containsNone(document.body, '.modal:visible', 'no confirm modal should be displayed'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input').val(), 'new value', 'input should contain yop'); // edit the foo field - form.$('input').val('wrong value').trigger('input'); + testUtils.fields.editInput(form.$('input[name=foo]'), 'wrong value'); - form.$buttons.find('.o_form_button_cancel').click(); - assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // click on confirm - form.pager.$('.o_pager_next').click(); // click on next + testUtils.form.clickDiscard(form); + assert.containsOnce(document.body, '.modal', 'a confirm modal should be displayed'); + testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm + testUtils.dom.click('.o_pager_next'); // click on next assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); form.destroy(); }); @@ -2560,20 +2464,16 @@ QUnit.module('Views', { }); // click on second page tab - form.$('.o_notebook .nav-link:eq(1)').click(); + testUtils.dom.click(form.$('.o_notebook .nav-link:eq(1)')); - assert.notOk(form.$('.o_notebook .nav-link:eq(0)').hasClass('active'), - "first tab should not be active"); - assert.ok(form.$('.o_notebook .nav-link:eq(1)').hasClass('active'), - "second tab should be active"); + assert.doesNotHaveClass(form.$('.o_notebook .nav-link:eq(0)'), 'active'); + assert.hasClass(form.$('.o_notebook .nav-link:eq(1)'), 'active'); // click on the pager to switch to the next record - form.pager.$('.o_pager_next').click(); + testUtils.dom.click('.o_pager_next'); - assert.notOk(form.$('.o_notebook .nav-link:eq(0)').hasClass('active'), - "first tab should not be active"); - assert.ok(form.$('.o_notebook .nav-link:eq(1)').hasClass('active'), - "second tab should be active"); + assert.doesNotHaveClass(form.$('.o_notebook .nav-link:eq(0)'), 'active'); + assert.hasClass(form.$('.o_notebook .nav-link:eq(1)'), 'active'); form.destroy(); }); @@ -2594,21 +2494,22 @@ QUnit.module('Views', { }, }); - assert.ok(form.pager.$el.is(':visible'), "pager should be visible"); + assert.isVisible(form.pager); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", "current pager value should be 1"); assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2", "current pager limit should be 1"); - form.$buttons.find('.o_form_button_create').click(); - assert.notOk(form.pager.$el.is(':visible'), "pager should not be visible"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickCreate(form); + assert.isNotVisible(form.pager); - assert.ok(form.pager.$el.is(':visible'), "pager should be visible"); + testUtils.form.clickSave(form); + assert.isVisible(form.pager); assert.strictEqual(form.pager.$('.o_pager_value').text(), "3", "current pager value should be 3"); assert.strictEqual(form.pager.$('.o_pager_limit').text(), "3", "current pager limit should be 3"); + form.destroy(); }); @@ -2636,7 +2537,7 @@ QUnit.module('Views', { assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); - form.pager.$('.o_pager_next').click(); // click on next + testUtils.dom.click(form.pager.$('.o_pager_next')); assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); @@ -2661,18 +2562,14 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('span.foo_field').length, 1, "should have a span foo field"); + assert.containsOnce(form, 'span.foo_field'); + assert.isNotVisible(form.$('span.foo_field')); - assert.ok(!form.$('span.foo_field').is(':visible'), - "foo field should not be visible"); + testUtils.form.clickCreate(form); - form.$buttons.find('.o_form_button_create').click(); + assert.containsOnce(form, 'input.foo_field'); + assert.isVisible(form.$('input.foo_field')); - assert.strictEqual(form.$('input.foo_field').length, 1, - "should have a visible input for foo field"); - - assert.ok(form.$('input.foo_field').is(':visible'), - "foo field should be visible"); form.destroy(); }); @@ -2695,13 +2592,11 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('.o_field_empty').length, 1, - 'readonly field should be invisible on an existing record'); + assert.containsOnce(form, '.o_field_empty'); - form.$buttons.find('.o_form_button_create').click(); + testUtils.form.clickCreate(form); - assert.strictEqual(form.$('.o_field_empty').length, 0, - 'readonly field should be visible on a new record'); + assert.containsNone(form, '.o_field_empty'); form.destroy(); }); @@ -2725,10 +2620,8 @@ QUnit.module('Views', { res_id: 1, }); - assert.ok(form.$('.inner_group').hasClass('o_group_col_6'), - "inner groups should have classname 'o_group_col_6'"); - assert.ok(form.$('.inner_div').hasClass('o_group_col_6'), - "divs inside groups should have classname 'o_group_col_6'"); + assert.hasClass(form.$('.inner_group'), 'o_group_col_6'), + assert.hasClass(form.$('.inner_div'), 'o_group_col_6'), form.destroy(); }); @@ -2754,14 +2647,14 @@ QUnit.module('Views', { 'should have a field with foo value for record 1'); assert.ok(!$('.modal:visible').length, 'no confirm modal should be displayed'); - // open sidebar - form.sidebar.$('button.o_dropdown_toggler_btn').click(); - form.sidebar.$('a:contains(Delete)').click(); + // open sidebar and delete + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); assert.ok($('.modal').length, 'a confirm modal should be displayed'); // confirm the delete - $('.modal-footer button.btn-primary').click(); + testUtils.dom.click($('.modal-footer button.btn-primary')); assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2", 'pager limit should be 2'); @@ -2791,14 +2684,14 @@ QUnit.module('Views', { }); // open sidebar, click on delete and confirm - form.sidebar.$('button.o_dropdown_toggler_btn').click(); - form.sidebar.$('a:contains(Delete)').click(); + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); - testUtils.intercept(form, 'history_back', function () { + testUtils.mock.intercept(form, 'history_back', function () { assert.step('history_back'); }); assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal-footer button.btn-primary').click(); + testUtils.dom.click($('.modal-footer button.btn-primary')); assert.strictEqual($('.modal').length, 0, 'no confirm modal should be displayed'); assert.verifySteps(['read', 'unlink', 'history_back']); @@ -2833,15 +2726,15 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_save').click(); - assert.ok(form.$('label').hasClass('o_field_invalid'), + testUtils.form.clickSave(form); + assert.hasClass(form.$('label'),'o_field_invalid', "label should be tagged as invalid"); - assert.ok(form.$('input').hasClass('o_field_invalid'), + assert.hasClass(form.$('input'),'o_field_invalid', "input should be tagged as invalid"); - form.$('input').val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input'), "tralala"); - assert.strictEqual(form.$('.o_field_invalid').length, 0, + assert.containsNone(form, '.o_field_invalid', "nothing should be marked as invalid"); form.destroy(); }); @@ -2869,32 +2762,32 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('.o_priority .o_priority_star').length, 2, + assert.containsN(form, '.o_priority .o_priority_star', 2, 'priority widget should have been rendered'); - assert.strictEqual(form.$('.o_priority .fa-star-o').length, 2, + assert.containsN(form, '.o_priority .fa-star-o', 2, 'priority widget should have been rendered with correct value'); // edit the value in readonly - form.$('.o_priority .fa-star-o:first').click(); // click on the first star + testUtils.dom.click(form.$('.o_priority .fa-star-o:first')); assert.strictEqual(nbWrite, 1, 'should have saved directly'); - assert.strictEqual(form.$('.o_priority .fa-star').length, 1, + assert.containsOnce(form, '.o_priority .fa-star', 'priority widget should have been updated'); // switch to edit mode and edit the value again - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('.o_priority .o_priority_star').length, 2, + testUtils.form.clickEdit(form); + assert.containsN(form, '.o_priority .o_priority_star', 2, 'priority widget should have been correctly rendered'); - assert.strictEqual(form.$('.o_priority .fa-star').length, 1, + assert.containsOnce(form, '.o_priority .fa-star', 'priority widget should have correct value'); - form.$('.o_priority .fa-star-o:first').click(); // click on the second star + testUtils.dom.click(form.$('.o_priority .fa-star-o:first')); assert.strictEqual(nbWrite, 1, 'should not have saved directly'); - assert.strictEqual(form.$('.o_priority .fa-star').length, 2, + assert.containsN(form, '.o_priority .fa-star', 2, 'priority widget should have been updated'); // save - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(nbWrite, 2, 'should not have saved directly'); - assert.strictEqual(form.$('.o_priority .fa-star').length, 2, + assert.containsN(form, '.o_priority .fa-star', 2, 'priority widget should have correct value'); form.destroy(); }); @@ -2936,12 +2829,12 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input[name=int_field]').val(), '9', "'int_field' value should be 9 before the change"); - form.$('input').first().val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input').first(), "tralala"); assert.strictEqual(form.$('input[name=int_field]').val(), '10', "the onchange should have been correctly applied"); @@ -3022,9 +2915,9 @@ QUnit.module('Views', { }); // go to edit mode, click to add a record in the o2m - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); - assert.strictEqual(form.$('tr.o_data_row').length, 0, + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + assert.containsNone(form, 'tr.o_data_row', "should not have added a line"); form.destroy(); }); @@ -3095,7 +2988,7 @@ QUnit.module('Views', { assert.strictEqual(form.$('.o_stat_text.o_not_hover:contains(Production Environment)').length, 1, "button should contain correct string"); - form.$buttons.find('.o_form_button_create').click(); + testUtils.form.clickCreate(form); assert.strictEqual(form.$('.o_stat_text.o_not_hover:contains(Test Environment)').length, 1, "button should contain correct string"); @@ -3121,19 +3014,19 @@ QUnit.module('Views', { }); // readonly mode - assert.strictEqual(form.$('.oe_stat_button').length, 1, + assert.containsOnce(form, '.oe_stat_button', "button box should be displayed in readonly"); // edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('.oe_stat_button').length, 1, + assert.containsOnce(form, '.oe_stat_button', "button box should be displayed in edit on an existing record"); // create mode (leave edition first!) - form.$buttons.find('.o_form_button_cancel').click(); - form.$buttons.find('.o_form_button_create').click(); - assert.strictEqual(form.$('.oe_stat_button').length, 1, + testUtils.form.clickDiscard(form); + testUtils.form.clickCreate(form); + assert.containsOnce(form, '.oe_stat_button', "button box should be displayed when creating a new record as well"); form.destroy(); @@ -3167,14 +3060,14 @@ QUnit.module('Views', { res_id: 1, }); - assert.strictEqual(form.$('.o_field_one2many .o_data_row').length, 1, + assert.containsOnce(form, '.o_field_one2many .o_data_row', "there should be one one2many record linked at first"); assert.strictEqual(form.$('.o_field_one2many .o_data_row td:first').text(), 'aaa', "the 'display_name' of the one2many record should be correct"); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); - form.$('input').val('let us trigger an onchange').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input'), 'let us trigger an onchange'); var $o2m = form.$('.o_field_one2many'); assert.strictEqual($o2m.find('.o_data_row').length, 2, "there should be two linked record"); @@ -3218,9 +3111,9 @@ QUnit.module('Views', { }); assert.strictEqual($('div[name="p"] .o_data_row td').text().trim(), "aaaNo records", "should have proper initial content"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('input').val("tralala").trigger('input'); + testUtils.fields.editInput(form.$('input'), "tralala"); assert.strictEqual($('div[name="p"] .o_data_row td').text().trim(), "goldNo records", "should have proper initial content"); @@ -3246,19 +3139,19 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_data_cell').first().click(); // edit first row - form.$('input').val('').trigger('input'); - form.$('.fa-trash-o').eq(1).click(); // delete second row + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_data_cell').first()); + testUtils.fields.editInput(form.$('input'), ''); + testUtils.dom.click(form.$('.fa-trash-o').eq(1)); assert.strictEqual($('.modal').find('.modal-title').first().text(), "Warning", "Clicking out of a dirty line while editing should trigger a warning modal."); - $('.modal').find('.btn-primary').click(); // discard changes + testUtils.dom.click($('.modal').find('.btn-primary')); assert.strictEqual(form.$('.o_data_cell').first().text(), "first record", "Value should have been reset to what it was before editing began."); - assert.strictEqual(form.$('.o_data_row').length, 1, + assert.containsOnce(form, '.o_data_row', "The other line should have been deleted."); form.destroy(); }); @@ -3303,12 +3196,12 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.$('.o_field_many2many .o_data_row').length, 0, + assert.containsNone(form, '.o_field_many2many .o_data_row', "there should be no many2many record linked at first"); // switch to edit mode - form.$buttons.find('.o_form_button_edit').click(); - form.$('input').val('let us trigger an onchange').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input'), 'let us trigger an onchange'); var $m2m = form.$('.o_field_many2many'); assert.strictEqual($m2m.find('.o_data_row').length, 2, "there should be two linked records"); @@ -3317,7 +3210,7 @@ QUnit.module('Views', { assert.strictEqual($m2m.find('.o_data_row:nth(1) td:first').text(), 'silver', "the 'display_name' of the second m2m record should be correctly displayed"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.verifySteps(['read', 'onchange', 'read', 'write', 'read', 'read']); @@ -3400,12 +3293,12 @@ QUnit.module('Views', { }); // trigger the onchange - form.$('.o_field_widget[name=foo]').val("coucou").trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), "coucou"); // open a subrecord and trigger an onchange readInModal = true; - form.$('.o_data_row .o_data_cell:first').click(); - $('.modal .o_field_widget[name=name]').val("new name").trigger('input'); + testUtils.dom.click(form.$('.o_data_row .o_data_cell:first')); + testUtils.fields.editInput($('.modal .o_field_widget[name=name]'), "new name"); form.destroy(); }); @@ -3443,7 +3336,7 @@ QUnit.module('Views', { assert.strictEqual(form.$('.o_field_widget[name=datetime]').text(), '12/12/2016 12:55:05', "the initial datetime should be correct"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_field_widget[name=date] input').val(), '01/25/2017', "the initial date should be correct in edit"); @@ -3451,7 +3344,7 @@ QUnit.module('Views', { '12/12/2016 12:55:05', "the initial datetime should be correct in edit"); // trigger the onchange - form.$('.o_field_widget[name="foo"]').val("coucou").trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name="foo"]'), "coucou"); assert.strictEqual(form.$('.o_field_widget[name=date] input').val(), '12/12/2021', "the initial date should be correct in edit"); @@ -3495,18 +3388,18 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - form.$('input').first().val("1").trigger('input'); + testUtils.fields.editInput(form.$('input').first(), "1"); assert.strictEqual(onchangeNbr, 0, "no onchange has been called yet"); - form.$('input').first().val("12").trigger('input'); + testUtils.fields.editInput(form.$('input').first(), "12"); assert.strictEqual(onchangeNbr, 0, "no onchange has been called yet"); return waitForFinishedOnChange().then(function () { assert.strictEqual(onchangeNbr, 1, "one onchange has been called"); // add something in the input, then focus another input - form.$('input').first().val("123").trigger('input'); + testUtils.fields.editInput(form.$('input').first(), "123"); form.$('input').first().change(); assert.strictEqual(onchangeNbr, 2, "one onchange has been called immediately"); @@ -3550,22 +3443,22 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // edit int_field, and check that an onchange has been applied - form.$('input[name="int_field"]').val("123").trigger('input'); + testUtils.fields.editInput(form.$('input[name="int_field"]'), "123"); assert.strictEqual(form.$('input[name="foo"]').val(), "123", "the onchange has been applied"); // enter an invalid value in a float, and check that no onchange has // been applied - form.$('input[name="int_field"]').val("123a").trigger('input'); + testUtils.fields.editInput(form.$('input[name="int_field"]'), "123a"); assert.strictEqual(form.$('input[name="foo"]').val(), "123", "the onchange has not been applied"); // save, and check that the int_field input is marked as invalid - form.$buttons.find('.o_form_button_save').click(); - assert.ok(form.$('input[name="int_field"]').hasClass('o_field_invalid'), + testUtils.form.clickSave(form); + assert.hasClass(form.$('input[name="int_field"]'),'o_field_invalid', "input int_field is marked as invalid"); assert.verifySteps(['read', 'onchange']); @@ -3590,7 +3483,7 @@ QUnit.module('Views', { } } }); - form.$('.o_form_button_update').click(); + testUtils.dom.click(form.$('.o_form_button_update')); }); QUnit.test('onchanges that complete after discarding', function (assert) { @@ -3626,14 +3519,14 @@ QUnit.module('Views', { // go into edit mode assert.strictEqual(form.$('span[name="foo"]').text(), "blip", "field foo should be displayed to initial value"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // edit a value - form.$('input').first().val("1234").trigger('input'); + testUtils.fields.editInput(form.$('input').first(), "1234"); // discard changes - form.$buttons.find('.o_form_button_cancel').click(); - $('.modal-footer .btn-primary').click(); + testUtils.form.clickDiscard(form); + testUtils.dom.click($('.modal-footer .btn-primary')); assert.strictEqual(form.$('span[name="foo"]').text(), "blip", "field foo should still be displayed to initial value"); @@ -3670,10 +3563,10 @@ QUnit.module('Views', { }, }); - form.$('input').val("1234").trigger('input'); + testUtils.fields.editInput(form.$('input'), "1234"); // save the value and discard directly - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.discardChanges(); // Simulate click on breadcrumb assert.strictEqual(form.$('.o_field_widget[name="foo"]').val(), "1234", @@ -3727,8 +3620,8 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input:first').val('trigger an onchange').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input:first'), 'trigger an onchange'); form.destroy(); }); @@ -3788,13 +3681,13 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input:first').val('trigger an onchange').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input:first'), 'trigger an onchange'); assert.strictEqual(form.$('.o_data_row td:first').text(), 'foo changed', "onchange should have been correctly applied on field in o2m list"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -3844,17 +3737,17 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_data_row td:first').text(), 'My little Foo Value', "the initial value should be the default one"); - form.$('input:first').val('trigger an onchange').trigger('input'); + testUtils.fields.editInput(form.$('input:first'), 'trigger an onchange'); assert.strictEqual(form.$('.o_data_row td:first').text(), 'foo changed', "onchange should have been correctly applied on field in o2m list"); - form.$('.o_data_row').click(); // edit the o2m in the dialog + testUtils.dom.click(form.$('.o_data_row')); assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: one2many field', "the field string is displayed in the modal title"); assert.strictEqual($('.modal .o_field_widget').val(), 'foo changed', @@ -3892,19 +3785,19 @@ QUnit.module('Views', { res_id: 2, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_data_row td:first').text(), 'My little Foo Value', "the initial value should be the default one"); - form.$('.o_data_row td:nth(1)').click(); // edit the o2m inline - form.$('.o_data_row input:nth(1)').val(77).trigger('input'); + testUtils.dom.click(form.$('.o_data_row td:nth(1)')); + testUtils.fields.editInput(form.$('.o_data_row input:nth(1)'), 77); assert.strictEqual(form.$('.o_data_row input:first').val(), '[blip] 77', "onchange should have been correctly applied"); // create a new o2m record - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('.o_data_row input:first').val(), '[blip] 14', "onchange should have been correctly applied after default get"); @@ -3943,26 +3836,26 @@ QUnit.module('Views', { res_id: 2, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('.o_data_row td:first').text(), 'My little Foo Value', "the initial value should be the default one"); - form.$('.o_data_row td:first').click(); // edit the o2m in a dialog - $('.modal input:nth(1)').val(77).trigger('input'); + testUtils.dom.click(form.$('.o_data_row td:first')); + testUtils.fields.editInput($('.modal input:nth(1)'), 77); assert.strictEqual($('.modal input:first').val(), '[blip] 77', "onchange should have been correctly applied"); - $('.modal-footer .btn-primary').click(); // save the dialog + testUtils.dom.click($('.modal-footer .btn-primary')); assert.strictEqual(form.$('.o_data_row td:first').text(), '[blip] 77', "onchange should have been correctly applied"); // create a new o2m record - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal .modal-title').text().trim(), 'Create custom label', "the custom field label is applied in the modal title"); assert.strictEqual($('.modal input:first').val(), '[blip] 14', "onchange should have been correctly applied after default get"); - $('.modal-footer .btn-primary').click(); // save the dialog + testUtils.dom.clickFirst($('.modal-footer .btn-primary')); assert.strictEqual(form.$('.o_data_row:nth(1) td:first').text(), '[blip] 14', "onchange should have been correctly applied after default get"); @@ -3997,8 +3890,8 @@ QUnit.module('Views', { res_id: 2, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input:first').val('coucou').trigger('input'); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input:first'), 'coucou'); form.destroy(); }); @@ -4023,7 +3916,7 @@ QUnit.module('Views', { }); // go to edit mode - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // focus first input, trigger tab form.$('input[name="foo"]').focus(); @@ -4110,7 +4003,7 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); form.$('input[name="foo"]').focus(); form.$('input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); assert.strictEqual(form.$('input[name="int_field"]')[0], document.activeElement, @@ -4149,7 +4042,7 @@ QUnit.module('Views', { }, }); - form.$('.oe_stat_button').click(); + testUtils.dom.click(form.$('.oe_stat_button')); form.destroy(); }); @@ -4183,7 +4076,7 @@ QUnit.module('Views', { }, }); - form.$('.oe_stat_button').click(); + testUtils.dom.click(form.$('.oe_stat_button')); form.destroy(); }); @@ -4206,7 +4099,7 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.$('button .o_field_widget').length, 1, + assert.containsOnce(form, 'button .o_field_widget', "a field widget should be display inside the button"); assert.strictEqual(form.$('button .o_field_widget').children().length, 2, "the field widget should have 2 children, the text and the value"); @@ -4235,9 +4128,9 @@ QUnit.module('Views', { assert.strictEqual(form.$('.oe_button_box').children().length, 2, "button box should contain two children"); - assert.strictEqual(form.$('.oe_button_box > .oe_stat_button').length, 1, + assert.containsOnce(form, '.oe_button_box > .oe_stat_button', "button box should only contain one button"); - assert.strictEqual(form.$('.oe_button_box > label').length, 1, + assert.containsOnce(form, '.oe_button_box > label', "button box should only contain one label"); form.destroy(); @@ -4309,7 +4202,7 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -4341,13 +4234,11 @@ QUnit.module('Views', { }); // add a o2m subrecord with a m2m tag - form.$('.o_field_x2many_list_row_add a').click(); - form.$('.o_many2many_tags_cell').click(); - form.$('.o_field_many2one input').click(); - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - $dropdown.find('li:first()').click(); // select the first tag + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.fields.many2one.clickOpenDropdown('timmy'); + testUtils.fields.many2one.clickHighlightedItem('timmy'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -4390,10 +4281,10 @@ QUnit.module('Views', { }); // add a o2m subrecord - form.$('.o_field_x2many_list_row_add a').click(); - $('.modal-body .o_field_one2many .o_field_x2many_list_row_add a').click(); - $('.modal-body input').val('xtv').trigger('input'); - $('.modal-footer button:first').click(); // save & close + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.dom.click($('.modal-body .o_field_one2many .o_field_x2many_list_row_add a')); + testUtils.fields.editInput($('.modal-body input'), 'xtv'); + testUtils.dom.click($('.modal-footer button:first')); assert.strictEqual($('.modal').length, 0, "dialog should be closed"); @@ -4401,7 +4292,7 @@ QUnit.module('Views', { assert.strictEqual(row.children()[0].textContent, '1 record', "the cell should contains the number of record: 1"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -4476,13 +4367,13 @@ QUnit.module('Views', { // bar being set to true, foo shouldn't be readonly and thus its value // could be saved, even if in its field description it is readonly - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); - assert.strictEqual(form.$('input[name="foo"]').length, 1, + assert.containsOnce(form, 'input[name="foo"]', "foo field should be editable"); - form.$('input[name="foo"]').val('New foo value').trigger('input'); + testUtils.fields.editInput(form.$('input[name="foo"]'), 'New foo value'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.strictEqual(form.$('.o_field_widget[name=foo]').text(), 'New foo value', "new value for foo field should have been saved"); @@ -4520,8 +4411,7 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); form.destroy(); }); @@ -4553,7 +4443,7 @@ QUnit.module('Views', { assert.deepEqual(getVisibleButtonTexts(), ["Hello", "World"], "only the first button section should be visible"); - form.$(".o_field_boolean input").click(); + testUtils.dom.click(form.$(".o_field_boolean input")); assert.deepEqual(getVisibleButtonTexts(), ["Foo"], "only the second button section should be visible"); @@ -4588,10 +4478,10 @@ QUnit.module('Views', { }, }); - assert.strictEqual(form.$('footer').length, 0, + assert.containsNone(form, 'footer', "footer should have been moved outside of the form view"); form.reload(); - assert.strictEqual(form.$('footer').length, 0, + assert.containsNone(form, 'footer', "footer should still have been moved outside of the form view"); form.destroy(); }); @@ -4633,7 +4523,7 @@ QUnit.module('Views', { '', res_id: 1, }).then(function (form) { - assert.strictEqual(form.$('.ace_editor').length, 1, + assert.containsOnce(form, '.ace_editor', "should have waited for ace to load its dependencies"); form.destroy(); done(); @@ -4689,7 +4579,7 @@ QUnit.module('Views', { var row = form.$('.o_field_one2many .o_list_view .o_data_row'); assert.strictEqual(row.children()[1].textContent, '1 record', "the cell should contains the number of record: 1"); - row.click(); + testUtils.dom.click(row); var modal_row = $('.modal-body .o_form_sheet .o_field_one2many .o_list_view .o_data_row'); assert.strictEqual(modal_row.children().length, 2, "the row should contains the 2 fields defined in the form view"); @@ -4713,7 +4603,7 @@ QUnit.module('Views', { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0], "foo field should have focus"); @@ -4736,7 +4626,7 @@ QUnit.module('Views', { '', res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0], "foo field should have focus"); @@ -4779,7 +4669,7 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); form.destroy(); }); @@ -4870,7 +4760,7 @@ QUnit.module('Views', { }, }); var row = form.$('.o_field_one2many .o_list_view .o_data_row'); - row.click(); + testUtils.dom.click(row); assert.verifySteps(['read', 'read', 'read'], "there should be 3 read rpcs"); form.destroy(); @@ -4913,9 +4803,9 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input[name="foo"]').val('').trigger("input"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name="foo"]'), ''); + testUtils.form.clickSave(form); def.resolve(); @@ -4969,14 +4859,15 @@ QUnit.module('Views', { var $customAction = $('.o_web_client .o_control_panel .btn-group .dropdown-menu:last .dropdown-item:nth(2)'); assert.strictEqual($customAction.text().trim(), 'Action partner', "the custom action should have 'Action partner' as name"); - testUtils.intercept(form, 'do_action', function (event) { + testUtils.mock.intercept(form, 'do_action', function (event) { var context = event.data.action.context.__contexts[1]; assert.strictEqual(context.active_id, 1, "the active_id shoud be 1."); assert.deepEqual(context.active_ids, [1], "the active_ids should be an array with 1 inside."); }); - $customAction.click(); + testUtils.dom.click($dropdowns); + testUtils.dom.click($customAction); form.destroy(); }); @@ -5027,9 +4918,9 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); // Open first dialog - form.$('.o_external_button').click(); + testUtils.dom.click(form.$('.o_external_button')); assert.strictEqual($('.modal').length, 1, "One FormViewDialog should be opened"); var $firstModal = $('.modal'); @@ -5039,20 +4930,20 @@ QUnit.module('Views', { "display_name should be correctly displayed"); // Open second dialog - $firstModal.find('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click($firstModal.find('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 2, "two FormViewDialogs should be opened"); var $secondModal = $('.modal:nth(1)'); // Add new value - $secondModal.find('input').val('xtv').trigger('input'); - $secondModal.find('.modal-footer button:first').click(); // Save & close + testUtils.fields.editInput($secondModal.find('input'), 'xtv'); + testUtils.dom.click($secondModal.find('.modal-footer button:first')); assert.strictEqual($('.modal').length, 1, "last opened dialog should be closed"); // Check that data in first dialog is correctly updated assert.strictEqual($firstModal.find('tr.o_data_row td').text(), 'xtv', "should have added a line with xtv as new record"); - $firstModal.find('.modal-footer button:first').click(); // Save & close + testUtils.dom.click($firstModal.find('.modal-footer button:first')); form.destroy(); }); @@ -5084,7 +4975,7 @@ QUnit.module('Views', { }, }); - form.$('input:first').click(); // trigger the name_search + testUtils.dom.click(form.$('input:first')); form.destroy(); }); @@ -5117,21 +5008,21 @@ QUnit.module('Views', { assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 2, "both tabs should be visible"); - assert.ok(form.$('.o_notebook .nav-link:first').hasClass('active'), + assert.hasClass(form.$('.o_notebook .nav-link:first'),'active', "first tab should be active"); // click on the pager to switch to the next record - form.pager.$('.o_pager_next').click(); + testUtils.dom.click(form.pager.$('.o_pager_next')); assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 1, "only the second tab should be visible"); - assert.ok(form.$('.o_notebook .nav-item:not(.o_invisible_modifier) .nav-link').hasClass('active'), + assert.hasClass(form.$('.o_notebook .nav-item:not(.o_invisible_modifier) .nav-link'),'active', "the visible tab should be active"); // click on the pager to switch back to the previous record - form.pager.$('.o_pager_previous').click(); + testUtils.dom.click(form.pager.$('.o_pager_previous')); assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 2, "both tabs should be visible again"); - assert.ok(form.$('.o_notebook .nav-link:nth(1)').hasClass('active'), + assert.hasClass(form.$('.o_notebook .nav-link:nth(1)'),'active', "second tab should be active"); form.destroy(); @@ -5155,7 +5046,7 @@ QUnit.module('Views', { } } }); - form.$('a[type="action"]').click(); + testUtils.dom.click(form.$('a[type="action"]')); form.destroy(); }); @@ -5252,14 +5143,14 @@ QUnit.module('Views', { assert.ok(form.$('.o_field_one2many tbody tr:first td:contains(yop)').length, "record 1 should be first"); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 1, "FormViewDialog should be opened"); - $('.modal input[name="foo"]').val('xop').trigger("input"); - $('.modal-footer button:eq(1)').click(); // Save & new - $('.modal input[name="foo"]').val('zop').trigger("input"); - $('.modal-footer button:first').click(); // Save & close + testUtils.fields.editInput($('.modal input[name="foo"]'), 'xop') + testUtils.dom.click($('.modal-footer button:eq(1)')); + testUtils.fields.editInput($('.modal input[name="foo"]'), 'zop') + testUtils.dom.click($('.modal-footer button:first')); // client-side sort assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zop)').length, @@ -5270,7 +5161,7 @@ QUnit.module('Views', { "record xop should be third"); // server-side sort - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zop)').length, "record zop should be first"); assert.ok(form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)').length, @@ -5279,10 +5170,10 @@ QUnit.module('Views', { "record xop should be third"); // client-side sort on edit - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)').click(); - $('.modal input[name="foo"]').val('zzz').trigger("input"); - $('.modal-footer button:first').click(); // Save + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)')); + testUtils.fields.editInput($('.modal input[name="foo"]'), 'zzz') + testUtils.dom.click($('.modal-footer button:first')); assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zzz)').length, "record zzz should be first"); assert.ok(form.$('.o_field_one2many tbody tr:eq(1) td:contains(zop)').length, @@ -5317,8 +5208,8 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('div[name="trululu"] input').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('div[name="trululu"] input')); form.destroy(); }); @@ -5391,18 +5282,18 @@ QUnit.module('Views', { assert.strictEqual($group4rows.length, 3, "there should be 3 rows in .group_4"); var $group4firstRowTd = $group4rows.eq(0).children('td'); assert.strictEqual($group4firstRowTd.length, 1, "there should be 1 td in first row"); - assert.strictEqual($group4firstRowTd.attr('colspan'), "3", "the first td colspan should be 3"); + assert.hasAttrValue($group4firstRowTd, 'colspan', "3", "the first td colspan should be 3"); assert.strictEqual($group4firstRowTd.attr('style').substr(0, 9), "width: 75", "the first td should be 75% width"); assert.strictEqual($group4firstRowTd.children()[0].tagName, "DIV", "the first td should contain a div"); var $group4secondRowTds = $group4rows.eq(1).children('td'); assert.strictEqual($group4secondRowTds.length, 2, "there should be 2 tds in second row"); - assert.strictEqual($group4secondRowTds.eq(0).attr('colspan'), "2", "the first td colspan should be 2"); + assert.hasAttrValue($group4secondRowTds.eq(0), 'colspan', "2", "the first td colspan should be 2"); assert.strictEqual($group4secondRowTds.eq(0).attr('style').substr(0, 9), "width: 50", "the first td be 50% width"); - assert.strictEqual($group4secondRowTds.eq(1).attr('colspan'), undefined, "the second td colspan should be default one (1)"); + assert.hasAttrValue($group4secondRowTds.eq(1), 'colspan', undefined, "the second td colspan should be default one (1)"); assert.strictEqual($group4secondRowTds.eq(1).attr('style').substr(0, 9), "width: 25", "the second td be 75% width"); var $group4thirdRowTd = $group4rows.eq(2).children('td'); assert.strictEqual($group4thirdRowTd.length, 1, "there should be 1 td in third row"); - assert.strictEqual($group4thirdRowTd.attr('colspan'), "4", "the first td colspan should be 4"); + assert.hasAttrValue($group4thirdRowTd, 'colspan', "4", "the first td colspan should be 4"); assert.strictEqual($group4thirdRowTd.attr('style').substr(0, 10), "width: 100", "the first td should be 100% width"); // Verify .group_3 content @@ -5417,32 +5308,32 @@ QUnit.module('Views', { assert.strictEqual($fieldGroupRows.length, 5, "there should be 5 rows in .field_group"); var $fieldGroupFirstRowTds = $fieldGroupRows.eq(0).children('td'); assert.strictEqual($fieldGroupFirstRowTds.length, 2, "there should be 2 tds in first row"); - assert.ok($fieldGroupFirstRowTds.eq(0).hasClass('o_td_label'), "first td should be a label td"); - assert.strictEqual($fieldGroupFirstRowTds.eq(1).attr('colspan'), "2", "second td colspan should be given colspan (3) - 1 (label)"); + assert.hasClass($fieldGroupFirstRowTds.eq(0),'o_td_label', "first td should be a label td"); + assert.hasAttrValue($fieldGroupFirstRowTds.eq(1), 'colspan', "2", "second td colspan should be given colspan (3) - 1 (label)"); assert.strictEqual($fieldGroupFirstRowTds.eq(1).attr('style').substr(0, 10), "width: 100", "second td width should be 100%"); var $fieldGroupSecondRowTds = $fieldGroupRows.eq(1).children('td'); assert.strictEqual($fieldGroupSecondRowTds.length, 2, "there should be 2 tds in second row"); - assert.strictEqual($fieldGroupSecondRowTds.eq(0).attr('colspan'), undefined, "first td colspan should be default one (1)"); + assert.hasAttrValue($fieldGroupSecondRowTds.eq(0), 'colspan', undefined, "first td colspan should be default one (1)"); assert.strictEqual($fieldGroupSecondRowTds.eq(0).attr('style').substr(0, 9), "width: 33", "first td width should be 33.3333%"); - assert.strictEqual($fieldGroupSecondRowTds.eq(1).attr('colspan'), undefined, "second td colspan should be default one (1)"); + assert.hasAttrValue($fieldGroupSecondRowTds.eq(1), 'colspan', undefined, "second td colspan should be default one (1)"); assert.strictEqual($fieldGroupSecondRowTds.eq(1).attr('style').substr(0, 9), "width: 33", "second td width should be 33.3333%"); var $fieldGroupThirdRowTds = $fieldGroupRows.eq(2).children('td'); // new row as label/field pair colspan is greater than remaining space assert.strictEqual($fieldGroupThirdRowTds.length, 2, "there should be 2 tds in third row"); - assert.ok($fieldGroupThirdRowTds.eq(0).hasClass('o_td_label'), "first td should be a label td"); - assert.strictEqual($fieldGroupThirdRowTds.eq(1).attr('colspan'), undefined, "second td colspan should be default one (1)"); + assert.hasClass($fieldGroupThirdRowTds.eq(0),'o_td_label', "first td should be a label td"); + assert.hasAttrValue($fieldGroupThirdRowTds.eq(1), 'colspan', undefined, "second td colspan should be default one (1)"); assert.strictEqual($fieldGroupThirdRowTds.eq(1).attr('style').substr(0, 9), "width: 50", "second td should be 50% width"); var $fieldGroupFourthRowTds = $fieldGroupRows.eq(3).children('td'); assert.strictEqual($fieldGroupFourthRowTds.length, 1, "there should be 1 td in fourth row"); - assert.strictEqual($fieldGroupFourthRowTds.attr('colspan'), "3", "the td should have a colspan equal to 3"); + assert.hasAttrValue($fieldGroupFourthRowTds, 'colspan', "3", "the td should have a colspan equal to 3"); assert.strictEqual($fieldGroupFourthRowTds.attr('style').substr(0, 10), "width: 100", "the td should have 100% width"); var $fieldGroupFifthRowTds = $fieldGroupRows.eq(4).children('td'); // label/field pair can be put after the 1-colspan span assert.strictEqual($fieldGroupFifthRowTds.length, 3, "there should be 3 tds in fourth row"); assert.strictEqual($fieldGroupFifthRowTds.eq(0).attr('style').substr(0, 9), "width: 50", "the first td should 50% width"); - assert.ok($fieldGroupFifthRowTds.eq(1).hasClass('o_td_label'), "the second td should be a label td"); + assert.hasClass($fieldGroupFifthRowTds.eq(1),'o_td_label', "the second td should be a label td"); assert.strictEqual($fieldGroupFifthRowTds.eq(2).attr('style').substr(0, 9), "width: 50", "the third td should 50% width"); // Verify that one2many list table hasn't been impacted - assert.strictEqual(form.$('.o_field_one2many th:first').attr('style'), undefined, + assert.hasAttrValue(form.$('.o_field_one2many th:first'), 'style', undefined, "o2m list columns should have no width harcoded"); form.destroy(); @@ -5474,7 +5365,7 @@ QUnit.module('Views', { var $group1 = form.$('.group_1'); var $group2 = form.$('.group_2'); - assert.strictEqual(form.$('table.o_inner_group').length, 2, + assert.containsN(form, 'table.o_inner_group', 2, "should contain two inner groups"); assert.strictEqual($group1.find('.o_horizontal_separator').length, 1, "inner group should contain one string separator"); @@ -5527,15 +5418,15 @@ QUnit.module('Views', { }); // Inner group - assert.strictEqual(form.$('.main_inner_group > tbody > tr').length, 2, + assert.containsN(form, '.main_inner_group > tbody > tr', 2, "there should be 2 rows in the group"); - assert.strictEqual(form.$('.main_inner_group > tbody > tr:first > .o_td_label').length, 1, + assert.containsOnce(form, '.main_inner_group > tbody > tr:first > .o_td_label', "there should be only one label in the first row"); - assert.strictEqual(form.$('.main_inner_group > tbody > tr:first .o_field_widget').length, 1, + assert.containsOnce(form, '.main_inner_group > tbody > tr:first .o_field_widget', "there should be only one widget in the first row"); - assert.strictEqual(form.$('.main_inner_group > tbody > tr:last > .o_td_label').length, 2, + assert.containsN(form, '.main_inner_group > tbody > tr:last > .o_td_label', 2, "there should be two labels in the second row"); - assert.strictEqual(form.$('.main_inner_group > tbody > tr:last .o_field_widget').length, 2, + assert.containsN(form, '.main_inner_group > tbody > tr:last .o_field_widget', 2, "there should be two widgets in the second row"); // Outer group @@ -5567,7 +5458,7 @@ QUnit.module('Views', { res_id: 1, }); - form.$('.o_data_row:first').click(); + testUtils.dom.click(form.$('.o_data_row:first')); assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: custom label', "modal should use the python field string as title"); @@ -5596,11 +5487,11 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input[name="foo"]').val("test").trigger("input"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name="foo"]'), "test"); + testUtils.form.clickSave(form); - assert.strictEqual(form.$('.o_form_view > .alert > div').length, 1,"should have a translation alert"); + assert.containsOnce(form, '.o_form_view > .alert > div',"should have a translation alert"); form.destroy(); @@ -5651,13 +5542,13 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('[name="product_id"] .o_external_button').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('[name="product_id"] .o_external_button')); assert.strictEqual($('.modal-body .o_field_translate').length, 1, "there should be a translate button in the modal"); - $('.modal-body .o_field_translate').click(); + testUtils.dom.click($('.modal-body .o_field_translate')); assert.strictEqual(nbTranslateCalls, 1, "should call_button translate once"); @@ -5707,14 +5598,14 @@ QUnit.module('Views', { assert.strictEqual(form.$('.oe_button_box button:not(:disabled)').length, 1, "stat buttons should be enabled"); - form.$('.o_form_statusbar button').click(); + testUtils.dom.clickFirst(form.$('.o_form_statusbar button')); // The unresolved deferred lets us check the state of the buttons assert.strictEqual(form.$buttons.find('button:disabled').length, 4, "control panel buttons should be disabled"); - assert.strictEqual(form.$('.o_form_statusbar button:disabled').length, 2, + assert.containsN(form, '.o_form_statusbar button:disabled', 2, "status bar buttons should be disabled"); - assert.strictEqual(form.$('.oe_button_box button:disabled').length, 1, + assert.containsOnce(form, '.oe_button_box button:disabled', "stat buttons should be disabled"); def.resolve(); @@ -5771,14 +5662,14 @@ QUnit.module('Views', { assert.strictEqual(form.$('.oe_button_box button:not(:disabled)').length, 1, "stat buttons should be enabled"); - form.$('.oe_button_box button').click(); + testUtils.dom.click(form.$('.oe_button_box button')); // The unresolved deferred lets us check the state of the buttons assert.strictEqual(form.$buttons.find('button:disabled').length, 4, "control panel buttons should be disabled"); - assert.strictEqual(form.$('.o_form_statusbar button:disabled').length, 2, + assert.containsN(form, '.o_form_statusbar button:disabled', 2, "status bar buttons should be disabled"); - assert.strictEqual(form.$('.oe_button_box button:disabled').length, 1, + assert.containsOnce(form, '.oe_button_box button:disabled', "stat buttons should be disabled"); def.resolve(); @@ -5821,19 +5712,19 @@ QUnit.module('Views', { }); // click on button, and cancel in confirm dialog - form.$('.o_statusbar_buttons button').click(); + testUtils.dom.click(form.$('.o_statusbar_buttons button')); assert.ok(form.$('.o_statusbar_buttons button').prop('disabled'), 'button should be disabled'); - $('.modal-footer button.btn-secondary').click(); + testUtils.dom.click($('.modal-footer button.btn-secondary')); assert.ok(!form.$('.o_statusbar_buttons button').prop('disabled'), 'button should no longer be disabled'); assert.verifySteps(['default_get']); // click on button, and click on ok in confirm dialog - form.$('.o_statusbar_buttons button').click(); + testUtils.dom.click(form.$('.o_statusbar_buttons button')); assert.verifySteps(['default_get']); - $('.modal-footer button.btn-primary').click(); + testUtils.dom.click($('.modal-footer button.btn-primary')); assert.verifySteps(['default_get', 'create', 'read', 'execute_action']); @@ -5887,12 +5778,12 @@ QUnit.module('Views', { }, }); - form.$('.o_external_button').click(); + testUtils.dom.click(form.$('.o_external_button')); assert.notOk($('.modal .oe_button_box button').attr('disabled'), "stat buttons should be enabled"); - $('.modal .oe_button_box button').click(); + testUtils.dom.click($('.modal .oe_button_box button')); assert.ok($('.modal .oe_button_box button').attr('disabled'), "stat buttons should be disabled"); @@ -5935,10 +5826,10 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input[name="foo"]').val("test").trigger("input"); - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name="foo"]'), "test"); + testUtils.form.clickSave(form); + testUtils.form.clickSave(form); def.resolve(); @@ -5975,13 +5866,13 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('input[name="foo"]').val("incorrect value").trigger("input"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickEdit(form); + testUtils.fields.editInput(form.$('input[name="foo"]'), "incorrect value"); + testUtils.form.clickSave(form); - form.$('input[name="foo"]').val("correct value").trigger("input"); + testUtils.fields.editInput(form.$('input[name="foo"]'), "correct value"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.verifySteps([ 'read', // initial read to render the view @@ -6008,7 +5899,7 @@ QUnit.module('Views', { assert.strictEqual(form.$('span[name="foo"]').text(), '***', "password should be displayed with stars"); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.strictEqual(form.$('input[name="foo"]').val(), 'yop', "input value should be the password"); assert.strictEqual(form.$('input[name="foo"]').prop('type'), 'password', @@ -6029,8 +5920,8 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); - assert.strictEqual(form.$('input[name="display_name"]').attr('autocomplete'), 'coucou', + testUtils.form.clickEdit(form); + assert.hasAttrValue(form.$('input[name="display_name"]'), 'autocomplete', 'coucou', "attribute autocomplete should be set"); form.destroy(); }); @@ -6071,18 +5962,17 @@ QUnit.module('Views', { }, }); - form.$buttons.find('.o_form_button_edit').click(); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal').length, 1, "One FormViewDialog should be opened"); // set a value on the m2o - var $dropdown = form.$('.o_field_many2one input').autocomplete('widget'); - $('.modal .o_field_many2one input').click(); - $dropdown.find('li:first()').click(); + testUtils.fields.many2one.clickOpenDropdown('partner_type_id'); + testUtils.fields.many2one.clickHighlightedItem('partner_type_id'); - $('.modal-footer button:eq(1)').click(); // Save & new - $('.modal .o_field_many2one input').click(); - $('.modal-footer button:first').click(); // Save & close + testUtils.dom.click($('.modal-footer button:eq(1)')); + testUtils.dom.click($('.modal .o_field_many2one input')); + testUtils.dom.click($('.modal-footer button:first')); form.destroy(); }); @@ -6119,7 +6009,7 @@ QUnit.module('Views', { assert.strictEqual(form.$('.o_field_widget[name="display_name"]').text(), "Select a model to add a filter.", "should contain an error message saying the model is missing"); - form.$('input[name="model_name"]').val("test").trigger("input"); + testUtils.fields.editInput(form.$('input[name="model_name"]'), "test"); assert.notStrictEqual(form.$('.o_field_widget[name="display_name"]').text(), "Select a model to add a filter.", "should not contain an error message anymore"); form.destroy(); @@ -6171,23 +6061,23 @@ QUnit.module('Views', { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual($('.modal input.o_field_widget[name=foo]').length, 1, 'foo should be editable'); checkOnchange = true; - $('.modal .o_field_widget[name=foo]').val('foo value').trigger('input'); - $('.modal .o_field_widget[name=display_name]').val('readonly').trigger('input'); + testUtils.fields.editInput($('.modal .o_field_widget[name=foo]'), 'foo value'); + testUtils.fields.editInput($('.modal .o_field_widget[name=display_name]'), 'readonly'); assert.strictEqual($('.modal span.o_field_widget[name=foo]').length, 1, 'foo should be readonly'); - $('.modal-footer .btn-primary').click(); // close the modal + testUtils.dom.clickFirst($('.modal-footer .btn-primary')); checkOnchange = false; - form.$('.o_data_row').click(); // re-open previous record + testUtils.dom.click(form.$('.o_data_row')); assert.strictEqual($('.modal .o_field_widget[name=foo]').text(), 'foo value', "the edited value should have been kept"); - $('.modal-footer .btn-primary').click(); // close the modal + testUtils.dom.clickFirst($('.modal-footer .btn-primary')); - form.$buttons.find('.o_form_button_save').click(); // save the record + testUtils.form.clickSave(form); // save the record form.destroy(); }); @@ -6205,13 +6095,13 @@ QUnit.module('Views', { '', }); - assert.ok(form.$('.o_field_widget[name=foo]').hasClass('o_readonly_modifier'), + assert.hasClass(form.$('.o_field_widget[name=foo]'),'o_readonly_modifier', "foo should be readonly in 'Create' mode"); - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickSave(form); + testUtils.form.clickEdit(form); - assert.notOk(form.$('.o_field_widget[name=foo]').hasClass('o_readonly_modifier'), + assert.doesNotHaveClass(form.$('.o_field_widget[name=foo]'), 'o_readonly_modifier', "foo should not be readonly anymore"); form.destroy(); @@ -6246,16 +6136,21 @@ QUnit.module('Views', { }, }); - form.sidebar.$('a:contains(Duplicate)').click(); // duplicate record 1 - assert.strictEqual(form.$('.o_form_editable').length, 1, + // duplicate record 1 + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); + assert.containsOnce(form, '.o_form_editable', "form should be in edit mode"); assert.strictEqual(form.$('.o_field_widget').val(), 'first record (copy)', "duplicated record should have correct name"); - form.$buttons.find('.o_form_button_save').click(); // save duplicated record + testUtils.form.clickSave(form); // save duplicated record + + // delete duplicated record + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); - form.sidebar.$('a:contains(Delete)').click(); // delete duplicated record assert.strictEqual($('.modal').length, 1, "should have opened a confirm dialog"); - $('.modal-footer .btn-primary').click(); // confirm + testUtils.dom.click($('.modal-footer .btn-primary')); assert.strictEqual(form.$('.o_field_widget').text(), 'first record', "should have come back to previous record"); @@ -6335,11 +6230,11 @@ QUnit.module('Views', { }, }); - form.$('.o_external_button').click(); // open the many2one record in a modal - $('.modal .o_external_button').click(); // in the modal, open the many2one record in another modal + testUtils.dom.click(form.$('.o_external_button')); + testUtils.dom.click($('.modal .o_external_button')); - $('.modal:nth(1) .o_field_widget[name=display_name]').val('new name').trigger('input'); - $('.modal:nth(1) footer .btn-primary').first().click(); // save changes + testUtils.fields.editInput($('.modal:nth(1) .o_field_widget[name=display_name]'), 'new name'); + testUtils.dom.click($('.modal:nth(1) footer .btn-primary').first()); assert.strictEqual($('.modal .o_field_widget[name=trululu] input').val(), 'new name', "record should have been reloaded"); @@ -6380,7 +6275,7 @@ QUnit.module('Views', { context: {hide_bar: true}, }, }); - assert.strictEqual(form.$('.o_list_view thead tr th').length, 1, + assert.containsOnce(form, '.o_list_view thead tr th', "there should be only one column"); form.destroy(); }); @@ -6408,7 +6303,7 @@ QUnit.module('Views', { context: {hide_bar: true}, }, }); - assert.strictEqual(form.$('.o_list_view thead tr th').length, 1, + assert.containsOnce(form, '.o_list_view thead tr th', "there should be only one column"); form.destroy(); }); @@ -6443,11 +6338,11 @@ QUnit.module('Views', { }, viewOptions: {mode: 'edit'}, }); - form.$('.o_external_button').click(); + testUtils.dom.click(form.$('.o_external_button')); assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "yopblip", "table has some initial order"); - $('.modal-body .o_form_view .o_list_view th').click(); + testUtils.dom.click($('.modal-body .o_form_view .o_list_view th')); assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "blipyop", "table is now sorted"); form.destroy(); @@ -6473,7 +6368,7 @@ QUnit.module('Views', { } }); - form.$('.o_form_statusbar .btn-secondary').click(); + testUtils.dom.click(form.$('.o_form_statusbar .btn-secondary')); form.destroy(); }); @@ -6522,7 +6417,7 @@ QUnit.module('Views', { '', }); - assert.strictEqual(form.$('button.o_attachment_button').length, 1, + assert.containsOnce(form, 'button.o_attachment_button', "should have 1 attach_document widget in the statusbar"); assert.strictEqual(form.$('span.o_attach_document').text().trim(), 'Attach document', "widget should have been instantiated"); @@ -6556,7 +6451,7 @@ QUnit.module('Views', { '', }); - form.$('input[name="foo"]').val("I am alive").trigger('input'); + testUtils.fields.editInput(form.$('input[name="foo"]'), "I am alive"); assert.strictEqual(form.$('.o_widget').text(), 'I am alive!', "widget should have been updated"); @@ -6586,12 +6481,12 @@ QUnit.module('Views', { }); // in readonly - form.$('[name="display_name"]').click(); + testUtils.dom.click(form.$('[name="display_name"]')); assert.verifySteps(['bounce']); // in edit - form.$buttons.find('.o_form_button_edit').click(); - form.$('[name="display_name"]').click(); + testUtils.form.clickEdit(form); + testUtils.dom.click(form.$('[name="display_name"]')); assert.verifySteps(['bounce']); form.destroy(); @@ -6653,7 +6548,7 @@ QUnit.module('Views', { }); // switch to edit mode to ensure that autoresize is correctly done - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); var height = form.$('.o_field_widget[name=text_field]').height(); // focus the field to manually trigger autoresize form.$('.o_field_widget[name=text_field]').trigger('focus'); @@ -6664,8 +6559,8 @@ QUnit.module('Views', { assert.ok(height > 80, "textarea should have an height of at least 80px"); // save and create a new record to ensure that autoresize is correctly done - form.$buttons.find('.o_form_button_save').click(); - form.$buttons.find('.o_form_button_create').click(); + testUtils.form.clickSave(form); + testUtils.form.clickCreate(form); height = form.$('.o_field_widget[name=text_field]').height(); // focus the field to manually trigger autoresize form.$('.o_field_widget[name=text_field]').trigger('focus'); @@ -6680,7 +6575,7 @@ QUnit.module('Views', { assert.expect(1); var instanceNumber = 0; - testUtils.patch(mixins.ParentedMixin, { + testUtils.mock.patch(mixins.ParentedMixin, { init: function () { instanceNumber++; return this._super.apply(this, arguments); @@ -6751,7 +6646,7 @@ QUnit.module('Views', { form.destroy(); - testUtils.unpatch(mixins.ParentedMixin); + testUtils.mock.unpatch(mixins.ParentedMixin); }); QUnit.test('do not change pager when discarding current record', function (assert) { @@ -6774,8 +6669,8 @@ QUnit.module('Views', { assert.strictEqual(form.pager.$('.o_pager_counter').text().trim(), '2 / 2', 'pager should indicate that we are on second record'); - form.$buttons.find('.o_form_button_edit').click(); - form.$buttons.find('.o_form_button_cancel').click(); + testUtils.form.clickEdit(form); + testUtils.form.clickDiscard(form); assert.strictEqual(form.pager.$('.o_pager_counter').text().trim(), '2 / 2', 'pager should not have changed'); @@ -6786,7 +6681,7 @@ QUnit.module('Views', { QUnit.test('edition in form view on a "noCache" model', function (assert) { assert.expect(4); - testUtils.patch(BasicModel, { + testUtils.mock.patch(BasicModel, { noCacheModels: BasicModel.prototype.noCacheModels.concat(['partner']), }); @@ -6812,19 +6707,19 @@ QUnit.module('Views', { }); core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache')); - form.$('.o_field_widget[name=display_name]').val('new value').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value'); + testUtils.form.clickSave(form); assert.verifySteps(['write', 'clear_cache']); form.destroy(); - testUtils.unpatch(BasicModel); + testUtils.mock.unpatch(BasicModel); }); QUnit.test('creation in form view on a "noCache" model', function (assert) { assert.expect(4); - testUtils.patch(BasicModel, { + testUtils.mock.patch(BasicModel, { noCacheModels: BasicModel.prototype.noCacheModels.concat(['partner']), }); @@ -6846,19 +6741,19 @@ QUnit.module('Views', { }); core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache')); - form.$('.o_field_widget[name=display_name]').val('value').trigger('input'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'value'); + testUtils.form.clickSave(form); assert.verifySteps(['create', 'clear_cache']); form.destroy(); - testUtils.unpatch(BasicModel); + testUtils.mock.unpatch(BasicModel); }); QUnit.test('deletion in form view on a "noCache" model', function (assert) { assert.expect(4); - testUtils.patch(BasicModel, { + testUtils.mock.patch(BasicModel, { noCacheModels: BasicModel.prototype.noCacheModels.concat(['partner']), }); @@ -6877,19 +6772,21 @@ QUnit.module('Views', { } return this._super.apply(this, arguments); }, + res_id: 1, viewOptions: { hasSidebar: true, }, }); core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache')); - form.sidebar.$('a:contains(Delete)').click(); - $('.modal-footer .btn-primary').click(); // confirm + testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); + testUtils.dom.click($('.modal-footer .btn-primary')); assert.verifySteps(['unlink', 'clear_cache']); form.destroy(); - testUtils.unpatch(BasicModel); + testUtils.mock.unpatch(BasicModel); }); QUnit.test('a popup window should automatically close after a do_action event', function (assert) { @@ -6926,10 +6823,10 @@ QUnit.module('Views', { }, }); // Open one2many - form.$('.o_data_row').click(); + testUtils.dom.click(form.$('.o_data_row')); assert.strictEqual($('.modal-content').length, 1, "a popup window should have opened"); // Click on many2one and trigger do_action - $('.modal-content a[name="partner_type_id"]').click(); + testUtils.dom.click($('.modal-content a[name="partner_type_id"]')); assert.strictEqual($('.modal-content').length, 0, "the popup window should have closed"); form.destroy(); @@ -6976,11 +6873,11 @@ QUnit.module('Views', { }, }); // Open two one2manys - form.$('.o_data_row').click(); - $('.modal-content .o_data_row').click(); + testUtils.dom.click(form.$('.o_data_row')); + testUtils.dom.click($('.modal-content .o_data_row')); assert.strictEqual($('.modal-content').length, 2, "Two popup windows should have opened."); // Click on many2one and trigger do_action - $('.modal-content a[name="partner_type_id"]').click(); + testUtils.dom.click($('.modal-content a[name="partner_type_id"]')); assert.strictEqual($('.modal-content').length, 0, "All popup windows should have closed."); form.destroy(); @@ -7070,7 +6967,7 @@ QUnit.module('Views', { '' + '', }).then(function(form) { - assert.strictEqual(form.$('div.o_widget').length, 1, + assert.containsOnce(form, 'div.o_widget', "there should be a div with widget class"); form.destroy(); delete widgetRegistry.map.test; @@ -7106,12 +7003,12 @@ QUnit.module('Views', { fieldDebounce: 5000, }); - form.$('input').val('some foo value').trigger('input'); + testUtils.fields.editInput(form.$('input'), 'some foo value'); // manually save the record, to prevent the field widget to notify the model of its new // value before being requested to form.saveRecord(); - assert.strictEqual(form.$('.o_form_readonly').length, 1, + assert.containsOnce(form, '.o_form_readonly', "form view should be in readonly"); assert.strictEqual(form.$el.text().trim(), 'some foo value', "foo field should have correct value"); @@ -7161,7 +7058,7 @@ QUnit.module('Views', { }, }); - form.$('.o_field_x2many_list_row_add a').click(); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); assert.strictEqual(form.$('.o_field_widget[name=display_name]').val(), '', "display_name should be the empty string by default"); @@ -7170,9 +7067,9 @@ QUnit.module('Views', { onchangeDef = $.Deferred(); // delay the onchange - form.$('.o_field_widget[name=display_name]').val('some value').trigger('input'); + testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'some value'); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.step('resolve'); onchangeDef.resolve(); @@ -7201,13 +7098,13 @@ QUnit.module('Views', { '', }); - form.$('input[name=display_name]').click(); + testUtils.dom.click(form.$('input[name=display_name]')); assert.strictEqual(form.$('input[name="display_name"]')[0], document.activeElement, "display_name should be focused"); form.$('input[name="display_name"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); assert.strictEqual(form.$('input[name="display_name"]')[0], document.activeElement, "display_name should still be focused because it is empty and required"); - assert.strictEqual(form.$('input[name="display_name"]').hasClass("o_field_invalid"), true, + assert.hasClass(form.$('input[name="display_name"]'), 'o_field_invalid', "display_name should have the o_field_invalid class"); form.destroy(); }); @@ -7229,7 +7126,7 @@ QUnit.module('Views', { '', }); - form.$('input[name=date]').click(); + testUtils.dom.click(form.$('input[name=date]')); assert.strictEqual(form.$('input[name="date"]')[0], document.activeElement, "display_name should be focused"); form.$('input[name="date"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); @@ -7255,7 +7152,7 @@ QUnit.module('Views', { }); // in edit - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); form.$('input[name="display_name"]').focus().trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); assert.strictEqual(form.$buttons.find('.btn-primary:visible')[0], document.activeElement, "the first primary button (save) should be focused"); @@ -7401,7 +7298,7 @@ QUnit.module('Views', { }, }); - form.$('div[name="bar"]>input').click(); + testUtils.dom.click(form.$('div[name="bar"]>input')); form.$('input[name="foo"]').focus(); $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB})); diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js index 6dcafc20072..30d295e1f8f 100644 --- a/addons/web/static/tests/views/graph_tests.js +++ b/addons/web/static/tests/views/graph_tests.js @@ -73,7 +73,7 @@ QUnit.module('Views', { var done = assert.async(); return concurrency.delay(0).then(function () { - assert.strictEqual(graph.$('div.o_graph_svg_container svg.nvd3-svg').length, 1, + assert.containsOnce(graph, 'div.o_graph_svg_container svg.nvd3-svg', "should contain a div with a svg element"); assert.strictEqual(graph.renderer.state.mode, "bar", @@ -134,15 +134,15 @@ QUnit.module('Views', { '', }); assert.strictEqual(graph.renderer.state.mode, "line", "should be in line chart mode by default"); - assert.notOk(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + assert.doesNotHaveClass(graph.$buttons.find('button[data-mode="bar"]'), 'active', 'bar type button should not be active'); - assert.ok(graph.$buttons.find('button[data-mode="line"]').hasClass('active'), + assert.hasClass(graph.$buttons.find('button[data-mode="line"]'),'active', 'line type button should be active'); - graph.$buttons.find('button[data-mode="bar"]').click(); + testUtils.dom.click(graph.$buttons.find('button[data-mode="bar"]')); assert.strictEqual(graph.renderer.state.mode, "bar", "should be in bar chart mode by default"); - assert.notOk(graph.$buttons.find('button[data-mode="line"]').hasClass('active'), + assert.doesNotHaveClass(graph.$buttons.find('button[data-mode="line"]'), 'active', 'line type button should not be active'); - assert.ok(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + assert.hasClass(graph.$buttons.find('button[data-mode="bar"]'),'active', 'bar type button should be active'); graph.destroy(); }); @@ -214,7 +214,8 @@ QUnit.module('Views', { "should have used the correct measure"); assert.ok(graph.$buttons.find('.dropdown-item[data-field="foo"]').length, "should have foo in the list of measures"); - graph.$buttons.find('.dropdown-item[data-field="foo"]').click(); + testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)')); + testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="foo"]')); return concurrency.delay(0); }).then(function () { @@ -238,9 +239,9 @@ QUnit.module('Views', { '' + '', }); - assert.strictEqual(graph.$('div.o_graph_svg_container svg.nvd3-svg').length, 0, + assert.containsNone(graph, 'div.o_graph_svg_container svg.nvd3-svg', "should not contain a div with a svg element"); - assert.strictEqual(graph.$('div.o_view_nocontent').length, 1, + assert.containsOnce(graph, 'div.o_view_nocontent', "should display the no content helper"); graph.destroy(); }); @@ -257,9 +258,9 @@ QUnit.module('Views', { '' + '', }); - assert.strictEqual(graph.$('div.o_graph_svg_container svg.nvd3-svg').length, 0, + assert.containsNone(graph, 'div.o_graph_svg_container svg.nvd3-svg', "should not contain a div with a svg element"); - assert.strictEqual(graph.$('div.o_view_nocontent').length, 1, + assert.containsOnce(graph, 'div.o_view_nocontent', "should display the no content helper"); graph.destroy(); }); @@ -286,7 +287,7 @@ QUnit.module('Views', { '', }); - assert.strictEqual(graph.$('div.o_view_nocontent').length, 0, + assert.containsNone(graph, 'div.o_view_nocontent', "should not display the no content helper"); assert.strictEqual($('.o_graph_svg_container svg > text').text(), "No data to displayNo data to display", "should display two empty pie charts instead"); @@ -310,7 +311,7 @@ QUnit.module('Views', { "should contain a div with a svg element"); assert.notOk(graph.$('div.o_view_nocontent').length, "should not display the no content helper"); - graph.update({domain: [['product_id', '=', 4]]}); + testUtils.graph.reload(graph, {domain: [['product_id', '=', 4]]}); assert.notOk(graph.$('div.o_graph_svg_container svg.nvd3-svg').length, "should not contain a div with a svg element"); @@ -339,7 +340,7 @@ QUnit.module('Views', { assert.notOk(graph.$('text:contains(red)').length, "should not contain a text element with color in legend"); - graph.update({groupBy: ['color_id']}); + testUtils.graph.reload(graph, {groupBy: ['color_id']}); return concurrency.delay(0); }).then(function () { @@ -372,7 +373,8 @@ QUnit.module('Views', { graph_intervalMapping: {}, }, "context should be correct"); - graph.$buttons.find('.dropdown-item[data-field="foo"]').click(); // change measure + testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)')); + testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="foo"]')); return concurrency.delay(0); }).then(function () { @@ -383,7 +385,7 @@ QUnit.module('Views', { graph_intervalMapping: {}, }, "context should be correct"); - graph.$buttons.find('button[data-mode="line"]').click(); // change mode + testUtils.dom.click(graph.$buttons.find('button[data-mode="line"]')); return concurrency.delay(0); }).then(function () { @@ -394,7 +396,7 @@ QUnit.module('Views', { graph_intervalMapping: {}, }, "context should be correct"); - graph.update({groupBy: ['product_id', 'color_id']}); // change groupbys + testUtils.graph.reload(graph, {groupBy: ['product_id', 'color_id']}); // change groupbys return concurrency.delay(0); }).then(function () { @@ -413,7 +415,7 @@ QUnit.module('Views', { QUnit.test('correctly uses graph_ keys from the context', function (assert) { var done = assert.async(); assert.expect(6); - + var lastOne = _.last(this.data.foo.records); lastOne.color_id = 14; @@ -437,9 +439,9 @@ QUnit.module('Views', { // check mode assert.strictEqual(graph.renderer.state.mode, "line", "should be in line chart mode"); - assert.notOk(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + assert.doesNotHaveClass(graph.$buttons.find('button[data-mode="bar"]'), 'active', 'bar chart button should not be active'); - assert.ok(graph.$buttons.find('button[data-mode="line"]').hasClass('active'), + assert.hasClass(graph.$buttons.find('button[data-mode="line"]'),'active', 'line chart button should be active'); // check groupbys @@ -498,7 +500,7 @@ QUnit.module('Views', { }); assert.strictEqual(graph.renderer.state.mode, "bar", "should be in bar chart mode"); - assert.ok(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + assert.hasClass(graph.$buttons.find('button[data-mode="bar"]'),'active', 'bar chart button should be active'); var reloadParams = { @@ -508,7 +510,7 @@ QUnit.module('Views', { graph_groupbys: ['color_id'], }, }; - graph.reload(reloadParams); + testUtils.graph.reload(graph, reloadParams); return concurrency.delay(0).then(function () { // check measure assert.strictEqual(graph.$('text.nv-legend-text:contains(Foo)').length, 1, @@ -516,9 +518,9 @@ QUnit.module('Views', { // check mode assert.strictEqual(graph.renderer.state.mode, "line", "should be in line chart mode"); - assert.notOk(graph.$buttons.find('button[data-mode="bar"]').hasClass('active'), + assert.doesNotHaveClass(graph.$buttons.find('button[data-mode="bar"]'), 'active', 'bar chart button should not be active'); - assert.ok(graph.$buttons.find('button[data-mode="line"]').hasClass('active'), + assert.hasClass(graph.$buttons.find('button[data-mode="line"]'),'active', 'line chart button should be active'); // check groupbys @@ -552,7 +554,7 @@ QUnit.module('Views', { }, }); - graph.reload({groupBy: []}); + testUtils.graph.reload(graph, {groupBy: []}); graph.destroy(); }); @@ -580,12 +582,12 @@ QUnit.module('Views', { return concurrency.delay(0).then(function () { - assert.strictEqual(graph.$('.nv-groups rect').length, 2, + assert.containsN(graph, '.nv-groups rect', 2, "should display two groups"); - graph.reload({groupBy: []}); + testUtils.graph.reload(graph, {groupBy: []}); return concurrency.delay(0).then(function () { - assert.strictEqual(graph.$('.nv-groups rect').length, 2, + assert.containsN(graph, '.nv-groups rect', 2, "should still display two groups"); graph.destroy(); @@ -607,7 +609,7 @@ QUnit.module('Views', { }); var done = assert.async(); return concurrency.delay(0).then(function () { - assert.strictEqual(graph.$('div.o_graph_svg_container svg.nvd3-svg').length, 1, + assert.containsOnce(graph, 'div.o_graph_svg_container svg.nvd3-svg', "should contain a div with a svg element"); assert.strictEqual(graph.renderer.state.mode, "bar", @@ -633,7 +635,7 @@ QUnit.module('Views', { }); var done = assert.async(); return concurrency.delay(0).then(function () { - assert.strictEqual(graph.$('div.o_graph_svg_container svg.nvd3-svg').length, 1, + assert.containsOnce(graph, 'div.o_graph_svg_container svg.nvd3-svg', "should contain a div with a svg element"); assert.strictEqual(graph.renderer.state.mode, "bar", @@ -665,7 +667,8 @@ QUnit.module('Views', { return concurrency.delay(0).then(function () { // need to set the measure this way because it cannot be set in the // arch. - graph.$buttons.find('.dropdown-item[data-field="product_id"]').click(); + testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)')); + testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="product_id"]')); assert.strictEqual(graph.model.chart.data[0].value, 1, "should have first datapoint with value 1"); @@ -756,13 +759,13 @@ QUnit.module('Views', { "Bouh should be the first measure"); assert.strictEqual(graph.$buttons.find('.o_graph_measures_list .dropdown-item:last').data('field'), '__count__', "Count should be the last measure"); - + graph.destroy(); }); QUnit.test('Undefined should appear in bar, pie graph but not in line graph', function (assert) { assert.expect(4); - + var graph = createView({ View: GraphView, model: "foo", @@ -776,7 +779,7 @@ QUnit.module('Views', { assert.strictEqual(graph.$("svg.nvd3-svg:contains('Undefined')").length, 0); assert.strictEqual(graph.$("svg.nvd3-svg:contains('March')").length, 1); - graph.$buttons.find('.o_graph_button[data-mode=bar]').click(); + testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=bar]')); assert.strictEqual(graph.$("svg.nvd3-svg:contains('Undefined')").length, 1); assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1); diff --git a/addons/web/static/tests/views/kanban_mobile_tests.js b/addons/web/static/tests/views/kanban_mobile_tests.js index 0ee35c2c9c3..98e65d1ea9c 100644 --- a/addons/web/static/tests/views/kanban_mobile_tests.js +++ b/addons/web/static/tests/views/kanban_mobile_tests.js @@ -72,29 +72,29 @@ QUnit.module('Views', { }); // basic rendering tests - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have 2 columns" ); - assert.ok(kanban.$('.o_kanban_mobile_tab:first').hasClass('o_current'), + assert.containsN(kanban, '.o_kanban_group', 2, "should have 2 columns" ); + assert.hasClass(kanban.$('.o_kanban_mobile_tab:first'),'o_current', "first tab is the active tab with class 'o_current'"); - assert.strictEqual(kanban.$('.o_kanban_group:first > div.o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first > div.o_kanban_record', 2, "there are 2 records in active tab"); assert.strictEqual(kanban.$('.o_kanban_group:nth(1) > div.o_kanban_record').length, 0, "there is no records in next tab. Records will be loaded when it will be opened"); // quick create in first column - kanban.$buttons.find('.o-kanban-button-new').click(); - assert.ok(kanban.$('.o_kanban_group:nth(0) > div:nth(1)').hasClass('o_kanban_quick_create'), + testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new')); + assert.hasClass(kanban.$('.o_kanban_group:nth(0) > div:nth(1)'),'o_kanban_quick_create', "clicking on create should open the quick_create in the first column"); // move to second column kanban.$('.o_kanban_mobile_tab:nth(1)').trigger('click'); - assert.ok(kanban.$('.o_kanban_mobile_tab:nth(1)').hasClass('o_current'), + assert.hasClass(kanban.$('.o_kanban_mobile_tab:nth(1)'),'o_current', "second tab is now active with class 'o_current'"); assert.strictEqual(kanban.$('.o_kanban_group:nth(1) > div.o_kanban_record').length, 2, "the 2 records of the second group have now been loaded"); // quick create in second column - kanban.$buttons.find('.o-kanban-button-new').click(); - assert.ok(kanban.$('.o_kanban_group:nth(1) > div:nth(1)').hasClass('o_kanban_quick_create'), + testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new')); + assert.hasClass(kanban.$('.o_kanban_group:nth(1) > div:nth(1)'),'o_kanban_quick_create', "clicking on create should open the quick_create in the second column"); // kanban column should match kanban mobile tabs @@ -120,8 +120,8 @@ QUnit.module('Views', { }); // first column should be undefined with framework unique identifier - assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have 3 columns" ); - assert.strictEqual(kanban.$('.o_kanban_group:first-child[data-id^="partner_"]').length, 1, + assert.containsN(kanban, '.o_kanban_group', 3, "should have 3 columns" ); + assert.containsOnce(kanban, '.o_kanban_group:first-child[data-id^="partner_"]', "Undefined column should be first and have unique framework identifier as data-id") // kanban column should match kanban mobile tabs @@ -147,8 +147,8 @@ QUnit.module('Views', { }); // basic rendering tests - assert.strictEqual(kanban.$('.o_kanban_group').length, 4, "should have 4 columns" ); - assert.strictEqual(kanban.$('.o_kanban_group[data-id^="partner_"]').length, 4, + assert.containsN(kanban, '.o_kanban_group', 4, "should have 4 columns" ); + assert.containsN(kanban, '.o_kanban_group[data-id^="partner_"]', 4, "all column should have framework unique identifiers"); // kanban column should match kanban mobile tabs diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index 435c13cd3f1..bb66243fed8 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -84,16 +84,11 @@ QUnit.module('Views', { '', }); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_ungrouped'), - "should have classname 'o_kanban_ungrouped'"); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_test'), - "should have classname 'o_kanban_test'"); - - assert.strictEqual(kanban.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4, - "should have 4 records"); - assert.strictEqual(kanban.$('.o_kanban_ghost').length, 6, "should have 6 ghosts"); - assert.strictEqual(kanban.$('.o_kanban_record:contains(gnap)').length, 1, - "should contain gnap"); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_kanban_ungrouped'); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_kanban_test'); + assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4); + assert.containsN(kanban,'.o_kanban_ghost', 6); + assert.containsOnce(kanban, '.o_kanban_record:contains(gnap)'); kanban.destroy(); }); @@ -120,31 +115,25 @@ QUnit.module('Views', { }, }); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), - "should have classname 'o_kanban_grouped'"); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_test'), - "should have classname 'o_kanban_test'"); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should contain " + 1 + " record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 3, - "column should contain " + 3 + " record(s)"); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped'); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_kanban_test'); + assert.containsN(kanban, '.o_kanban_group', 2); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 3); + // check available actions in kanban header's config dropdown - assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_kanban_toggle_fold').length, - "should be able to fold the column"); - assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_edit').length, - "should not be able to edit the column"); - assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_delete').length, - "should not be able to delete the column"); - assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive_records').length, "should not be able to archive all the records"); - assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, "should not be able to restore all the records"); + assert.containsOnce(kanban, '.o_kanban_header:first .o_kanban_config .o_kanban_toggle_fold'); + assert.containsNone(kanban, '.o_kanban_header:first .o_kanban_config .o_column_edit'); + assert.containsNone(kanban, '.o_kanban_header:first .o_kanban_config .o_column_delete'); + assert.containsNone(kanban, '.o_kanban_header:first .o_kanban_config .o_column_archive_records'); + assert.containsNone(kanban, '.o_kanban_header:first .o_kanban_config .o_column_unarchive_records'); // the next line makes sure that reload works properly. It looks useless, // but it actually test that a grouped local record can be reloaded without // changing its result. - kanban.reload(); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 3, - "column should contain " + 3 + " record(s)"); + testUtils.kanban.reload(kanban); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 3); + kanban.destroy(); }); @@ -175,21 +164,23 @@ QUnit.module('Views', { }); // check archive/restore all actions in kanban header's config dropdown - assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive_records').length, "should be able to archive all the records"); - assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, "should be able to restore all the records"); + assert.containsOnce(kanban, '.o_kanban_header:first .o_kanban_config .o_column_archive_records'); + assert.containsOnce(kanban, '.o_kanban_header:first .o_kanban_config .o_column_unarchive_records'); // archive the records of the first column - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, - "last column should contain 3 records"); + assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3); envIDs = [4]; - kanban.$('.o_kanban_group:last .o_column_archive_records').click(); // Click on 'Archive All' + + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records')); + assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed"); + testUtils.modal.clickButton('Cancel'); + assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3, "still last column should contain 3 records"); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records')); assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-secondary').click(); // Click on 'Cancel' - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, "still last column should contain 3 records"); - kanban.$('.o_kanban_group:last .o_column_archive_records').click(); - assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // Click on 'Ok' - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 0, "last column should not contain any records"); + testUtils.modal.clickButton('Ok'); + assert.containsNone(kanban, '.o_kanban_group:last .o_kanban_record', "last column should not contain any records"); kanban.destroy(); }); @@ -218,17 +209,19 @@ QUnit.module('Views', { assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive_records').length, "should be able to restore all the records"); // archive the records of the first column - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, + assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3, "last column should contain 3 records"); envIDs = [4]; - kanban.$('.o_kanban_group:last .o_column_archive_records').click(); // Click on 'Archive All' + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records')); assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-secondary').click(); // Click on 'Cancel' - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3, "still last column should contain 3 records"); - kanban.$('.o_kanban_group:last .o_column_archive_records').click(); + testUtils.modal.clickButton('Cancel'); // Click on 'Cancel' + assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3, "still last column should contain 3 records"); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records')); assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // Click on 'Ok' - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 0, "last column should not contain any records"); + testUtils.modal.clickButton('Ok'); // Click on 'Ok' + assert.containsNone(kanban, '.o_kanban_group:last .o_kanban_record', "last column should not contain any records"); kanban.destroy(); }); @@ -278,7 +271,7 @@ QUnit.module('Views', { }); kanban.renderPager(); - assert.ok(kanban.pager.$el.hasClass('o_hidden'), + assert.isNotVisible(kanban.pager.$el, "pager should be hidden in grouped kanban"); kanban.destroy(); }); @@ -300,7 +293,7 @@ QUnit.module('Views', { }, }); - assert.ok(!kanban.pager.$el.hasClass('o_hidden'), + assert.isVisible(kanban.pager.$el, "pager should be visible in ungrouped kanban"); assert.strictEqual(kanban.pager.state.size, 4, "pager's size should be 4"); kanban.destroy(); @@ -372,17 +365,16 @@ QUnit.module('Views', { '', groupBy: ['product_id'], }); - kanban.renderButtons(); - assert.ok(kanban.$('.o_kanban_view').hasClass('ui-sortable'), + assert.hasClass(kanban.$('.o_kanban_view'),'ui-sortable', "columns are sortable when grouped by a m2o field"); - assert.ok(kanban.$buttons.find('.o-kanban-button-new').hasClass('btn-primary'), + assert.hasClass(kanban.$buttons.find('.o-kanban-button-new'),'btn-primary', "'create' button should be btn-primary for grouped kanban with at least one column"); - assert.ok(kanban.$('.o_kanban_view > div:last').hasClass('o_column_quick_create'), + assert.hasClass(kanban.$('.o_kanban_view > div:last'),'o_column_quick_create', "column quick create should be enabled when grouped by a many2one field)"); - kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create' - assert.ok(kanban.$('.o_kanban_group:first() > div:nth(1)').hasClass('o_kanban_quick_create'), + testUtils.kanban.clickCreate(kanban); // Click on 'Create' + assert.hasClass(kanban.$('.o_kanban_group:first() > div:nth(1)'),'o_kanban_quick_create', "clicking on create should open the quick_create in the first column"); assert.ok(kanban.$('span.o_column_title:contains(hello)').length, @@ -405,12 +397,12 @@ QUnit.module('Views', { groupBy: ['foo'], }); - assert.ok(!kanban.$('.o_kanban_view').hasClass('ui-sortable'), + assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'ui-sortable', "columns aren't sortable when not grouped by a m2o field"); - assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have " + 3 + " columns"); + assert.containsN(kanban, '.o_kanban_group', 3, "should have " + 3 + " columns"); assert.strictEqual(kanban.$('.o_kanban_group:first() .o_column_title').text(), "yop", "'yop' column should be the first column"); - assert.ok(!kanban.$('.o_kanban_view > div:last').hasClass('o_column_quick_create'), + assert.doesNotHaveClass(kanban.$('.o_kanban_view > div:last'), 'o_column_quick_create', "column quick create should be disabled when not grouped by a many2one field)"); kanban.destroy(); }); @@ -438,11 +430,11 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click on 'Create' -> should open the quick create in the first column - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); assert.strictEqual($quickCreate.length, 1, @@ -451,16 +443,16 @@ QUnit.module('Views', { "should have rendered an XXS form view"); assert.strictEqual($quickCreate.find('input').length, 1, "should have only one input"); - assert.ok($quickCreate.find('input').hasClass('o_required_modifier'), + assert.hasClass($quickCreate.find('input'),'o_required_modifier', "the field should be required"); assert.strictEqual($quickCreate.find('input[placeholder=Title]').length, 1, "input placeholder should be 'Title'"); // fill the quick create and validate - $quickCreate.find('input').val('new partner').trigger('input'); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('input'), 'new partner'); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should contain two records"); assert.verifySteps([ @@ -509,11 +501,11 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click on 'Create' -> should open the quick create in the first column - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); assert.strictEqual($quickCreate.length, 1, @@ -526,12 +518,12 @@ QUnit.module('Views', { "should have rendered three widgets"); // fill the quick create and validate - $quickCreate.find('.o_field_widget[name=foo]').val('new partner').trigger('input'); - $quickCreate.find('.o_field_widget[name=int_field]').val('4').trigger('input'); - $quickCreate.find('.o_field_widget[name=state] .o_priority_star:first').click(); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner'); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '4'); + testUtils.dom.click($quickCreate.find('.o_field_widget[name=state] .o_priority_star:first')); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should contain two records"); assert.verifySteps([ @@ -580,16 +572,16 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should contain two records"); // click on 'Create', fill the quick create and validate - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); - $quickCreate.find('input').val('new partner').trigger('input'); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('input'), 'new partner'); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3, "first column should contain three records"); assert.verifySteps([ @@ -645,18 +637,18 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should contain two records"); // click on 'Create', fill the quick create and validate - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); - $quickCreate.find('.o_field_widget[name=foo]').val('new partner').trigger('input'); - $quickCreate.find('.o_field_widget[name=int_field]').val('4').trigger('input'); - $quickCreate.find('.o_field_widget[name=state] .o_priority_star:first').click(); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner'); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '4'); + testUtils.dom.click($quickCreate.find('.o_field_widget[name=state] .o_priority_star:first')); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3, "first column should contain three records"); assert.verifySteps([ @@ -709,7 +701,7 @@ QUnit.module('Views', { }); // click on 'Create' -> should open the quick create in the first column - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); assert.strictEqual($quickCreate.length, 1, @@ -718,7 +710,7 @@ QUnit.module('Views', { "default value should be set"); // fill the 'foo' field -> should trigger the onchange - $quickCreate.find('.o_field_widget[name=foo]').val('new partner').trigger('input'); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner'); assert.strictEqual($quickCreate.find('.o_field_widget[name=int_field]').val(), '8', "onchange should have been triggered"); @@ -758,18 +750,18 @@ QUnit.module('Views', { }); // create a new record - kanban.$('.o_kanban_group:first .o_kanban_quick_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_quick_add')); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); - assert.ok($quickCreate.find('.o_field_widget[name=foo]').hasClass('o_required_modifier'), + assert.hasClass($quickCreate.find('.o_field_widget[name=foo]'),'o_required_modifier', "foo field should be required"); - assert.ok($quickCreate.find('.o_field_widget[name=int_field]').hasClass('o_invisible_modifier'), + assert.hasClass($quickCreate.find('.o_field_widget[name=int_field]'),'o_invisible_modifier', "int_field should be invisible"); // fill 'foo' field - $quickCreate.find('.o_field_widget[name=foo]').val('new partner').trigger('input'); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner'); - assert.notOk($quickCreate.find('.o_field_widget[name=int_field]').hasClass('o_invisible_modifier'), + assert.doesNotHaveClass($quickCreate.find('.o_field_widget[name=int_field]'), 'o_invisible_modifier', "int_field should now be visible"); kanban.destroy(); @@ -800,15 +792,15 @@ QUnit.module('Views', { }); // Quick create kanban record - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); var $quickAdd = kanban.$('.o_kanban_quick_create'); $quickAdd.find('.o_input').val('Test'); - $quickAdd.find('.o_kanban_add').click(); + testUtils.dom.click($quickAdd.find('.o_kanban_add')); // Select state in kanban - kanban.$('.o_status').first().click(); - kanban.$('.o_selection .dropdown-item:first').click(); - assert.ok(kanban.$('.o_status').first().hasClass('o_status_green'), + testUtils.dom.click(kanban.$('.o_status').first()); + testUtils.dom.click(kanban.$('.o_selection .dropdown-item:first')); + assert.hasClass(kanban.$('.o_status').first(),'o_status_green', "Kanban state should be done (Green)"); kanban.destroy(); }); @@ -836,7 +828,7 @@ QUnit.module('Views', { }); // click to add an element and cancel the quick creation by pressing ESC - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); var $quickCreate = kanban.$('.o_kanban_quick_create'); assert.strictEqual($quickCreate.length, 1, "should have a quick create element"); @@ -845,23 +837,23 @@ QUnit.module('Views', { keyCode: $.ui.keyCode.ESCAPE, which: $.ui.keyCode.ESCAPE, })); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + assert.containsNone(kanban, '.o_kanban_quick_create', "should have destroyed the quick create element"); // click to add and element and click outside, should cancel the quick creation - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - kanban.$('.o_kanban_group .o_kanban_record:first').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first')); + assert.containsNone(kanban, '.o_kanban_quick_create', "the quick create should be destroyed when the user clicks outside"); // click to really add an element - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); $quickCreate = kanban.$('.o_kanban_quick_create'); - $quickCreate.find('input').val('new partner').trigger('input'); + testUtils.fields.editInput($quickCreate.find('input'), 'new partner'); // clicking outside should no longer destroy the quick create as it is dirty - kanban.$('.o_kanban_group .o_kanban_record:first').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first')); + assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should not have been destroyed"); // confirm by pressing ENTER @@ -908,20 +900,15 @@ QUnit.module('Views', { fieldDebounce: 5000, }); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should have 4 records at the beginning"); // add an element and confirm by pressing ENTER - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - kanban.$('.o_kanban_quick_create').find('input[name=foo]') - .val('new partner') - .trigger('input') // changes aren't notified here thanks to the fieldDebounce - .trigger($.Event('keydown', { - keyCode: $.ui.keyCode.ENTER, - which: $.ui.keyCode.ENTER, - })); // triggers a navigation event, leading to the 'commitChanges' and record creation + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + testUtils.kanban.quickCreate(kanban, 'new partner', 'foo'); + // triggers a navigation event, leading to the 'commitChanges' and record creation - assert.strictEqual(kanban.$('.o_kanban_record').length, 5, + assert.containsN(kanban, '.o_kanban_record', 5, "should have created a new record"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '', "quick create should now be empty"); @@ -963,36 +950,36 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should have 4 records at the beginning"); // add an element and press ENTER twice def = $.Deferred(); - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); var enterEvent = { keyCode: $.ui.keyCode.ENTER, which: $.ui.keyCode.ENTER, }; - kanban.$('.o_kanban_quick_create').find('input[name=foo]') - .val('new partner') - .trigger('input') - .trigger($.Event('keydown', enterEvent)) - .trigger($.Event('keydown', enterEvent)); + testUtils.fields.editAndTrigger( + kanban.$('.o_kanban_quick_create').find('input[name=foo]'), + 'new partner', + ['input', $.Event('keydown', enterEvent), $.Event('keydown', enterEvent)] + ); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should not have created the record yet"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), 'new partner', "quick create should not be empty yet"); - assert.ok(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled', "quick create should be disabled"); def.resolve(); - assert.strictEqual(kanban.$('.o_kanban_record').length, 5, + assert.containsN(kanban, '.o_kanban_record', 5, "should have created a new record"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '', "quick create should now be empty"); - assert.notOk(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.doesNotHaveClass(kanban.$('.o_kanban_quick_create'), 'o_disabled', "quick create should be enabled"); assert.verifySteps(['create']); @@ -1030,33 +1017,30 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should have 4 records at the beginning"); // add an element and click 'Add' twice def = $.Deferred(); - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - kanban.$('.o_kanban_quick_create').find('input[name=foo]') - .val('new partner') - .trigger('input'); - kanban.$('.o_kanban_quick_create').find('.o_kanban_add') - .click() - .click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create').find('input[name=foo]'), 'new partner'); + testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add')); + testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should not have created the record yet"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), 'new partner', "quick create should not be empty yet"); - assert.ok(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled', "quick create should be disabled"); def.resolve(); - assert.strictEqual(kanban.$('.o_kanban_record').length, 5, + assert.containsN(kanban, '.o_kanban_record', 5, "should have created a new record"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '', "quick create should now be empty"); - assert.notOk(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.doesNotHaveClass(kanban.$('.o_kanban_quick_create'), 'o_disabled', "quick create should be enabled"); assert.verifySteps(['create']); @@ -1110,36 +1094,37 @@ QUnit.module('Views', { fieldDebounce: 5000, }); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should have 4 records at the beginning"); // add an element and press ENTER twice - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); def = $.Deferred(); var enterEvent = { keyCode: $.ui.keyCode.ENTER, which: $.ui.keyCode.ENTER, }; - kanban.$('.o_kanban_quick_create').find('input[name=foo]') - .val('new partner') - .trigger('input') - .trigger($.Event('keydown', enterEvent)) - .trigger($.Event('keydown', enterEvent)); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + testUtils.fields.editAndTrigger( + kanban.$('.o_kanban_quick_create').find('input[name=foo]'), + 'new partner', + ['input', $.Event('keydown', enterEvent), $.Event('keydown', enterEvent)] + ); + + assert.containsN(kanban, '.o_kanban_record', 4, "should not have created the record yet"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), 'new partner', "quick create should not be empty yet"); - assert.ok(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled', "quick create should be disabled"); def.resolve(); - assert.strictEqual(kanban.$('.o_kanban_record').length, 5, + assert.containsN(kanban, '.o_kanban_record', 5, "should have created a new record"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '', "quick create should now be empty"); - assert.notOk(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.doesNotHaveClass(kanban.$('.o_kanban_quick_create'), 'o_disabled', "quick create should be enabled"); assert.verifySteps([ @@ -1194,31 +1179,29 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should have 4 records at the beginning"); // add an element and click 'add' - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); def = $.Deferred(); - kanban.$('.o_kanban_quick_create').find('input[name=foo]') - .val('new partner') - .trigger('input'); - kanban.$('.o_kanban_quick_create').find('.o_kanban_add').click(); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create').find('input[name=foo]'), 'new partner'); + testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_record').length, 4, + assert.containsN(kanban, '.o_kanban_record', 4, "should not have created the record yet"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), 'new partner', "quick create should not be empty yet"); - assert.ok(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled', "quick create should be disabled"); def.resolve(); // the onchange returns - assert.strictEqual(kanban.$('.o_kanban_record').length, 5, + assert.containsN(kanban, '.o_kanban_record', 5, "should have created a new record"); assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '', "quick create should now be empty"); - assert.notOk(kanban.$('.o_kanban_quick_create').hasClass('o_disabled'), + assert.doesNotHaveClass(kanban.$('.o_kanban_quick_create'), 'o_disabled', "quick create should be enabled"); assert.verifySteps([ @@ -1246,30 +1229,32 @@ QUnit.module('Views', { groupBy: ['bar'], }); - assert.notOk(kanban.$('.o_kanban_group:first').hasClass('o_column_folded'), + assert.doesNotHaveClass(kanban.$('.o_kanban_group:first'), 'o_column_folded', "first column should not be folded"); // fold the first column - kanban.$('.o_kanban_group:first .o_kanban_toggle_fold').click(); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:first')); + testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold')); - assert.ok(kanban.$('.o_kanban_group:first').hasClass('o_column_folded'), + assert.hasClass(kanban.$('.o_kanban_group:first'),'o_column_folded', "first column should be folded"); // click on 'Create' to open the quick create in the first column - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); - assert.notOk(kanban.$('.o_kanban_group:first').hasClass('o_column_folded'), + assert.doesNotHaveClass(kanban.$('.o_kanban_group:first'), 'o_column_folded', "first column should no longer be folded"); var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); assert.strictEqual($quickCreate.length, 1, "should have added a quick create element in first column"); // fold again the first column - kanban.$('.o_kanban_group:first .o_kanban_toggle_fold').click(); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:first')); + testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold')); - assert.ok(kanban.$('.o_kanban_group:first').hasClass('o_column_folded'), + assert.hasClass(kanban.$('.o_kanban_group:first'),'o_column_folded', "first column should be folded"); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + assert.containsNone(kanban, '.o_kanban_quick_create', "there should be no more quick create"); kanban.destroy(); @@ -1290,27 +1275,27 @@ QUnit.module('Views', { groupBy: ['bar'], }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click to add an element - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have open the quick create widget"); // click again to add an element -> should have kept the quick create open - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have kept the quick create open"); // click outside: should remove the quick create - kanban.$('.o_kanban_group .o_kanban_record:first').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first')); + assert.containsNone(kanban, '.o_kanban_quick_create', "the quick create should not have been destroyed"); // click to reopen the quick create - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have open the quick create widget"); // press ESC: should remove the quick create @@ -1318,21 +1303,21 @@ QUnit.module('Views', { keyCode: $.ui.keyCode.ESCAPE, which: $.ui.keyCode.ESCAPE, })); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + assert.containsNone(kanban, '.o_kanban_quick_create', "quick create widget should have been removed"); // click to reopen the quick create - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have open the quick create widget"); // click on 'Discard': should remove the quick create - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - kanban.$('.o_kanban_group .o_kanban_record:first').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first')); + assert.containsNone(kanban, '.o_kanban_quick_create', "the quick create should be destroyed when the user clicks outside"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should still contain one record"); kanban.destroy(); @@ -1353,20 +1338,20 @@ QUnit.module('Views', { groupBy: ['bar'], }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click to add an element and edit it - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have open the quick create widget"); var $quickCreate = kanban.$('.o_kanban_quick_create'); - $quickCreate.find('input').val('some value').trigger('input'); + testUtils.fields.editInput($quickCreate.find('input'), 'some value'); // click outside: should not remove the quick create - kanban.$('.o_kanban_group .o_kanban_record:first').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first')); + assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should not have been destroyed"); // press ESC: should remove the quick create @@ -1374,23 +1359,23 @@ QUnit.module('Views', { keyCode: $.ui.keyCode.ESCAPE, which: $.ui.keyCode.ESCAPE, })); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + assert.containsNone(kanban, '.o_kanban_quick_create', "quick create widget should have been removed"); // click to reopen quick create and edit it - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have open the quick create widget"); $quickCreate = kanban.$('.o_kanban_quick_create'); - $quickCreate.find('input').val('some value').trigger('input'); + testUtils.fields.editInput($quickCreate.find('input'), 'some value'); // click on 'Discard': should remove the quick create - kanban.$('.o_kanban_quick_create .o_kanban_cancel').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + testUtils.dom.click(kanban.$('.o_kanban_quick_create .o_kanban_cancel')); + assert.containsNone(kanban, '.o_kanban_quick_create', "the quick create should be destroyed when the user clicks outside"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should still contain one record"); kanban.destroy(); @@ -1429,21 +1414,21 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click to add and edit an element var $quickCreate = kanban.$('.o_kanban_quick_create'); - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); $quickCreate = kanban.$('.o_kanban_quick_create'); - $quickCreate.find('input').val('new partner').trigger('input'); - $quickCreate.find('button.o_kanban_edit').click(); + testUtils.fields.editInput($quickCreate.find('input'), 'new partner'); + testUtils.dom.click($quickCreate.find('button.o_kanban_edit')); assert.strictEqual(this.data.partner.records.length, 5, "should have created a partner"); assert.strictEqual(_.last(this.data.partner.records).name, "new partner", "should have correct name"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should now contain two records"); kanban.destroy(); @@ -1464,40 +1449,28 @@ QUnit.module('Views', { groupBy: ['bar'], }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click to add an element, fill the input and press ENTER - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should be open"); - kanban.$('.o_kanban_quick_create input') - .val('new partner 1') - .trigger('input') - .trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); + testUtils.kanban.quickCreate(kanban, 'new partner 1'); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should now contain two records"); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should still be open"); // create a second element in a row - kanban.$('.o_kanban_quick_create input') - .val('new partner 2') - .trigger('input') - .trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); + testUtils.kanban.quickCreate(kanban, 'new partner 2'); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3, "first column should now contain three records"); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should still be open"); kanban.destroy(); @@ -1526,32 +1499,27 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); // click to add a record, and add two in a row (first one will be delayed) - kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click(); + testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first()); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + assert.containsOnce(kanban, '.o_kanban_quick_create', "the quick create should be open"); def = $.Deferred(); - kanban.$('.o_kanban_quick_create input') - .val('new partner 1') - .trigger('input') - .trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + testUtils.kanban.quickCreate(kanban, 'new partner 1'); + + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should still contain one record"); - assert.strictEqual(kanban.$('.o_kanban_quick_create.o_disabled').length, 1, + assert.containsOnce(kanban, '.o_kanban_quick_create.o_disabled', "quick create should be disabled"); def.resolve(); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should now contain two records"); assert.strictEqual(kanban.$('.o_kanban_quick_create:not(.o_disabled)').length, 1, "quick create should be enabled"); @@ -1591,20 +1559,14 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "there should be 2 records in first column"); - kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create' - assert.ok(kanban.$('.o_kanban_group:first() > div:nth(1)').hasClass('o_kanban_quick_create'), + testUtils.kanban.clickCreate(kanban); // Click on 'Create' + assert.hasClass(kanban.$('.o_kanban_group:first() > div:nth(1)'),'o_kanban_quick_create', "clicking on create should open the quick_create in the first column"); - kanban.$('.o_kanban_quick_create input') - .val('test') - .trigger('input') - .trigger($.Event('keydown', { - keyCode: $.ui.keyCode.ENTER, - which: $.ui.keyCode.ENTER, - })); + testUtils.kanban.quickCreate(kanban, 'test'); assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1, "a form view dialog should have been opened (in edit)"); @@ -1612,11 +1574,11 @@ QUnit.module('Views', { "the correct product_id should already be set"); // specify a name and save - $('.modal input[name=foo]').val('test').trigger('input'); - $('.modal-footer .btn-primary').click(); + testUtils.fields.editInput($('.modal input[name=foo]'), 'test'); + testUtils.modal.clickButton('Save'); assert.strictEqual($('.modal').length, 0, "the modal should be closed"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3, "there should be 3 records in first column"); var $firstRecord = kanban.$('.o_kanban_group:first .o_kanban_record:first'); assert.strictEqual($firstRecord.text(), 'test', @@ -1656,26 +1618,19 @@ QUnit.module('Views', { }, $.Event()); } return this._super.apply(this, arguments); - }, + } }); - kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create' - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1, + testUtils.kanban.clickCreate(kanban); + assert.containsOnce(kanban, '.o_kanban_quick_create', "should have a quick create widget"); - kanban.$('.o_kanban_quick_create input') - .val('test') - .trigger('input') - .trigger($.Event('keydown', { - keyCode: $.ui.keyCode.ENTER, - which: $.ui.keyCode.ENTER, - })); + testUtils.kanban.quickCreate(kanban, 'test'); assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1, "a form view dialog should have been opened (in edit)"); - // discard - $('.modal-footer .btn-secondary').click(); + testUtils.modal.clickButton('Discard'); assert.strictEqual($('.modal').length, 0, "the modal should be closed"); assert.strictEqual(kanban.$('.o_kanban_quick_create:not(.o_disabled)').length, 1, @@ -1720,22 +1675,21 @@ QUnit.module('Views', { groupBy: ['foo'], }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "there should be 1 record in first column"); - kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click(); - kanban.$('.o_kanban_quick_create input').val('test').trigger('input'); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'test'); + testUtils.dom.click(kanban.$('.o_kanban_add')); assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1, "a form view dialog should have been opened (in edit)"); assert.strictEqual($('.modal .o_field_widget[name=foo]').val(), 'yop', "the correct default value for foo should already be set"); - - $('.modal-footer .btn-primary').click(); + testUtils.modal.clickButton('Save'); assert.strictEqual($('.modal').length, 0, "the modal should be closed"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "there should be 2 records in first column"); kanban.destroy(); @@ -1777,22 +1731,22 @@ QUnit.module('Views', { groupBy: ['state'], }); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "there should be 1 record in first column"); - kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click(); - kanban.$('.o_kanban_quick_create input').val('test').trigger('input'); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'test'); + testUtils.dom.click(kanban.$('.o_kanban_add')); assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1, "a form view dialog should have been opened (in edit)"); assert.strictEqual($('.modal .o_field_widget[name=state]').val(), '"abc"', "the correct default value for state should already be set"); - $('.modal-footer .btn-primary').click(); + testUtils.modal.clickButton('Save'); assert.strictEqual($('.modal').length, 0, "the modal should be closed"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "there should be 2 records in first column"); kanban.destroy(); @@ -1827,14 +1781,14 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, + assert.containsN(kanban, '.o_kanban_group', 2, "there should be 2 columns"); - assert.strictEqual(kanban.$('.o_kanban_record').length, 0, + assert.containsNone(kanban, '.o_kanban_record', "both columns should be empty"); - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_quick_create').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_quick_create', "should have opened the quick create in the first column"); kanban.destroy(); @@ -1863,22 +1817,22 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0, + assert.containsNone(kanban, '.o_kanban_header .o_kanban_quick_add i', "quick create should be disabled when grouped on a date field"); // clicking on CREATE in control panel should not open a quick create - kanban.$buttons.find('.o-kanban-button-new').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + testUtils.kanban.clickCreate(kanban); + assert.containsNone(kanban, '.o_kanban_quick_create', "should not have opened the quick create widget"); kanban.reload({groupBy: ['datetime']}); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0, + assert.containsNone(kanban, '.o_kanban_header .o_kanban_quick_add i', "quick create should be disabled when grouped on a datetime field"); // clicking on CREATE in control panel should not open a quick create - kanban.$buttons.find('.o-kanban-button-new').click(); - assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0, + testUtils.kanban.clickCreate(kanban); + assert.containsNone(kanban, '.o_kanban_quick_create', "should not have opened the quick create widget"); kanban.destroy(); @@ -1899,17 +1853,17 @@ QUnit.module('Views', { groupBy: ['foo'], }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 3, "quick create should be enabled when grouped on a char field"); kanban.reload({groupBy: ['date']}); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0, + assert.containsNone(kanban, '.o_kanban_header .o_kanban_quick_add i', "quick create should now be disabled (grouped on date field)"); kanban.reload({groupBy: ['bar']}); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 2, "quick create should be enabled again (grouped on boolean field)"); kanban.destroy(); @@ -1937,16 +1891,16 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 3, "quick create should be enabled when grouped on a char field"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain 1 record"); - kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click(); - kanban.$('.o_kanban_quick_create input').val('new record').trigger('input'); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record'); + testUtils.dom.click(kanban.$('.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should now contain 2 records"); kanban.destroy(); @@ -1974,14 +1928,14 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 2, "quick create should be enabled when grouped on a boolean field"); assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 3, "second column (true) should contain 3 records"); - kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i').click(); - kanban.$('.o_kanban_quick_create input').val('new record').trigger('input'); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record'); + testUtils.dom.click(kanban.$('.o_kanban_add')); assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 4, "second column (true) should now contain 4 records"); @@ -2011,16 +1965,16 @@ QUnit.module('Views', { groupBy: ['state'], }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 3, "quick create should be enabled when grouped on a selection field"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column (abc) should contain 1 record"); - kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click(); - kanban.$('.o_kanban_quick_create input').val('new record').trigger('input'); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record'); + testUtils.dom.click(kanban.$('.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column (abc) should contain 2 records"); kanban.destroy(); @@ -2055,17 +2009,17 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 3, "quick create should be enabled when grouped on a char field"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain 1 record"); - kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i')); assert.strictEqual(kanban.$('.o_kanban_quick_create input').val(), 'yop', "should have set the correct foo value by default"); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column should now contain 2 records"); kanban.destroy(); @@ -2100,15 +2054,15 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 2, "quick create should be enabled when grouped on a boolean field"); assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 3, "second column (true) should contain 3 records"); - kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i')); assert.ok(kanban.$('.o_kanban_quick_create .o_field_boolean input').is(':checked'), "should have set the correct bar value by default"); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_add')); assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 4, "second column (true) should now contain 4 records"); @@ -2145,17 +2099,17 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3, + assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 3, "quick create should be enabled when grouped on a selection field"); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1, + assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column (abc) should contain 1 record"); - kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click(); + testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i')); assert.strictEqual(kanban.$('.o_kanban_quick_create select').val(), '"abc"', "should have set the correct state value by default"); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2, "first column (abc) should now contain 2 records"); kanban.destroy(); @@ -2204,7 +2158,7 @@ QUnit.module('Views', { var $first_record = kanban.$('.o_kanban_record:first()'); assert.strictEqual($first_record.find('.o_field_many2manytags .o_tag').length, 2, 'first record should contain 2 tags'); - assert.ok($first_record.find('.o_tag:first()').hasClass('o_tag_color_2'), + assert.hasClass($first_record.find('.o_tag:first()'),'o_tag_color_2', 'first tag should have color 2'); assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/category/read'], 'two RPC should have been done (one search read and one read for the m2m)'); @@ -2214,7 +2168,7 @@ QUnit.module('Views', { 'there should be only one tag in second record'); // Write on the record using the priority widget to trigger a re-render in readonly - kanban.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').first().click(); + testUtils.dom.click(kanban.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').first()); assert.verifySteps([ '/web/dataset/search_read', '/web/dataset/call_kw/category/read', @@ -2226,7 +2180,7 @@ QUnit.module('Views', { 'first record should still contain only 2 tags'); // click on a tag (should trigger switch_view) - kanban.$('.o_tag:contains(gold):first').click(); + testUtils.dom.click(kanban.$('.o_tag:contains(gold):first')); kanban.destroy(); }); @@ -2291,7 +2245,7 @@ QUnit.module('Views', { ev.preventDefault(); }); - $testLink.click(); + testUtils.dom.click($testLink); $(document.body).off('click.o_test'); kanban.destroy(); @@ -2372,7 +2326,7 @@ QUnit.module('Views', { }, }); - kanban.reload(); + testUtils.kanban.reload(kanban); assert.verifySteps([ 'read_group', '/web/dataset/search_read', @@ -2461,22 +2415,18 @@ QUnit.module('Views', { }, }, }); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 2, - "column should contain 2 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2, - "column should contain 2 record(s)"); + assert.containsN(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record', 2); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2); + assert.containsN(kanban, '.thisiseditable', 4); - assert.strictEqual(kanban.$('.thisiseditable').length, 4, "all records should be editable"); var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first'); var $group = kanban.$('.o_kanban_group:nth-child(2)'); envIDs = [3, 2, 4, 1]; // first record of first column moved to the bottom of second column - testUtils.dragAndDrop($record, $group); + testUtils.dom.dragAndDrop($record, $group); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should now contain 1 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 3, - "column should contain 3 record(s)"); - assert.strictEqual(kanban.$('.thisiseditable').length, 4, "all records should be editable"); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 3); + assert.containsN(kanban, '.thisiseditable', 4); kanban.destroy(); }); @@ -2506,19 +2456,15 @@ QUnit.module('Views', { return this._super(route, args); }, }); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should contain 1 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 1, - "column should contain 1 record(s)"); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record'); var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first'); var $group = kanban.$('.o_kanban_group:nth-child(2)'); - testUtils.dragAndDrop($record, $group); + testUtils.dom.dragAndDrop($record, $group); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 0, - "column should now contain 0 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2, - "column should contain 2 record(s)"); + assert.containsNone(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2); kanban.destroy(); }); @@ -2550,42 +2496,36 @@ QUnit.module('Views', { }); // simulate an update coming from the searchview, with another groupby given kanban.update({groupBy: ['state']}); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should contain 1 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 1, - "column should contain 1 record(s)"); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record'); + // drag&drop a record in another column var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first'); var $group = kanban.$('.o_kanban_group:nth-child(2)'); - testUtils.dragAndDrop($record, $group); + testUtils.dom.dragAndDrop($record, $group); // should not be draggable - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should now contain 1 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 1, - "column should contain 1 record(s)"); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record'); // simulate an update coming from the searchview, with another groupby given kanban.update({groupBy: ['foo']}); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should contain 1 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2, - "column should contain 2 record(s)"); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2); + // drag&drop a record in another column $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first'); $group = kanban.$('.o_kanban_group:nth-child(2)'); - testUtils.dragAndDrop($record, $group); + testUtils.dom.dragAndDrop($record, $group); // should not be draggable - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, - "column should now contain 1 record(s)"); - assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2, - "column should contain 2 record(s)"); + assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record'); + assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2); // drag&drop a record in the same column var $record1 = kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(0)'); var $record2 = kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(1)'); assert.strictEqual($record1.text(), "blipDEF", "first record should be DEF"); assert.strictEqual($record2.text(), "blipGHI", "second record should be GHI"); - testUtils.dragAndDrop($record2, $record1, {position: 'top'}); + testUtils.dom.dragAndDrop($record2, $record1, {position: 'top'}); // should still be able to resequence assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(0)').text(), "blipGHI", "records should have been resequenced"); @@ -2627,17 +2567,16 @@ QUnit.module('Views', { }, }); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), - "should have classname 'o_kanban_grouped'"); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns"); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped'); + assert.containsN(kanban, '.o_kanban_group', 2, "should have " + 2 + " columns"); // simulate an update coming from the searchview, with another groupby given kanban.update({groupBy: ['product_id']}); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should now have " + 3 + " columns"); + assert.containsN(kanban, '.o_kanban_group', 2, "should now have " + 3 + " columns"); // simulate an update coming from the searchview, removing the previously set groupby kanban.update({groupBy: []}); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns again"); + assert.containsN(kanban, '.o_kanban_group', 2, "should have " + 2 + " columns again"); kanban.destroy(); }); @@ -2671,7 +2610,7 @@ QUnit.module('Views', { '', }); - testUtils.intercept(kanban, 'switch_view', function (event) { + testUtils.mock.intercept(kanban, 'switch_view', function (event) { assert.deepEqual(event.data, { view_type: 'form', res_id: 1, @@ -2679,7 +2618,7 @@ QUnit.module('Views', { model: 'partner', }); }); - kanban.$('a').first().click(); + testUtils.dom.click(kanban.$('a').first()); kanban.destroy(); }); @@ -2709,12 +2648,13 @@ QUnit.module('Views', { // fold the second group and check that the res_ids it contains are no // longer in the environment envIDs = [1, 3]; - kanban.$('.o_kanban_group:last .o_kanban_toggle_fold').click(); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_kanban_toggle_fold')); // re-open the second group and check that the res_ids it contains are // back in the environment envIDs = [1, 3, 2, 4]; - kanban.$('.o_kanban_group:last .o_kanban_toggle_fold').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:last')); kanban.destroy(); }); @@ -2747,11 +2687,11 @@ QUnit.module('Views', { return this._super(route, args); }, }); - assert.strictEqual(kanban.$('.o_column_quick_create').length, 1, "should have a quick create column"); + assert.containsOnce(kanban, '.o_column_quick_create', "should have a quick create column"); assert.notOk(kanban.$('.o_column_quick_create input').is(':visible'), "the input should not be visible"); - kanban.$('.o_quick_create_folded').click(); + testUtils.dom.click(kanban.$('.o_quick_create_folded')); assert.ok(kanban.$('.o_column_quick_create input').is(':visible'), "the input should be visible"); @@ -2764,39 +2704,39 @@ QUnit.module('Views', { assert.notOk(kanban.$('.o_column_quick_create input').is(':visible'), "the input should not be visible after discard"); - kanban.$('.o_quick_create_folded').click(); + testUtils.dom.click(kanban.$('.o_quick_create_folded')); assert.ok(kanban.$('.o_column_quick_create input').is(':visible'), "the input should be visible"); kanban.$('.o_column_quick_create input').val('new value'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new value)').length, 1, "the last column should be the newly created one"); assert.ok(_.isNumber(kanban.$('.o_kanban_group:last').data('id')), 'the created column should have the correct id'); - assert.ok(!kanban.$('.o_kanban_group:last').hasClass('o_column_folded'), + assert.doesNotHaveClass(kanban.$('.o_kanban_group:last'), 'o_column_folded', 'the created column should not be folded'); // fold and unfold the created column, and check that no RPC is done (as there is no record) nbRPCs = 0; - kanban.$('.o_kanban_group:last .o_kanban_toggle_fold').click(); // fold the group - assert.ok(kanban.$('.o_kanban_group:last').hasClass('o_column_folded'), + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_kanban_toggle_fold')); + assert.hasClass(kanban.$('.o_kanban_group:last'),'o_column_folded', 'the created column should now be folded'); - kanban.$('.o_kanban_group:last').click(); - assert.ok(!kanban.$('.o_kanban_group:last').hasClass('o_column_folded'), - 'the created column should not be folded'); + testUtils.dom.click(kanban.$('.o_kanban_group:last')); + assert.doesNotHaveClass(kanban.$('.o_kanban_group:last'), 'o_column_folded'); assert.strictEqual(nbRPCs, 0, 'no rpc should have been done when folding/unfolding'); // quick create a record - kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create' - assert.ok(kanban.$('.o_kanban_group:first() > div:nth(1)').hasClass('o_kanban_quick_create'), + testUtils.kanban.clickCreate(kanban); + assert.hasClass(kanban.$('.o_kanban_group:first() > div:nth(1)'),'o_kanban_quick_create', "clicking on create should open the quick_create in the first column"); kanban.destroy(); }); QUnit.test('auto fold group when reach the limit', function (assert) { - assert.expect(7); + assert.expect(9); var data = this.data; for (var i = 0; i < 12; i++) { @@ -2835,28 +2775,19 @@ QUnit.module('Views', { }); // we look if column are fold/unfold according what is expected - assert.notOk(kanban.$('.o_kanban_group:nth-child(2)').hasClass('o_column_folded'), - 'second column must be unfolded by default'); - assert.notOk(kanban.$('.o_kanban_group:nth-child(4)').hasClass('o_column_folded'), - 'fourth column must be unfolded by default'); - assert.notOk(kanban.$('.o_kanban_group:nth-child(10)').hasClass('o_column_folded'), - 'tenth column must be unfolded by default'); - assert.ok( - kanban.$('.o_kanban_group:nth-child(3)').hasClass('o_column_folded') - && kanban.$('.o_kanban_group:nth-child(9)').hasClass('o_column_folded'), - 'third and ninth columns must be folded by default'); + assert.doesNotHaveClass(kanban.$('.o_kanban_group:nth-child(2)'), 'o_column_folded'); + assert.doesNotHaveClass(kanban.$('.o_kanban_group:nth-child(4)'), 'o_column_folded'); + assert.doesNotHaveClass(kanban.$('.o_kanban_group:nth-child(10)'), 'o_column_folded'); + assert.hasClass(kanban.$('.o_kanban_group:nth-child(3)'), 'o_column_folded'); + assert.hasClass(kanban.$('.o_kanban_group:nth-child(9)'), 'o_column_folded'); + // we look if columns are actually fold after we reached the limit - assert.ok( - kanban.$('.o_kanban_group:nth-child(13)').hasClass('o_column_folded') - && kanban.$('.o_kanban_group:nth-child(14)').hasClass('o_column_folded'), - 'thirteenth and fourtheenth columns must be folded because we reached the limit'); + assert.hasClass(kanban.$('.o_kanban_group:nth-child(13)'), 'o_column_folded'); + assert.hasClass(kanban.$('.o_kanban_group:nth-child(14)'), 'o_column_folded'); + // we look if we have the right count of folded/unfolded column - assert.strictEqual( - kanban.$('.o_kanban_group:not(.o_column_folded)').length, - 10, 'must have ten opened columns'); - assert.strictEqual( - kanban.$('.o_kanban_group.o_column_folded').length, - 4, 'must have four folded columns'); + assert.containsN(kanban, '.o_kanban_group:not(.o_column_folded)', 10); + assert.containsN(kanban, '.o_kanban_group.o_column_folded', 4); kanban.destroy(); }); @@ -2877,13 +2808,12 @@ QUnit.module('Views', { groupBy: ['product_id'], }); - kanban.$('.o_quick_create_folded').click(); - + testUtils.dom.click(kanban.$('.o_quick_create_folded')); assert.ok(kanban.$('.o_discard_msg').is(':visible'), 'the ESC to discard message is visible'); - // click in the column, but outside the input (to lose focus) - kanban.$('.o_kanban_header').click(); + // click outside the column (to lose focus) + testUtils.dom.clickFirst(kanban.$('.o_kanban_header')); assert.notOk(kanban.$('.o_discard_msg').is(':visible'), 'the ESC to discard message is no longer visible'); @@ -2893,7 +2823,7 @@ QUnit.module('Views', { QUnit.test('delete a column in grouped on m2o', function (assert) { assert.expect(36); - testUtils.patch(KanbanRenderer, { + testUtils.mock.patch(KanbanRenderer, { _renderGrouped: function () { this._super.apply(this, arguments); // set delay and revert animation time to 0 so dummy drag and drop works @@ -2931,14 +2861,14 @@ QUnit.module('Views', { }); // check the initial rendering - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have two columns"); + assert.containsN(kanban, '.o_kanban_group', 2, "should have two columns"); assert.strictEqual(kanban.$('.o_kanban_group:first').data('id'), 3, 'first column should be [3, "hello"]'); assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 5, 'second column should be [5, "xmo"]'); assert.strictEqual(kanban.$('.o_kanban_group:last .o_column_title').text(), 'xmo', 'second column should have correct title'); - assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 2, + assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 2, "second column should have two records"); // check available actions in kanban header's config dropdown @@ -2952,17 +2882,19 @@ QUnit.module('Views', { assert.ok(!kanban.$('.o_kanban_group:first .o_column_unarchive_records').length, "should not be able to restore all the records"); // delete second column (first cancel the confirm request, then confirm) - kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete')); assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-secondary').click(); // click on cancel + testUtils.modal.clickButton('Cancel'); // click on cancel assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 5, 'column [5, "xmo"] should still be there'); - kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete')); assert.ok($('.modal').length, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // click on confirm + testUtils.modal.clickButton('Ok'); // click on confirm assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 3, 'last column should now be [3, "hello"]'); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should still have two columns"); + assert.containsN(kanban, '.o_kanban_group', 2, "should still have two columns"); assert.ok(!_.isNumber(kanban.$('.o_kanban_group:first').data('id')), 'first column should have no id (Undefined column)'); // check available actions on 'Undefined' column @@ -2979,22 +2911,23 @@ QUnit.module('Views', { "the old widgets should have been correctly deleted"); // test column drag and drop having an 'Undefined' column - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( kanban.$('.o_kanban_header_title:first'), kanban.$('.o_kanban_header_title:last'), {position: 'right'} ); assert.strictEqual(resequencedIDs, undefined, "resequencing require at least 2 not Undefined columns"); + testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded')); kanban.$('.o_column_quick_create input').val('once third column'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); var newColumnID = kanban.$('.o_kanban_group:last').data('id'); - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( kanban.$('.o_kanban_header_title:first'), kanban.$('.o_kanban_header_title:last'), {position: 'right'} ); assert.deepEqual([3, newColumnID], resequencedIDs, "moving the Undefined column should not affect order of other columns") - testUtils.dragAndDrop( + testUtils.dom.dragAndDrop( kanban.$('.o_kanban_header_title:first'), kanban.$('.o_kanban_header_title:nth(1)'), {position: 'right'} ); @@ -3002,7 +2935,7 @@ QUnit.module('Views', { "moved column should be resequenced accordingly") kanban.destroy(); - testUtils.unpatch(KanbanRenderer); + testUtils.mock.unpatch(KanbanRenderer); }); QUnit.test('create a column, delete it and create another one', function (assert) { @@ -3021,24 +2954,25 @@ QUnit.module('Views', { groupBy: ['product_id'], }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have two columns"); + assert.containsN(kanban, '.o_kanban_group', 2, "should have two columns"); - kanban.$('.o_column_quick_create').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded')); kanban.$('.o_column_quick_create input').val('new column 1'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have two columns"); + assert.containsN(kanban, '.o_kanban_group', 3, "should have two columns"); - kanban.$('.o_kanban_group:last .o_column_delete').click(); - $('.modal-footer .btn-primary').click(); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last')); + testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete')); + testUtils.modal.clickButton('Ok'); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have twos columns"); + assert.containsN(kanban, '.o_kanban_group', 2, "should have twos columns"); - kanban.$('.o_column_quick_create').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded')); kanban.$('.o_column_quick_create input').val('new column 2'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have three columns"); + assert.containsN(kanban, '.o_kanban_group', 3, "should have three columns"); assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new column 2)').length, 1, "the last column should be the newly created one"); kanban.destroy(); @@ -3071,33 +3005,37 @@ QUnit.module('Views', { 'title of the column should be "xmo"'); // edit the title of column [5, 'xmo'] and close without saving - kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit' - assert.ok($('.modal .o_form_editable').length, 'a form view should be open in a modal'); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group[data-id=5]')); + testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit')); + assert.containsOnce(document.body, '.modal .o_form_editable', + "a form view should be open in a modal"); assert.strictEqual($('.modal .o_form_editable input').val(), 'xmo', 'the name should be "xmo"'); - $('.modal .o_form_editable input').val('ged').trigger('input'); // change the value + testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value nbRPCs = 0; - $('.modal-header .close').click(); // click on the cross to close the modal - assert.ok(!$('.modal').length, 'the modal should be closed'); + testUtils.dom.click($('.modal-header .close')); + assert.containsNone(document.body, '.modal'); assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo', 'title of the column should still be "xmo"'); assert.strictEqual(nbRPCs, 0, 'no RPC should have been done'); // edit the title of column [5, 'xmo'] and discard - kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit' - $('.modal .o_form_editable input').val('ged').trigger('input'); // change the value + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group[data-id=5]')); + testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit')); + testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value nbRPCs = 0; - $('.modal-footer .btn-secondary').click(); // click on discard - assert.ok(!$('.modal').length, 'the modal should be closed'); + testUtils.modal.clickButton('Discard'); + assert.containsNone(document.body, '.modal'); assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo', 'title of the column should still be "xmo"'); assert.strictEqual(nbRPCs, 0, 'no RPC should have been done'); // edit the title of column [5, 'xmo'] and save - kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit' - $('.modal .o_form_editable input').val('ged').trigger('input'); // change the value + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group[data-id=5]')); + testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit')); + testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value nbRPCs = 0; - $('.modal-footer .btn-primary').click(); // click on save + testUtils.modal.clickButton('Save'); // click on save assert.ok(!$('.modal').length, 'the modal should be closed'); assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'ged', 'title of the column should be "ged"'); @@ -3122,10 +3060,8 @@ QUnit.module('Views', { domain: [['foo', '=', 'norecord']], }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 0, - "there should be no column"); - assert.strictEqual(kanban.$('.o_column_quick_create').length, 1, - "should have a quick create column"); + assert.containsNone(kanban, '.o_kanban_group'); + assert.containsOnce(kanban, '.o_column_quick_create'); assert.ok(kanban.$('.o_column_quick_create input').is(':visible'), "the quick create should be opened"); @@ -3148,34 +3084,34 @@ QUnit.module('Views', { groupBy: ['product_id'], }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, + assert.containsN(kanban, '.o_kanban_group', 2, "should have two columns"); - assert.strictEqual(kanban.$('.o_column_quick_create').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create', "should have a ColumnQuickCreate widget"); - assert.strictEqual(kanban.$('.o_column_quick_create .o_quick_create_folded:visible').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create .o_quick_create_folded:visible', "the ColumnQuickCreate should be folded"); - assert.strictEqual(kanban.$('.o_column_quick_create .o_quick_create_unfolded:visible').length, 0, + assert.containsNone(kanban, '.o_column_quick_create .o_quick_create_unfolded:visible', "the ColumnQuickCreate should be folded"); // add a new column - kanban.$('.o_column_quick_create .o_quick_create_folded').click(); - assert.strictEqual(kanban.$('.o_column_quick_create .o_quick_create_folded:visible').length, 0, + testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded')); + assert.containsNone(kanban, '.o_column_quick_create .o_quick_create_folded:visible', "the ColumnQuickCreate should be unfolded"); - assert.strictEqual(kanban.$('.o_column_quick_create .o_quick_create_unfolded:visible').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create .o_quick_create_unfolded:visible', "the ColumnQuickCreate should be unfolded"); kanban.$('.o_column_quick_create input').val('New Column 1'); - kanban.$('.o_column_quick_create .btn-primary').click(); - assert.strictEqual(kanban.$('.o_kanban_group').length, 3, + testUtils.dom.click(kanban.$('.o_column_quick_create .btn-primary')); + assert.containsN(kanban, '.o_kanban_group', 3, "should now have three columns"); // add another column - assert.strictEqual(kanban.$('.o_column_quick_create .o_quick_create_folded:visible').length, 0, + assert.containsNone(kanban, '.o_column_quick_create .o_quick_create_folded:visible', "the ColumnQuickCreate should still be unfolded"); - assert.strictEqual(kanban.$('.o_column_quick_create .o_quick_create_unfolded:visible').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create .o_quick_create_unfolded:visible', "the ColumnQuickCreate should still be unfolded"); kanban.$('.o_column_quick_create input').val('New Column 2'); - kanban.$('.o_column_quick_create .btn-primary').click(); - assert.strictEqual(kanban.$('.o_kanban_group').length, 4, + testUtils.dom.click(kanban.$('.o_column_quick_create .btn-primary')); + assert.containsN(kanban, '.o_kanban_group', 4, "should now have four columns"); kanban.destroy(); @@ -3206,17 +3142,17 @@ QUnit.module('Views', { groupBy: ['product_id'], }); - assert.strictEqual(kanban.$('.o_column_quick_create').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create', "should have a ColumnQuickCreate widget"); // open the quick create - kanban.$('.o_column_quick_create .o_quick_create_folded').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded')); - assert.strictEqual(kanban.$('.o_column_quick_create .o_kanban_examples:visible').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create .o_kanban_examples:visible', "should have a link to see examples"); // click to see the examples - kanban.$('.o_column_quick_create .o_kanban_examples').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create .o_kanban_examples')); assert.strictEqual($('.modal .o_kanban_examples_dialog').length, 1, "should have open the examples dialog"); @@ -3263,7 +3199,7 @@ QUnit.module('Views', { }); kanban.update({groupBy: []}); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped')); + assert.hasClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped'); kanban.destroy(); }); @@ -3281,11 +3217,11 @@ QUnit.module('Views', { '' + '', }); - assert.notOk(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), "should not be grouped"); + assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped', "should not be grouped"); kanban.update({groupBy: ['product_id']}); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), "should be grouped"); + assert.hasClass(kanban.$('.o_kanban_view'),'o_kanban_grouped', "should be grouped"); kanban.update({groupBy: []}); - assert.notOk(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), "should not be grouped"); + assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped', "should not be grouped"); kanban.destroy(); }); @@ -3313,7 +3249,7 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 1, + assert.containsOnce(kanban, '.o_view_nocontent', "should display the no content helper"); assert.strictEqual(kanban.$('.o_view_nocontent p.hello:contains(add a partner)').length, 1, @@ -3322,7 +3258,7 @@ QUnit.module('Views', { this.data.partner.records = records; kanban.reload(); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "should not display the no content helper"); kanban.destroy(); }); @@ -3362,9 +3298,9 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, + assert.containsN(kanban, '.o_kanban_group', 2, "there should be two columns"); - assert.strictEqual(kanban.$('.o_kanban_record').length, 0, + assert.containsNone(kanban, '.o_kanban_record', "there should be no records"); kanban.destroy(); @@ -3392,13 +3328,13 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 0, + assert.containsNone(kanban, '.o_kanban_group', "there should be no columns"); - assert.strictEqual(kanban.$('.o_kanban_record').length, 0, + assert.containsNone(kanban, '.o_kanban_record', "there should be no records"); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should be no nocontent helper (we are in 'column creation mode')"); - assert.strictEqual(kanban.$('.o_column_quick_create').length, 1, + assert.containsOnce(kanban, '.o_column_quick_create', "there should be a column quick create"); kanban.destroy(); }); @@ -3425,14 +3361,14 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should be no nocontent helper (we are in 'column creation mode')"); // creating a new column kanban.$('.o_column_quick_create .o_input').val('applejack'); - kanban.$('.o_column_quick_create .o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create .o_kanban_add')); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should be no nocontent helper (still in 'column creation mode')"); // leaving column creation mode @@ -3441,7 +3377,7 @@ QUnit.module('Views', { which: $.ui.keyCode.ESCAPE, })); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 1, + assert.containsOnce(kanban, '.o_view_nocontent', "there should be a nocontent helper"); kanban.destroy(); @@ -3478,12 +3414,12 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 1, + assert.containsOnce(kanban, '.o_view_nocontent', "there should be a nocontent helper"); - kanban.$('.o_kanban_add_column').click(); + testUtils.dom.click(kanban.$('.o_kanban_add_column')); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should be no nocontent helper (we are in 'column creation mode')"); kanban.destroy(); @@ -3520,15 +3456,15 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 1, + assert.containsOnce(kanban, '.o_view_nocontent', "there should be a nocontent helper"); // add a record - kanban.$('.o_kanban_quick_add').click(); - kanban.$('.o_kanban_quick_create .o_input').val('twilight sparkle').trigger('input'); - kanban.$('button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_quick_add')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create .o_input'), 'twilight sparkle'); + testUtils.dom.click(kanban.$('.o_kanban_quick_create button.o_kanban_add')); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should be no nocontent helper (there is now one record)"); kanban.destroy(); @@ -3565,14 +3501,14 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 1, + assert.containsOnce(kanban, '.o_view_nocontent', "there should be a nocontent helper"); // add a record - kanban.$('.o_kanban_quick_add').click(); - kanban.$('.o_kanban_quick_create .o_input').val('twilight sparkle').trigger('input'); + testUtils.dom.click(kanban.$('.o_kanban_quick_add')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create .o_input'), 'twilight sparkle'); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should be no nocontent helper (there is now one record)"); kanban.destroy(); @@ -3610,11 +3546,11 @@ QUnit.module('Views', { }); // add a record - kanban.$('.o_kanban_quick_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_quick_add')); - kanban.$('.o_kanban_view').click(); + testUtils.dom.click(kanban.$('.o_kanban_view')); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 1, + assert.containsOnce(kanban, '.o_view_nocontent', "there should be again a nocontent helper"); kanban.destroy(); @@ -3643,13 +3579,13 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.$('.o_kanban_group').length, 0, + assert.containsNone(kanban, '.o_kanban_group', "there should be no columns"); - assert.strictEqual(kanban.$('.o_kanban_record').length, 0, + assert.containsNone(kanban, '.o_kanban_record', "there should be no records"); - assert.strictEqual(kanban.$('.o_view_nocontent').length, 0, + assert.containsNone(kanban, '.o_view_nocontent', "there should not be a nocontent helper"); - assert.strictEqual(kanban.$('.o_column_quick_create').length, 0, + assert.containsNone(kanban, '.o_column_quick_create', "there should not be a column quick create"); kanban.destroy(); }); @@ -3678,9 +3614,9 @@ QUnit.module('Views', { '', }); - assert.strictEqual(kanban.$(".o_btn_test_1").length, 1, + assert.containsOnce(kanban, ".o_btn_test_1", "kanban should have one buttons of type 1"); - assert.strictEqual(kanban.$(".o_btn_test_2").length, 3, + assert.containsN(kanban, ".o_btn_test_2", 3, "kanban should have three buttons of type 2"); kanban.destroy(); }); @@ -3709,14 +3645,14 @@ QUnit.module('Views', { "kanban should have at least one button a1"); var count = 0; - testUtils.intercept(kanban, 'execute_action', function (event) { + testUtils.mock.intercept(kanban, 'execute_action', function (event) { count++; event.data.on_closed(); }); - $('button[data-name="a1"]').first().click(); + testUtils.dom.click($('button[data-name="a1"]').first()); assert.strictEqual(count, 1, "should have triggered a execute action"); - $('button[data-name="a1"]').first().click(); + testUtils.dom.click($('button[data-name="a1"]').first()); assert.strictEqual(count, 1, "double-click on kanban actions should be debounced"); assert.verifySteps([ @@ -3751,13 +3687,13 @@ QUnit.module('Views', { '', }); - testUtils.intercept(kanban, 'execute_action', function (event) { + testUtils.mock.intercept(kanban, 'execute_action', function (event) { data.partner.records[0].active = false; event.data.on_closed(); }); assert.strictEqual(kanban.$('.o_kanban_record:contains(yop)').length, 1, "should display 'yop' record"); - kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_active"]').click(); + testUtils.dom.click(kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_active"]')); assert.strictEqual(kanban.$('.o_kanban_record:contains(yop)').length, 0, "should remove 'yop' record from the view"); kanban.destroy(); @@ -3781,12 +3717,12 @@ QUnit.module('Views', { '', }); - testUtils.intercept(kanban, 'execute_action', function (event) { + testUtils.mock.intercept(kanban, 'execute_action', function (event) { event.data.on_closed(); }); try { - kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_action"]').click(); + testUtils.dom.click(kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_action"]')); assert.strictEqual(true, true, 'Everything went fine'); } catch (e) { assert.strictEqual(true, false, 'Error triggered at action execution'); @@ -3879,9 +3815,9 @@ QUnit.module('Views', { }, }); - assert.ok(kanban.$('.o_kanban_view').hasClass('ui-sortable'), + assert.hasClass(kanban.$('.o_kanban_view'),'ui-sortable', "columns should be sortable"); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, + assert.containsN(kanban, '.o_kanban_group', 2, "should have two columns"); assert.strictEqual(kanban.$('.o_kanban_group:first').data('id'), 3, "first column should be id 3 before resequencing"); @@ -3921,7 +3857,7 @@ QUnit.module('Views', { '', }); - assert.strictEqual(kanban.$('button.oe_kanban_action_button').length, 1, + assert.containsOnce(kanban, 'button.oe_kanban_action_button', "only one button should be visible"); kanban.destroy(); }); @@ -3967,7 +3903,7 @@ QUnit.module('Views', { var $firstRecord = kanban.$('.o_kanban_record:first()'); - assert.strictEqual(kanban.$('.o_kanban_record.oe_kanban_color_12').length, 0, + assert.containsNone(kanban, '.o_kanban_record.oe_kanban_color_12', "no record should have the color 12"); assert.strictEqual($firstRecord.find('.oe_kanban_colorpicker').length, 1, "there should be a color picker"); @@ -3975,7 +3911,8 @@ QUnit.module('Views', { "the color picker should have 12 children (the colors)"); // Set a color - $firstRecord.find('.oe_kanban_colorpicker a.oe_kanban_color_9').click(); + testUtils.kanban.toggleRecordDropdown($firstRecord); + testUtils.dom.click($firstRecord.find('.oe_kanban_colorpicker a.oe_kanban_color_9')); assert.ok(writeOnColor, "should write on the color field"); $firstRecord = kanban.$('.o_kanban_record:first()'); // First record is reloaded here assert.ok($firstRecord.is('.oe_kanban_color_9'), @@ -4020,7 +3957,7 @@ QUnit.module('Views', { // load more envIDs = [1, 2, 3, 4]; // id 3 will be loaded - kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more')); assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3, "there should now be 3 records in the column"); @@ -4086,7 +4023,7 @@ QUnit.module('Views', { assert.verifySteps([[7]], "only the appearing category should be fetched"); // load more - kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more')); assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3, "there should now be 3 records in the column"); @@ -4112,14 +4049,14 @@ QUnit.module('Views', { groupBy: ['product_id'], }); - assert.ok(kanban.$buttons.find('.o-kanban-button-new').hasClass('o_hidden'), + assert.isNotVisible(kanban.$buttons.find('.o-kanban-button-new'), "Create button should be hidden"); - kanban.$('.o_column_quick_create').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create')); kanban.$('.o_column_quick_create input').val('new column'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); - assert.notOk(kanban.$buttons.find('.o-kanban-button-new').hasClass('o_hidden'), + assert.isVisible(kanban.$buttons.find('.o-kanban-button-new'), "Create button should now be visible"); kanban.destroy(); }); @@ -4149,13 +4086,13 @@ QUnit.module('Views', { }, }); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), + assert.hasClass(kanban.$('.o_kanban_view'),'o_kanban_grouped', "should have classname 'o_kanban_grouped'"); - assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns"); + assert.containsN(kanban, '.o_kanban_group', 2, "should have " + 2 + " columns"); // simulate an update coming from the searchview, with another groupby given kanban.update({groupBy: ['product_id']}); - assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have " + 3 + " columns"); + assert.containsN(kanban, '.o_kanban_group', 3, "should have " + 3 + " columns"); assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1, "column should contain 1 record(s)"); assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2, @@ -4194,18 +4131,18 @@ QUnit.module('Views', { groupBy: ['product_id'], }); - kanban.$('.o_column_quick_create').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create')); kanban.$('.o_column_quick_create input').val('column1'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); - kanban.$('.o_column_quick_create').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create')); kanban.$('.o_column_quick_create input').val('column2'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); - kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_add i').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_add i')); var $quickCreate = kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_create'); - $quickCreate.find('input').val('new partner').trigger('input'); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('input'), 'new partner'); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 0, "column should contain 0 record"); @@ -4214,7 +4151,7 @@ QUnit.module('Views', { var $record = kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(0)'); var $group = kanban.$('.o_kanban_group:eq(0)'); - testUtils.dragAndDrop($record, $group); + testUtils.dom.dragAndDrop($record, $group); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 1, "column should contain 1 records"); @@ -4224,7 +4161,7 @@ QUnit.module('Views', { $record = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'); $group = kanban.$('.o_kanban_group:eq(1)'); - testUtils.dragAndDrop($record, $group); + testUtils.dom.dragAndDrop($record, $group); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 0, "column should contain 0 records"); @@ -4258,19 +4195,19 @@ QUnit.module('Views', { }, }); - kanban.$('.o_column_quick_create').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create')); kanban.$('.o_column_quick_create input').val('column1'); - kanban.$('.o_column_quick_create button.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add')); - kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i')); var $quickCreate = kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_create'); - $quickCreate.find('input').val('record1').trigger('input'); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('input'), 'record1'); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); - kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i').click(); + testUtils.dom.click(kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i')); $quickCreate = kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_create'); - $quickCreate.find('input').val('record2').trigger('input'); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('input'), 'record2'); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2, "column should contain 2 records"); @@ -4281,7 +4218,7 @@ QUnit.module('Views', { var $record1 = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)'); var $record2 = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'); - testUtils.dragAndDrop($record1, $record2, {position: 'top'}); + testUtils.dom.dragAndDrop($record1, $record2, {position: 'top'}); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2, "column should contain 2 records"); @@ -4290,7 +4227,7 @@ QUnit.module('Views', { assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)').text(), "record2", "records should be correctly ordered"); - testUtils.dragAndDrop($record2, $record1, {position: 'top'}); + testUtils.dom.dragAndDrop($record2, $record1, {position: 'top'}); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2, "column should contain 2 records"); @@ -4356,7 +4293,7 @@ QUnit.module('Views', { groupBy: ['bar'], }); - assert.strictEqual(kanban.$('.o_kanban_counter').length, this.data.product.records.length, + assert.containsN(kanban, '.o_kanban_counter', this.data.product.records.length, "kanban counters should have been created"); assert.strictEqual(parseInt(kanban.$('.o_kanban_counter_side').last().text()), 36, @@ -4419,11 +4356,11 @@ QUnit.module('Views', { // Create a new column: this should create an empty progressbar var $columnQuickCreate = kanban.$('.o_column_quick_create'); - $columnQuickCreate.click(); + testUtils.dom.click($columnQuickCreate.find('.o_quick_create_folded')); $columnQuickCreate.find('input').val('test'); - $columnQuickCreate.find('.btn-primary').click(); + testUtils.dom.click($columnQuickCreate.find('.btn-primary')); - assert.strictEqual(kanban.$('.o_kanban_counter').length, nbProgressBars + 1, + assert.containsN(kanban, '.o_kanban_counter', nbProgressBars + 1, "a new column with a new column progressbar should have been created"); kanban.destroy(); @@ -4449,9 +4386,9 @@ QUnit.module('Views', { }); var initialCount = parseInt(kanban.$('.o_kanban_counter_side:first').text()); - kanban.$('.o_kanban_quick_add:first').click(); - kanban.$('.o_kanban_quick_create input').val('Test').trigger('input'); - kanban.$('.o_kanban_add').click(); + testUtils.dom.click(kanban.$('.o_kanban_quick_add:first')); + testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'Test'); + testUtils.dom.click(kanban.$('.o_kanban_add')); var lastCount = parseInt(kanban.$('.o_kanban_counter_side:first').text()); assert.strictEqual(lastCount, initialCount + 1, "kanban counters should have updated on quick create"); @@ -4480,8 +4417,8 @@ QUnit.module('Views', { }); // we have 1 record shown, load 2 more and check it worked - kanban.$('.o_kanban_group').find('.o_kanban_load_more').click(); - kanban.$('.o_kanban_group').find('.o_kanban_load_more').click(); + testUtils.dom.click(kanban.$('.o_kanban_group').find('.o_kanban_load_more')); + testUtils.dom.click(kanban.$('.o_kanban_group').find('.o_kanban_load_more')); var shownIDs = _.map(kanban.$('.o_kanban_record'), function(record) { return parseInt(record.innerText); }); @@ -4521,9 +4458,9 @@ QUnit.module('Views', { "the counter progressbars should be correctly displayed"); // archive all records of the second columns - kanban.$('.o_kanban_group:eq(1) .o_kanban_config a.o-no-caret').click(); - kanban.$('.o_column_archive_records:visible').click(); - $('.modal-footer button:first').click(); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:eq(1)')); + testUtils.dom.click(kanban.$('.o_column_archive_records:visible')); + testUtils.dom.click($('.modal-footer button:first')); assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_counter_side').text(), "0", "counter should contain the correct value"); @@ -4564,9 +4501,9 @@ QUnit.module('Views', { }); // archive all records of the first column - kanban.$('.o_kanban_group:first .o_kanban_config a.o-no-caret').click(); - kanban.$('.o_column_archive_records:visible').click(); - $('.modal-footer button:first').click(); + testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:first')); + testUtils.dom.click(kanban.$('.o_column_archive_records:visible')); + testUtils.dom.click($('.modal-footer button:first')); assert.verifySteps([ [1, 2, 3, 4], @@ -4649,15 +4586,15 @@ QUnit.module('Views', { assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "1", "counter should contain the correct value"); - testUtils.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)')); + testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)')); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "0", "counter should contain the correct value"); - testUtils.dragAndDrop(kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(2)'), kanban.$('.o_kanban_group:eq(0)')); + testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(2)'), kanban.$('.o_kanban_group:eq(0)')); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "1", "counter should contain the correct value"); - testUtils.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)')); + testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)')); assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "0", "counter should contain the correct value"); @@ -4683,11 +4620,12 @@ QUnit.module('Views', { groupBy: ['bar'], }); - var initialCount = parseInt(kanban.$('.o_kanban_counter_side').eq(1).text()); + var $secondGroup = kanban.$('.o_kanban_group:eq(1)'); + var initialCount = parseInt($secondGroup.find('.o_kanban_counter_side').text()); assert.strictEqual(initialCount, 3, "Initial count should be Three"); - kanban.$('.bg-success-full').click(); - var lastCount = parseInt(kanban.$('.o_kanban_counter_side').eq(1).text()); + testUtils.dom.click($secondGroup.find('.bg-success-full')); + var lastCount = parseInt($secondGroup.find('.o_kanban_counter_side').text()); assert.strictEqual(lastCount, 1, "kanban counters should vary according to what subgroup is selected"); @@ -4720,11 +4658,11 @@ QUnit.module('Views', { var initialCount = parseInt(kanban.$('.o_kanban_counter_side:first').text()); - // click on 'Create', fill the quick create and validate - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); + // fill the quick create and validate var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create'); - $quickCreate.find('.o_field_widget[name=int_field]').val('44').trigger('input'); - $quickCreate.find('button.o_kanban_add').click(); + testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '44'); + testUtils.dom.click($quickCreate.find('button.o_kanban_add')); var lastCount = parseInt(kanban.$('.o_kanban_counter_side:first').text()); assert.strictEqual(lastCount, initialCount + 44, @@ -4759,12 +4697,12 @@ QUnit.module('Views', { var $quickCreateGroup; var $groups; _quickCreateAndTest(); - testUtils.dragAndDrop($groups.first().find('.o_kanban_record:first'), $groups.eq(1)); + testUtils.dom.dragAndDrop($groups.first().find('.o_kanban_record:first'), $groups.eq(1)); _quickCreateAndTest(); kanban.destroy(); function _quickCreateAndTest() { - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); $quickCreateGroup = kanban.$('.o_kanban_quick_create').closest('.o_kanban_group'); $groups = kanban.$('.o_kanban_group'); assert.strictEqual($quickCreateGroup[0], $groups[0], @@ -4802,7 +4740,7 @@ QUnit.module('Views', { assert.expect(1); var instanceNumber = 0; - testUtils.patch(mixins.ParentedMixin, { + testUtils.mock.patch(mixins.ParentedMixin, { init: function () { instanceNumber++; return this._super.apply(this, arguments); @@ -4850,7 +4788,7 @@ QUnit.module('Views', { kanban.destroy(); - testUtils.unpatch(mixins.ParentedMixin); + testUtils.mock.unpatch(mixins.ParentedMixin); }); QUnit.test('grouped kanban becomes ungrouped when clearing domain then clearing groupby', function (assert) { @@ -4886,18 +4824,18 @@ QUnit.module('Views', { }, }); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), + assert.hasClass(kanban.$('.o_kanban_view'),'o_kanban_grouped', "the kanban view should be grouped"); - assert.notOk(kanban.$('.o_kanban_view').hasClass('o_kanban_ungrouped'), + assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_ungrouped', "the kanban view should not be ungrouped"); kanban.update({domain: []}); // 1st update on kanban view kanban.update({groupBy: false}); // 2n update on kanban view def.resolve(); // simulate slow 1st update of kanban view - assert.notOk(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), + assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped', "the kanban view should not longer be grouped"); - assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_ungrouped'), + assert.hasClass(kanban.$('.o_kanban_view'),'o_kanban_ungrouped', "the kanban view should have become ungrouped"); kanban.destroy(); @@ -4910,7 +4848,8 @@ QUnit.module('Views', { View: KanbanView, model: 'partner', data: this.data, - arch: '' + + // force group_create to false, otherwise the CREATE button in control panel is hidden + arch: '' + '
' + '' + '
' + @@ -4923,7 +4862,7 @@ QUnit.module('Views', { }, }, }); - kanban.$buttons.find('.o-kanban-button-new').click(); + testUtils.kanban.clickCreate(kanban); kanban.destroy(); }); @@ -5071,7 +5010,7 @@ QUnit.module('Views', { '
', }); - testUtils.intercept(kanban, 'switch_view', function (event) { + testUtils.mock.intercept(kanban, 'switch_view', function (event) { assert.deepEqual(event.data, { view_type: 'form', res_id: 1, diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 030a676f4eb..51a4d424d10 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -105,15 +105,15 @@ QUnit.module('Views', { arch: '', }); - assert.notOk(list.$el.hasClass('o_cannot_create'), + assert.doesNotHaveClass(list.$el, 'o_cannot_create', "should not have className 'o_cannot_create'"); // 3 th (1 for checkbox, 2 for columns) - assert.strictEqual(list.$('th').length, 3, "should have 3 columns"); + assert.containsN(list, 'th', 3, "should have 3 columns"); assert.strictEqual(list.$('td:contains(gnap)').length, 1, "should contain gnap"); - assert.strictEqual(list.$('tbody tr').length, 4, "should have 4 rows"); - assert.strictEqual(list.$('th.o_column_sortable').length, 1, "should have 1 sortable column"); + assert.containsN(list, 'tbody tr', 4, "should have 4 rows"); + assert.containsOnce(list, 'th.o_column_sortable', "should have 1 sortable column"); assert.strictEqual(list.$('thead th:nth(2)').css('text-align'), 'right', "header cells of integer fields should be right aligned"); @@ -139,7 +139,7 @@ QUnit.module('Views', { arch: '', }); - assert.ok(list.$el.hasClass('o_cannot_create'), + assert.hasClass(list.$el,'o_cannot_create', "should have className 'o_cannot_create'"); assert.strictEqual(list.$buttons.find('.o_list_button_add').length, 0, "should not have the 'Create' button"); @@ -158,11 +158,11 @@ QUnit.module('Views', { arch: '', }); - assert.ok(list.sidebar.$el.hasClass('o_hidden'), 'sidebar should be invisible'); + assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible'); assert.ok(list.$('tbody td.o_list_record_selector').length, 'should have at least one record'); - list.$('tbody td.o_list_record_selector:first input').click(); - assert.ok(!list.sidebar.$el.hasClass('o_hidden'), 'sidebar should be visible'); + testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input')); + assert.isVisible(list.sidebar.$el, 'sidebar should be visible'); assert.notOk(list.sidebar.$('a:contains(Delete)').length, 'sidebar should not have Delete button'); list.destroy(); @@ -178,8 +178,8 @@ QUnit.module('Views', { arch: '', }); - assert.strictEqual(list.$('th').length, 3, "should have 2 th"); - assert.strictEqual(list.$('th').length, 3, "should have 3 th"); + assert.containsN(list, 'th', 3, "should have 2 th"); + assert.containsN(list, 'th', 3, "should have 3 th"); assert.strictEqual(list.$('td:contains(yop)').length, 1, "should contain yop"); assert.ok(list.$buttons.find('.o_list_button_add').is(':visible'), @@ -189,7 +189,7 @@ QUnit.module('Views', { assert.ok(!list.$buttons.find('.o_list_button_discard').is(':visible'), "should not have a visible discard button"); - list.$('td:not(.o_list_record_selector)').first().click(); + testUtils.dom.click(list.$('td:not(.o_list_record_selector)').first()); assert.ok(!list.$buttons.find('.o_list_button_add').is(':visible'), "should not have a visible Create button"); @@ -198,7 +198,7 @@ QUnit.module('Views', { assert.ok(list.$buttons.find('.o_list_button_discard').is(':visible'), "should have a visible discard button"); - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); assert.ok(list.$buttons.find('.o_list_button_add').is(':visible'), "should have a visible Create button"); @@ -223,7 +223,7 @@ QUnit.module('Views', { }); // 1 th for checkbox, 1 for 1 visible column - assert.strictEqual(list.$('th').length, 2, "should have 2 th"); + assert.containsN(list, 'th', 2, "should have 2 th"); list.destroy(); }); @@ -241,11 +241,11 @@ QUnit.module('Views', { '', }); - assert.strictEqual(list.$('tbody tr:first td').length, 4, + assert.containsN(list, 'tbody tr:first td', 4, "there should be 4 cells in the first row"); - assert.strictEqual(list.$('tbody td.o_invisible_modifier').length, 1, + assert.containsOnce(list, 'tbody td.o_invisible_modifier', "there should be 1 invisible bar cell"); - assert.ok(list.$('tbody tr:first td:eq(2)').hasClass('o_invisible_modifier'), + assert.hasClass(list.$('tbody tr:first td:eq(2)'),'o_invisible_modifier', "the 3rd cell should be invisible"); assert.strictEqual(list.$('tbody tr:eq(0) td:visible').length, list.$('tbody tr:eq(1) td:visible').length, "there should be the same number of visible cells in different rows"); @@ -271,7 +271,7 @@ QUnit.module('Views', { }, }); - list.$buttons.find('.o_list_button_add').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_add')); assert.verifySteps(['search_read', 'default_get'], "no nameget should be done"); list.destroy(); @@ -288,7 +288,7 @@ QUnit.module('Views', { domain: [['bar', '=', true]], }); - assert.strictEqual(list.$('tbody tr').length, 4, "should have 4 rows"); + assert.containsN(list, 'tbody tr', 4, "should have 4 rows"); list.destroy(); }); @@ -305,8 +305,8 @@ QUnit.module('Views', { assert.strictEqual(list.$('th:contains(Foo)').length, 1, "should contain Foo"); assert.strictEqual(list.$('th:contains(Bar)').length, 1, "should contain Bar"); - assert.strictEqual(list.$('tr.o_group_header').length, 2, "should have 2 .o_group_header"); - assert.strictEqual(list.$('th.o_group_name').length, 2, "should have 2 .o_group_name"); + assert.containsN(list, 'tr.o_group_header', 2, "should have 2 .o_group_header"); + assert.containsN(list, 'th.o_group_name', 2, "should have 2 .o_group_name"); list.destroy(); }); @@ -404,9 +404,9 @@ QUnit.module('Views', { groupBy: ['foo'], }); - list.$('th.o_group_name').get(1).click(); + testUtils.dom.click(list.$('th.o_group_name:nth(1)')); assert.strictEqual(list.$('tbody:eq(1) tr').length, 2, "open group should contain 2 records"); - assert.strictEqual(list.$('tbody').length, 3, "should contain 3 tbody"); + assert.containsN(list, 'tbody', 3, "should contain 3 tbody"); assert.strictEqual(list.$('td:contains(9)').length, 1, "should contain 9"); assert.strictEqual(list.$('td:contains(-4)').length, 1, "should contain -4"); assert.strictEqual(list.$('td:contains(10)').length, 1, "should contain 10"); @@ -424,16 +424,16 @@ QUnit.module('Views', { arch: '', }); - testUtils.intercept(list, "open_record", function () { + testUtils.mock.intercept(list, "open_record", function () { assert.ok("list view should trigger 'open_record' event"); }); - list.$('tr td:not(.o_list_record_selector)').first().click(); + testUtils.dom.click(list.$('tr td:not(.o_list_record_selector)').first()); list.update({groupBy: ['foo']}); - assert.strictEqual(list.$('tr.o_group_header').length, 3, "list should be grouped"); - list.$('th.o_group_name').first().click(); + assert.containsN(list, 'tr.o_group_header', 3, "list should be grouped"); + testUtils.dom.click(list.$('th.o_group_name').first()); - list.$('tr:not(.o_group_header) td:not(.o_list_record_selector)').first().click(); + testUtils.dom.click(list.$('tr:not(.o_group_header) td:not(.o_list_record_selector)').first()); list.destroy(); }); @@ -455,31 +455,33 @@ QUnit.module('Views', { var $td = list.$('td:not(.o_list_record_selector)').first(); var $second_td = list.$('td:not(.o_list_record_selector)').eq(1); var $third_td = list.$('td:not(.o_list_record_selector)').eq(2); - $td.click(); - assert.ok($td.parent().hasClass('o_selected_row'), + testUtils.dom.click($td); + assert.hasClass($td.parent(),'o_selected_row', "row should be in edit mode"); - assert.ok($td.hasClass('o_readonly_modifier'), + assert.hasClass($td,'o_readonly_modifier', "foo cell should be readonly in edit mode"); - assert.ok(!$second_td.hasClass('o_readonly_modifier'), + assert.doesNotHaveClass($second_td, 'o_readonly_modifier', "bar cell should be editable"); - assert.ok($third_td.hasClass('o_readonly_modifier'), + assert.hasClass($third_td,'o_readonly_modifier', "int_field cell should be readonly in edit mode"); list.destroy(); }); - QUnit.test('editable list view: no active element', function (assert) { + QUnit.test('editable list view: line with no active element', function (assert) { assert.expect(3); - this.data.bar= { + + this.data.bar = { fields: { titi: {string: "Char", type: "char"}, grosminet: {string: "Bool", type: "boolean"}, }, records: [ - {titi: 'cui', grosminet: true}, - {titi: 'cuicui', grosminet: false}, - ] + {id: 1, titi: 'cui', grosminet: true}, + {id: 2, titi: 'cuicui', grosminet: false}, + ], }; this.data.foo.records[0].o2m = [1, 2]; + var form = createView({ View: FormView, model: 'foo', @@ -494,20 +496,25 @@ QUnit.module('Views', { ''+ '
'+ '', + mockRPC: function (route, args) { + if (args.method === 'write') { + assert.deepEqual(args.args[1], { + o2m: [[1, 1, {grosminet: false}], [4, 2, false]], + }); + } + return this._super.apply(this, arguments); + }, }); + var $td = form.$('.o_data_cell').first(); var $td2 = form.$('.o_data_cell').eq(1); - assert.ok($td.hasClass("o_readonly_modifier"), "first field must be readonly"); - assert.ok($td2.hasClass("o_boolean_toggle_cell"), "second field must be not activable but updatable on click (boolean toggle in this case)"); - $td.click(); //select row first - var $slider = $td2.find('.slider').first(); - try { - $slider.click(); //toggle boolean - assert.ok(true); - } - catch(e) { - assert.ok(false, "should not crash when clicking on the slider"); - } + assert.hasClass($td, 'o_readonly_modifier'); + assert.hasClass($td2, 'o_boolean_toggle_cell'); + testUtils.dom.click($td); + testUtils.dom.click($td2.find('.o_boolean_toggle input')); + + testUtils.form.clickSave(form); + form.destroy(); }); @@ -522,16 +529,16 @@ QUnit.module('Views', { }); var $td = list.$('td:not(.o_list_record_selector)').first(); - assert.ok(!$td.parent().hasClass('o_selected_row'), "td should not be in edit mode"); - $td.click(); - assert.ok($td.parent().hasClass('o_selected_row'), "td should be in edit mode"); + assert.doesNotHaveClass($td.parent(), 'o_selected_row', "td should not be in edit mode"); + testUtils.dom.click($td); + assert.hasClass($td.parent(),'o_selected_row', "td should be in edit mode"); list.destroy(); }); QUnit.test('editable list: add a line and discard', function (assert) { assert.expect(11); - testUtils.patch(basicFields.FieldChar, { + testUtils.mock.patch(basicFields.FieldChar, { destroy: function () { assert.step('destroy'); this._super.apply(this, arguments); @@ -546,34 +553,34 @@ QUnit.module('Views', { domain: [['foo', '=', 'yop']], }); - assert.strictEqual(list.$('tbody tr').length, 4, + assert.containsN(list, 'tbody tr', 4, "list should contain 4 rows"); - assert.strictEqual(list.$('.o_data_row').length, 1, + assert.containsOnce(list, '.o_data_row', "list should contain one record (and thus 3 empty rows)"); assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-1', "pager should be correct"); - list.$buttons.find('.o_list_button_add').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_add')); - assert.strictEqual(list.$('tbody tr').length, 4, + assert.containsN(list, 'tbody tr', 4, "list should still contain 4 rows"); - assert.strictEqual(list.$('.o_data_row').length, 2, + assert.containsN(list, '.o_data_row', 2, "list should contain two record (and thus 2 empty rows)"); assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-2', "pager should be correct"); - list.$buttons.find('.o_list_button_discard').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_discard')); - assert.strictEqual(list.$('tbody tr').length, 4, + assert.containsN(list, 'tbody tr', 4, "list should still contain 4 rows"); - assert.strictEqual(list.$('.o_data_row').length, 1, + assert.containsOnce(list, '.o_data_row', "list should contain one record (and thus 3 empty rows)"); assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-1', "pager should be correct"); assert.verifySteps(['destroy'], "should have destroyed the widget of the removed line"); - testUtils.unpatch(basicFields.FieldChar); + testUtils.mock.unpatch(basicFields.FieldChar); list.destroy(); }); @@ -589,13 +596,13 @@ QUnit.module('Views', { var $td = list.$('td:not(.o_list_record_selector)').first(); var n = 0; - testUtils.intercept(list, "field_changed", function () { + testUtils.mock.intercept(list, "field_changed", function () { n += 1; }); - $td.click(); - $td.find('input').val('abc').trigger('input'); + testUtils.dom.click($td); + testUtils.fields.editInput($td.find('input'), 'abc'); assert.strictEqual(n, 1, "field_changed should have been triggered"); - list.$('td:not(.o_list_record_selector)').eq(2).click(); + testUtils.dom.click(list.$('td:not(.o_list_record_selector)').eq(2)); assert.strictEqual(n, 1, "field_changed should not have been triggered"); list.destroy(); }); @@ -610,15 +617,15 @@ QUnit.module('Views', { arch: '', }); var $td = list.$('td:not(.o_list_record_selector)').first(); - $td.click(); - $td.find('input').val('abc').trigger('input'); + testUtils.dom.click($td); + testUtils.fields.editInput($td.find('input'), 'abc'); assert.strictEqual($td.find('input').val(), 'abc', "char field has been edited correctly"); var $next_row_td = list.$('tbody tr:eq(1) td:not(.o_list_record_selector)').first(); - $next_row_td.click(); // should trigger the save of the previous row + testUtils.dom.click($next_row_td); assert.strictEqual(list.$('td:not(.o_list_record_selector)').first().text(), 'abc', 'changes should be saved correctly'); - assert.ok(!list.$('tbody tr').first().hasClass('o_selected_row'), + assert.doesNotHaveClass(list.$('tbody tr').first(), 'o_selected_row', 'saved row should be in readonly mode'); assert.strictEqual(this.data.foo.records[0].foo, 'abc', "the edition should have been properly saved"); @@ -644,15 +651,15 @@ QUnit.module('Views', { } }); - list.$('.o_data_cell:first').click(); - list.$('input[name="foo"]').val('xyz').trigger('input'); - list.$('.o_column_sortable').click(); + testUtils.dom.click(list.$('.o_data_cell:first')); + testUtils.fields.editInput(list.$('input[name="foo"]'), 'xyz'); + testUtils.dom.click(list.$('.o_column_sortable')); - assert.ok(list.$('.o_data_row:first').hasClass('o_selected_row'), + assert.hasClass(list.$('.o_data_row:first'),'o_selected_row', "first row should still be in edition"); - list.$buttons.find('.o_list_button_save').click(); - assert.ok(!list.$buttons.hasClass('o-editing'), + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); + assert.doesNotHaveClass(list.$buttons, 'o-editing', "list buttons should be back to their readonly mode"); list.destroy(); @@ -671,28 +678,28 @@ QUnit.module('Views', { var $thead_selector = list.$('thead .o_list_record_selector input'); var n = 0; - testUtils.intercept(list, "selection_changed", function () { + testUtils.mock.intercept(list, "selection_changed", function () { n += 1; }); // tbody checkbox click - $tbody_selector.click(); + testUtils.dom.click($tbody_selector); assert.strictEqual(n, 1, "selection_changed should have been triggered"); assert.ok($tbody_selector.is(':checked'), "selection checkbox should be checked"); - $tbody_selector.click(); + testUtils.dom.click($tbody_selector); assert.strictEqual(n, 2, "selection_changed should have been triggered"); assert.ok(!$tbody_selector.is(':checked'), "selection checkbox shouldn't be checked"); // head checkbox click - $thead_selector.click(); + testUtils.dom.click($thead_selector); assert.strictEqual(n, 3, "selection_changed should have been triggered"); - assert.strictEqual(list.$('tbody .o_list_record_selector input:checked').length, + assert.containsN(list, 'tbody .o_list_record_selector input:checked', list.$('tbody tr').length, "all selection checkboxes should be checked"); - $thead_selector.click(); + testUtils.dom.click($thead_selector); assert.strictEqual(n, 4, "selection_changed should have been triggered"); - assert.strictEqual(list.$('tbody .o_list_record_selector input:checked').length, 0, + assert.containsNone(list, 'tbody .o_list_record_selector input:checked', "no selection checkbox should be checked"); list.destroy(); }); @@ -715,7 +722,7 @@ QUnit.module('Views', { // select first record var $firstRowSelector = list.$('tbody .o_list_record_selector input').first(); - $firstRowSelector.click(); + testUtils.dom.click($firstRowSelector); assert.ok($firstRowSelector.is(':checked'), "first row should be selected"); assert.strictEqual(list.$('tfoot td:nth(2)').text(), '10', "total should be 10 (first record selected)"); @@ -732,7 +739,7 @@ QUnit.module('Views', { }); QUnit.test('selection is kept on render without reload', function (assert) { - assert.expect(5); + assert.expect(6); var list = createView({ View: ListView, @@ -746,26 +753,25 @@ QUnit.module('Views', { '', }); + assert.isNotVisible(list.sidebar); + // open blip grouping and check all lines - list.$('.o_group_header:contains("blip (2)")').click(); - list.$('.o_data_row input').click(); - assert.strictEqual(true, list.sidebar.$el.is(':visible'), - "element checked so sidebar") + testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")')); + testUtils.dom.click(list.$('.o_data_row:first input')); + assert.isVisible(list.sidebar); // open yop grouping and verify blip are still checked - list.$('.o_group_header:contains("yop (1)")').click() - assert.strictEqual(2, list.$('.o_data_row input:checked').length, + testUtils.dom.click(list.$('.o_group_header:contains("yop (1)")')); + assert.containsOnce(list, '.o_data_row input:checked', "opening a grouping does not uncheck others"); - assert.strictEqual(true, list.sidebar.$el.is(':visible'), - "element checked so sidebar") + assert.isVisible(list.sidebar); // close and open blip grouping and verify blip are unchecked - list.$('.o_group_header:contains("blip (2)")').click(); - list.$('.o_group_header:contains("blip (2)")').click(); - assert.strictEqual(0, list.$('.o_data_row input:checked').length, + testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")')); + testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")')); + assert.containsNone(list, '.o_data_row input:checked', "opening and closing a grouping uncheck its elements"); - assert.strictEqual(false, list.sidebar.$el.is(':visible'), - "no element checked so no sidebar") + assert.isNotVisible(list.sidebar); list.destroy(); }); @@ -784,12 +790,12 @@ QUnit.module('Views', { assert.strictEqual(list.$('tfoot td:nth(2)').text(), "32", "total should be 32"); - $tbody_selectors.first().click(); - $tbody_selectors.last().click(); + testUtils.dom.click($tbody_selectors.first()); + testUtils.dom.click($tbody_selectors.last()); assert.strictEqual(list.$('tfoot td:nth(2)').text(), "6", "total should be 6 as first and last records are selected"); - $thead_selector.click(); + testUtils.dom.click($thead_selector); assert.strictEqual(list.$('tfoot td:nth(2)').text(), "32", "total should be 32 as all records are selected"); @@ -821,8 +827,8 @@ QUnit.module('Views', { assert.strictEqual($groupHeader2.find('td:last()').text(), "9", "second group total should be 9"); assert.strictEqual(list.$('tfoot td:last()').text(), "32", "total should be 32"); - $groupHeader1.click(); - list.$('tbody .o_list_record_selector input').first().click(); + testUtils.dom.click($groupHeader1); + testUtils.dom.click(list.$('tbody .o_list_record_selector input').first()); assert.strictEqual(list.$('tfoot td:last()').text(), "10", "total should be 10 as first record of first group is selected"); list.destroy(); @@ -840,8 +846,8 @@ QUnit.module('Views', { assert.strictEqual(list.$('td[title="Sum"]').text(), "32", "current total should be 32"); - list.$('tr.o_data_row td.o_data_cell').first().click(); - list.$('td.o_data_cell input').val("15").trigger("input"); + testUtils.dom.click(list.$('tr.o_data_row td.o_data_cell').first()); + testUtils.fields.editInput(list.$('td.o_data_cell input'), "15"); assert.strictEqual(list.$('td[title="Sum"]').text(), "37", "current total should now be 37"); @@ -887,12 +893,12 @@ QUnit.module('Views', { "initial order should be 10, 5, 17"); assert.strictEqual(list.$('tfoot td:last()').text(), '32', "total should be 32"); - list.$('.o_column_sortable').click(); // sort (int_field ASC) + testUtils.dom.click(list.$('.o_column_sortable')); assert.strictEqual(list.$('tfoot td:last()').text(), '32', "total should still be 32"); assert.strictEqual(list.$('tbody .o_list_number').text(), '51017', "order should be 5, 10, 17"); - list.$('.o_column_sortable').click(); // sort (int_field DESC) + testUtils.dom.click(list.$('.o_column_sortable')); assert.strictEqual(list.$('tbody .o_list_number').text(), '17105', "initial order should be 17, 10, 5"); assert.strictEqual(list.$('tfoot td:last()').text(), '32', "total should still be 32"); @@ -923,13 +929,13 @@ QUnit.module('Views', { }, }); //we cannot sort by sort_field since it doesn't have a group_operator - list.$('.o_column_sortable:eq(2)').click(); // sort (sort_field ASC(invalid) -> default order) + testUtils.dom.click(list.$('.o_column_sortable:eq(2)')); //we can sort by int_field since it has a group_operator - list.$('.o_column_sortable:eq(1)').click(); // sort (int_field ASC) + testUtils.dom.click(list.$('.o_column_sortable:eq(1)')); //we keep previous order - list.$('.o_column_sortable:eq(2)').click(); // sort (sort_field ASC(invalid) -> int_field ASC) + testUtils.dom.click(list.$('.o_column_sortable:eq(2)')); //we can sort on foo since we are groupped by foo + previous order - list.$('.o_column_sortable:eq(0)').click(); // sort (foo ASC, int_field ASK") + testUtils.dom.click(list.$('.o_column_sortable:eq(0)')); assert.verifySteps([ 'default order', @@ -963,8 +969,8 @@ QUnit.module('Views', { assert.strictEqual($int_field_td.text(), '10', "should contain initial value"); - $foo_td.click(); - $foo_td.find('input').val('tralala').trigger('input'); + testUtils.dom.click($foo_td); + testUtils.fields.editInput($foo_td.find('input'), 'tralala'); assert.strictEqual($int_field_td.find('input').val(), "1007", "should contain input with onchange applied"); @@ -991,13 +997,13 @@ QUnit.module('Views', { var startWidth = list.$('table').addBack('table').width(); // start edition of first row - list.$('td:not(.o_list_record_selector)').first().click(); + testUtils.dom.click(list.$('td:not(.o_list_record_selector)').first()); var editionWidths = _.pluck(list.$('thead th'), 'offsetWidth'); var editionWidth = list.$('table').addBack('table').width(); // leave edition - list.$buttons.find('.o_list_button_save').click(); + testUtils.dom.click(list.$buttons.find('.o_list_button_save')); var readonlyWidths = _.pluck(list.$('thead th'), 'offsetWidth'); var readonlyWidth = list.$('table').addBack('table').width(); @@ -1025,19 +1031,20 @@ QUnit.module('Views', { arch: '', }); - assert.ok(list.sidebar.$el.hasClass('o_hidden'), 'sidebar should be invisible'); - assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 4, "should have 4 records"); + assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible'); + assert.containsN(list, 'tbody td.o_list_record_selector', 4, "should have 4 records"); - list.$('tbody td.o_list_record_selector:first input').click(); + testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input')); - assert.ok(!list.sidebar.$el.hasClass('o_hidden'), 'sidebar should be visible'); + assert.isVisible(list.sidebar.$el, 'sidebar should be visible'); - list.sidebar.$('a:contains(Delete)').click(); - assert.ok($('body').hasClass('modal-open'), 'body should have modal-open clsss'); + testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(list.sidebar.$('a:contains(Delete)')); + assert.hasClass($('body'),'modal-open', 'body should have modal-open clsss'); - $('body .modal button span:contains(Ok)').click(); + testUtils.dom.click($('body .modal button span:contains(Ok)')); - assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 3, "should have 3 records"); + assert.containsN(list, 'tbody td.o_list_record_selector', 3, "should have 3 records"); list.destroy(); }); @@ -1059,23 +1066,25 @@ QUnit.module('Views', { }, }); - assert.ok(list.sidebar.$el.hasClass('o_hidden'), 'sidebar should be invisible'); - assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 4, "should have 4 records"); + assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible'); + assert.containsN(list, 'tbody td.o_list_record_selector', 4, "should have 4 records"); - list.$('tbody td.o_list_record_selector:first input').click(); + testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input')); - assert.ok(!list.sidebar.$el.hasClass('o_hidden'), 'sidebar should be visible'); + assert.isVisible(list.sidebar.$el, 'sidebar should be visible'); assert.verifySteps(['/web/dataset/search_read']); - list.sidebar.$('a:contains(Archive)').click(); + testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(list.sidebar.$('a:contains(Archive)')); assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal-footer .btn-secondary').click(); // Click on 'Cancel' - assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 4, "still should have 4 records"); + testUtils.dom.click($('.modal-footer .btn-secondary')); + assert.containsN(list, 'tbody td.o_list_record_selector', 4, "still should have 4 records"); - list.sidebar.$('a:contains(Archive)').click(); + testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); + testUtils.dom.click(list.sidebar.$('a:contains(Archive)')); assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); - $('.modal-footer .btn-primary').click(); // Click on 'Ok' - assert.strictEqual(list.$('tbody td.o_list_record_selector').length, 3, "should have 3 records"); + testUtils.dom.click($('.modal-footer .btn-primary')); + assert.containsN(list, 'tbody td.o_list_record_selector', 3, "should have 3 records"); assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/write', '/web/dataset/search_read']); list.destroy(); }); @@ -1096,10 +1105,10 @@ QUnit.module('Views', { }, }); - assert.ok(!list.pager.$el.hasClass('o_hidden'), "pager should be visible"); + assert.isVisible(list.pager.$el, "pager should be visible"); assert.strictEqual(list.pager.state.size, 4, "pager's size should be 4"); list.update({ groupBy: ['bar']}); - assert.ok(list.pager.$el.hasClass('o_hidden'), "pager should be invisible"); + assert.isNotVisible(list.pager.$el, "pager should be invisible"); list.destroy(); }); @@ -1129,7 +1138,7 @@ QUnit.module('Views', { "record 3 should be first"); nbSearchRead = 0; - list.$('thead th:contains(Foo)').click(); + testUtils.dom.click(list.$('thead th:contains(Foo)')); assert.strictEqual(nbSearchRead, 1, "should have done one search_read"); assert.ok(list.$('tbody tr:first td:contains(blip)').length, "record 3 should be first"); @@ -1137,7 +1146,7 @@ QUnit.module('Views', { "record 1 should be first"); nbSearchRead = 0; - list.$('thead th:contains(Foo)').click(); + testUtils.dom.click(list.$('thead th:contains(Foo)')); assert.strictEqual(nbSearchRead, 1, "should have done one search_read"); assert.ok(list.$('tbody tr:first td:contains(yop)').length, "record 3 should be first"); @@ -1220,15 +1229,15 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(form.$('tbody tr:first td:contains(Value 1)').length, "Value 1 should be first"); assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length, "Value 3 should be second"); var $o2m = form.$('.o_field_widget[name=o2m]'); - form.$('.o_field_x2many_list_row_add a').click(); - $o2m.find('.o_field_widget').val("Value 2").trigger('input'); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.fields.editInput($o2m.find('.o_field_widget'), "Value 2"); assert.ok(form.$('tbody tr:first td:contains(Value 1)').length, "Value 1 should be first"); assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length, @@ -1236,7 +1245,7 @@ QUnit.module('Views', { assert.ok(form.$('tbody tr:eq(2) td input').val(), "Value 2 should be third (shouldn't be sorted)"); - form.$buttons.find('.o_form_button_save').click(); + testUtils.form.clickSave(form); assert.ok(form.$('tbody tr:first td:contains(Value 1)').length, "Value 1 should be first"); assert.ok(form.$('tbody tr:eq(1) td:contains(Value 2)').length, @@ -1271,15 +1280,15 @@ QUnit.module('Views', { res_id: 1, }); - form.$buttons.find('.o_form_button_edit').click(); + testUtils.form.clickEdit(form); assert.ok(form.$('tbody tr:first td:contains(Value 1)').length, "Value 1 should be first"); assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length, "Value 3 should be second"); var $o2m = form.$('.o_field_widget[name=o2m]'); - form.$('.o_field_x2many_list_row_add a').click(); - $o2m.find('.o_field_widget').val("Value 2").trigger('input'); + testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); + testUtils.fields.editInput($o2m.find('.o_field_widget'), "Value 2"); assert.ok(form.$('tbody tr:first td:contains(Value 1)').length, "Value 1 should be first"); assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length, @@ -1287,9 +1296,9 @@ QUnit.module('Views', { assert.ok(form.$('tbody tr:eq(2) td input').val(), "Value 2 should be third (shouldn't be sorted)"); - form.$('.o_form_sheet_bg').click(); // validate the row before sorting + testUtils.dom.click(form.$('.o_form_sheet_bg')); - $o2m.find('.o_column_sortable').click(); // resort list after edition + testUtils.dom.click($o2m.find('.o_column_sortable')); assert.strictEqual(form.$('tbody tr:first').text(), 'Value 1', "Value 1 should be first"); assert.strictEqual(form.$('tbody tr:eq(1)').text(), 'Value 2', @@ -1297,7 +1306,7 @@ QUnit.module('Views', { assert.strictEqual(form.$('tbody tr:eq(2)').text(), 'Value 3', "Value 3 should be third"); - $o2m.find('.o_column_sortable').click(); + testUtils.dom.click($o2m.find('.o_column_sortable')); assert.strictEqual(form.$('tbody tr:first').text(), 'Value 3', "Value 3 should be first"); assert.strictEqual(form.$('tbody tr:eq(1)').text(), 'Value 2', @@ -1341,13 +1350,13 @@ QUnit.module('Views', { }); // Change page - form.$('.o_pager_next').click(); + testUtils.dom.click(form.$('.o_pager_next')); assert.strictEqual(form.$('tbody tr:first').text(), 'Value 44', "record 44 should be first"); assert.strictEqual(form.$('tbody tr:eq(4)').text(), 'Value 48', "record 48 should be last"); - form.$('.o_column_sortable').click(); + testUtils.dom.click(form.$('.o_column_sortable')); assert.strictEqual(form.$('tbody tr:first').text(), 'Value 08', "record 48 should be first"); assert.strictEqual(form.$('tbody tr:eq(4)').text(), 'Value 04', @@ -1368,8 +1377,8 @@ QUnit.module('Views', { '