From abf32b8b21394491040e5c11c1fea809c1d7c62c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Mon, 19 Nov 2018 08:18:28 +0000 Subject: [PATCH] [REF] *: update js test suite to use helpers This rev. introduces robust helpers to use in the JS tests suite to interact with DOM and components, and starts using them (almost) everywhere. All the helpers are exposed though testUtils.js. There are 2 kinds of helpers: 1. Assertions ------------- * assert.containsNone, containsN, containsOnce check that the DOM (or a specific part of the DOM) contains a `selector`. It generates a correct error message automatically. ex: assert.strictEqual(form.$('.o_form_editable'), 1, "msg"); -> assert.containsOnce(form, '.o_form_editable'); * assert.isVisible, isNotVisible check that the DOM has an element visible or not. They also check that the element is actually in the DOM (before most tests didn't verify this). * assert.hasClass, doesNotHaveClass, hasAttrVAlue, check specific properties of a DOM element, and also validate that it is applied on a single existing DOM element (before most tests didn't verify this). ex: assert.notOk(form.$('button').hasClass('btn-primary')); -> assert.doesNotHaveClass(form.$('button'), 'btn-primary'); 2. Utilities ------------ The goal of the utilities is to centralize the definition of many standard components and interactions, ensuring that when we refactor the JS framework, we do not need to change all the tests. Existing mock utilities (addMockEnvironment, intercept, path, patchDate, unpatch and fieldsViewGet) are moved to 'testUtils.mock.*'. Existing DOM utilities are moved to 'testUtils.dom.*'. New dom utilities are created for opendDatePicker, click, clickFirst and clickLast. Helper `click` verifies that there is exactly 1 element visible in the DOM you click on, `clickFirst` and `clickLast` verify that there are more than one element on the DOM. ex: form.$('button').click(); -> testUtils.dom.click(form.$('button')); New Form utilities: (testUtils.form.*) clickEdit, clickSave, clickCreate, clickDiscard, all clicks on the control panel buttons of the form. `reload` reloads the form data. New modal, graph, kanban and pivot utils (testUtils.pivot.*, testUtils.kanban.*, etc.). New fields utils: (testUtils.fields.*) * editInput, editSelect: allow to change the value of a field, using a selector to identify it. They validate that the input exists and trigger the change event automatically. * editAndTrigger: allow to modify a field and trigger specific events after the value change * many2one (testUtils.fields.many2one.*) clickOpenDropdown, clickHighlightedItem, clickItem, searchAndClickItem: use a field name instead of a selector and do all the complex mechanism to open, filter and highlight many2one fields. Joint work with aab, dam, ged, mge, svs and vsc. --- .../static/tests/reconciliation_tests.js | 158 +- .../static/tests/section_and_note_tests.js | 10 +- addons/barcodes/static/tests/barcode_tests.js | 24 +- .../static/tests/import_buttons_tests.js | 8 +- addons/board/static/tests/dashboard_tests.js | 70 +- addons/bus/static/tests/bus_tests.js | 12 +- .../calendar/static/tests/calendar_tests.js | 8 +- .../tests/systray_activity_menu_tests.js | 20 +- .../tests/sales_team_dashboard_tests.js | 10 +- .../document/static/tests/document_tests.js | 14 +- .../static/tests/google_calendar_tests.js | 6 +- .../google_drive/static/tests/gdrive_test.js | 28 +- .../static/tests/hr_attendance_tests.js | 6 +- .../static/tests/hr_org_chart_tests.js | 10 +- .../tests/website_livechat_window_tests.js | 6 +- .../static/tests/helpers/test_utils.js | 4 +- .../static/tests/systray_no_support_tests.js | 7 +- .../im_support/static/tests/systray_tests.js | 43 +- addons/lunch/static/tests/lunch_tests.js | 10 +- addons/mail/static/tests/activity_tests.js | 30 +- addons/mail/static/tests/chatter_tests.js | 321 ++-- .../mail/static/tests/discuss_mobile_tests.js | 50 +- .../static/tests/discuss_moderation_tests.js | 92 +- addons/mail/static/tests/discuss_tests.js | 104 +- .../discuss_typing_notification_tests.js | 61 +- .../tests/document_thread_window_tests.js | 46 +- .../static/tests/document_viewer_tests.js | 44 +- .../mail/static/tests/helpers/test_utils.js | 2 +- .../systray/systray_activity_menu_tests.js | 52 +- ...stray_messaging_menu_mail_failure_tests.js | 18 +- .../systray/systray_messaging_menu_tests.js | 66 +- .../basic_thread_window_tests.js | 14 +- .../blank_thread_window_tests.js | 14 +- .../hidden_thread_window_tests.js | 10 +- .../moderation_thread_window_tests.js | 2 +- .../static/tests/tools/debug_manager_tests.js | 4 +- .../tests/systray_messaging_menu_tests.js | 20 +- addons/mrp/static/tests/mrp_tests.js | 2 +- .../tests/systray_activity_menu_tests.js | 34 +- addons/pad/static/tests/pad_tests.js | 16 +- .../tests/partner_autocomplete_tests.js | 40 +- addons/project/static/tests/project_tests.js | 26 +- .../static/tests/product_configurator.test.js | 6 +- .../tests/sales_team_dashboard_tests.js | 11 +- .../static/tests/timesheet_plan_tests.js | 2 +- .../sms/static/src/tests/sms_widget_test.js | 7 +- addons/web/static/src/js/tools/test_menus.js | 22 +- .../chrome/action_manager_mobile_tests.js | 41 +- .../tests/chrome/action_manager_tests.js | 470 +++-- addons/web/static/tests/chrome/pager_tests.js | 17 +- .../tests/chrome/search_view_mobile_tests.js | 6 +- .../static/tests/chrome/user_menu_tests.js | 6 +- addons/web/static/tests/core/dom_tests.js | 9 +- addons/web/static/tests/core/mixins_tests.js | 2 +- addons/web/static/tests/core/widget_tests.js | 16 +- .../tests/fields/basic_fields_mobile_tests.js | 32 +- .../static/tests/fields/basic_fields_tests.js | 1056 +++++------ .../field_many2many_tests.js | 188 +- .../relational_fields/field_many2one_tests.js | 528 +++--- .../relational_fields/field_one2many_tests.js | 1541 ++++++++--------- .../fields/relational_fields_mobile_tests.js | 12 +- .../tests/fields/relational_fields_tests.js | 460 +++-- .../web/static/tests/fields/special_fields.js | 2 +- .../tests/fields/upgrade_fields_tests.js | 6 +- .../web/static/tests/helpers/qunit_asserts.js | 229 +++ addons/web/static/tests/helpers/test_utils.js | 1008 +---------- .../static/tests/helpers/test_utils_create.js | 288 +++ .../static/tests/helpers/test_utils_dom.js | 235 +++ .../static/tests/helpers/test_utils_fields.js | 172 ++ .../static/tests/helpers/test_utils_form.js | 74 + .../static/tests/helpers/test_utils_graph.js | 28 + .../static/tests/helpers/test_utils_kanban.js | 97 ++ .../static/tests/helpers/test_utils_mock.js | 545 ++++++ .../static/tests/helpers/test_utils_modal.js | 34 + .../static/tests/helpers/test_utils_pivot.js | 57 + .../services/notification_service_tests.js | 27 +- .../static/tests/tools/debug_manager_tests.js | 8 +- .../tests/views/abstract_controller_tests.js | 4 +- .../web/static/tests/views/calendar_tests.js | 350 ++-- .../web/static/tests/views/form_benchmarks.js | 2 +- addons/web/static/tests/views/form_tests.js | 1351 +++++++-------- addons/web/static/tests/views/graph_tests.js | 71 +- .../static/tests/views/kanban_mobile_tests.js | 24 +- addons/web/static/tests/views/kanban_tests.js | 1087 ++++++------ addons/web/static/tests/views/list_tests.js | 779 +++++---- addons/web/static/tests/views/pivot_tests.js | 263 +-- .../tests/views/search_filters_menu_tests.js | 64 +- .../tests/views/search_groupby_menu_tests.js | 45 +- .../static/tests/views/search_view_tests.js | 196 +-- .../static/tests/views/view_dialogs_tests.js | 44 +- .../static/tests/widgets/data_export_tests.js | 30 +- .../tests/widgets/domain_selector_tests.js | 30 +- .../tests/widgets/dropdown_menu_tests.js | 87 +- .../widgets/model_field_selector_tests.js | 20 +- addons/web/views/webclient_templates.xml | 13 + .../web_diagram/static/tests/diagram_tests.js | 46 +- .../static/tests/web_editor_tests.js | 40 +- .../static/tests/gauge_tests.js | 2 +- .../static/tests/dashboard_tests.js | 20 +- addons/website/static/tests/website_tests.js | 8 +- .../base/static/tests/base_settings_tests.js | 14 +- 101 files changed, 7009 insertions(+), 6345 deletions(-) create mode 100644 addons/web/static/tests/helpers/qunit_asserts.js create mode 100644 addons/web/static/tests/helpers/test_utils_create.js create mode 100644 addons/web/static/tests/helpers/test_utils_dom.js create mode 100644 addons/web/static/tests/helpers/test_utils_fields.js create mode 100644 addons/web/static/tests/helpers/test_utils_form.js create mode 100644 addons/web/static/tests/helpers/test_utils_graph.js create mode 100644 addons/web/static/tests/helpers/test_utils_kanban.js create mode 100644 addons/web/static/tests/helpers/test_utils_mock.js create mode 100644 addons/web/static/tests/helpers/test_utils_modal.js create mode 100644 addons/web/static/tests/helpers/test_utils_pivot.js 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', { '