diff options
| author | Julien Mougenot <jum@odoo.com> | 2020-03-11 09:38:30 +0000 |
|---|---|---|
| committer | Julien Mougenot <jum@odoo.com> | 2020-03-13 14:08:33 +0000 |
| commit | 804507ef4925cafdf5349a3b7fa1e41dbca87ff7 (patch) | |
| tree | 09a097ffb347dae1c9dc7879be261ec734f70d4f /addons | |
| parent | bb8eb766a84b9fd06007d3fb4ab9a29b70097738 (diff) | |
[REF] *: Adapt all module tests to the new control panel
Use of the new control panel helpers to increase consistency and change the assertions
according to the new DOM/behaviour (e.g. components removed instead of turning invisible).
Part of task 2196029
Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com>
Diffstat (limited to 'addons')
34 files changed, 1080 insertions, 3700 deletions
diff --git a/addons/account/static/tests/tours/account_dashboard_setup_bar_tests.js b/addons/account/static/tests/tours/account_dashboard_setup_bar_tests.js index a212e1761ef..0d11b027163 100644 --- a/addons/account/static/tests/tours/account_dashboard_setup_bar_tests.js +++ b/addons/account/static/tests/tours/account_dashboard_setup_bar_tests.js @@ -20,7 +20,7 @@ odoo.define('account.dashboard.setup.tour', function (require) { }, { trigger: '.o_control_panel button:contains("' + _t('Print') + '")', }, { - trigger: '.o_control_panel div.o_dropdown_menu a:contains("' + _t('Invoices without Payment') + '")', + trigger: '.o_control_panel .o_dropdown_menu a:contains("' + _t('Invoices without Payment') + '")', }, { trigger: 'iframe .o_report_layout_standard h2', content: 'Primary color is correct', diff --git a/addons/board/static/tests/dashboard_tests.js b/addons/board/static/tests/dashboard_tests.js index 41cc5928c6a..f192f743997 100644 --- a/addons/board/static/tests/dashboard_tests.js +++ b/addons/board/static/tests/dashboard_tests.js @@ -8,6 +8,7 @@ var testUtils = require('web.test_utils'); var ListRenderer = require('web.ListRenderer'); var pyUtils = require('web.py_utils'); +const cpHelpers = testUtils.controlPanel; var createActionManager = testUtils.createActionManager; var createView = testUtils.createView; @@ -701,7 +702,7 @@ QUnit.test('save actions to dashboard', async function (assert) { var result = this._super.apply(this, arguments); result.context = { 'fire': 'on the bayou', - } + }; return result; } }); @@ -733,7 +734,7 @@ QUnit.test('save actions to dashboard', async function (assert) { return Promise.resolve(true); } return this._super.apply(this, arguments); - }, + } }); await actionManager.doAction({ @@ -750,15 +751,16 @@ QUnit.test('save actions to dashboard', async function (assert) { await testUtils.dom.click($('.o_column_sortable')); // Group It - await testUtils.dom.click($('.o_search_options .o_dropdown button:contains(Group By)')); - await testUtils.dom.click($('.o_search_options .o_group_by_menu button')); - await testUtils.dom.click($('.o_search_options .o_group_by_menu button.o_apply_group')); + await cpHelpers.toggleGroupByMenu(actionManager); + await cpHelpers.toggleAddCustomGroup(actionManager); + await cpHelpers.applyGroup(actionManager); // add this action to dashboard - await testUtils.dom.click($('.o_search_options .o_dropdown button:contains(Favorites)')); - await testUtils.dom.click($('.o_add_to_board.o_menu_header')); - testUtils.fields.editInput($('input.o_add_to_board_input'), 'a name'); - await testUtils.dom.click($('.o_add_to_board_confirm_button')); + await cpHelpers.toggleFavoriteMenu(actionManager); + + await testUtils.dom.click($('.o_add_to_board > button')); + await testUtils.fields.editInput($('.o_add_to_board input'), 'a name'); + await testUtils.dom.click($('.o_add_to_board div button')); testUtils.unpatch(ListController); @@ -802,38 +804,28 @@ QUnit.test('save two searches to dashboard', async function (assert) { var filter_count = 0; // Add a first filter - await testUtils.dom.click(actionManager.$('.o_filters_menu_button')); - await testUtils.dom.click(actionManager.$('.o_add_custom_filter')); - actionManager.$('.o_searchview_extended_prop_value .o_input').val('a'); - await testUtils.dom.click(actionManager.$('.o_apply_filter')); + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleAddCustomFilter(actionManager); + await testUtils.fields.editInput(actionManager.el.querySelector('.o_generator_menu_value .o_input'), 'a'); + await cpHelpers.applyFilter(actionManager); + // Add it to dashboard - await testUtils.dom.click(actionManager.$('.o_favorites_menu_button')); - $('.o_search_options .dropdown-menu.o_favorites_menu').one('click', function (ev) { - // This handler is on the webClient - // But since the test suite doesn't have one - // We manually set it here - ev.stopPropagation(); - }); - await testUtils.dom.click(actionManager.$('.o_add_to_board')); - await testUtils.dom.click(actionManager.$('.o_add_to_board_confirm_button')); + await cpHelpers.toggleFavoriteMenu(actionManager); + await testUtils.dom.click($('.o_add_to_board > button')); + await testUtils.dom.click($('.o_add_to_board div button')); + // Remove it - await testUtils.dom.click(actionManager.$('.o_facet_remove')); + await testUtils.dom.click(actionManager.el.querySelector('.o_facet_remove')); // Add the second filter - await testUtils.dom.click(actionManager.$('.o_filters_menu_button')); - await testUtils.dom.click(actionManager.$('.o_add_custom_filter')); - actionManager.$('.o_searchview_extended_prop_value .o_input').val('b'); - await testUtils.dom.click(actionManager.$('.o_apply_filter')); + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleAddCustomFilter(actionManager); + await testUtils.fields.editInput(actionManager.el.querySelector('.o_generator_menu_value .o_input'), "b"); + await cpHelpers.applyFilter(actionManager); // Add it to dashboard - await testUtils.dom.click(actionManager.$('.o_favorites_menu_button')); - $('.o_search_options .dropdown-menu.o_favorites_menu').one('click', function (ev) { - // This handler is on the webClient - // But since the test suite doesn't have one - // We manually set it here - ev.stopPropagation(); - }); - await testUtils.dom.click(actionManager.$('.o_add_to_board')); - await testUtils.dom.click(actionManager.$('.o_add_to_board_confirm_button')); + await cpHelpers.toggleFavoriteMenu(actionManager); + await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board > button')); + await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board div button')); actionManager.destroy(); }); @@ -846,7 +838,7 @@ QUnit.test('save a action domain to dashboard', async function (assert) { var filter_domain = ["display_name", "ilike", "b"]; // The filter domain already contains the view domain, but is always added by dashboard.., - var expected_domain = ['&', '&', view_domain, view_domain, filter_domain] + var expected_domain = ['&', '&', view_domain, view_domain, filter_domain]; var actionManager = await createActionManager({ data: this.data, @@ -873,14 +865,18 @@ QUnit.test('save a action domain to dashboard', async function (assert) { }); // Add a filter - await testUtils.dom.click(actionManager.$('.o_filters_menu_button')); - await testUtils.dom.click(actionManager.$('.o_add_custom_filter')); - actionManager.$('.o_searchview_extended_prop_value .o_input').val('b'); - await testUtils.dom.click(actionManager.$('.o_apply_filter')); + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleAddCustomFilter(actionManager); + await testUtils.fields.editInput( + actionManager.el.querySelector('.o_generator_menu_value .o_input'), + "b" + ); + await cpHelpers.applyFilter(actionManager); // Add it to dashboard - await testUtils.dom.click(actionManager.$('.o_favorites_menu_button')); - await testUtils.dom.click(actionManager.$('.o_add_to_board')); - await testUtils.dom.click(actionManager.$('.o_add_to_board_confirm_button')); + await cpHelpers.toggleFavoriteMenu(actionManager); + await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board > button')); + // add + await testUtils.dom.click(actionManager.el.querySelector('.o_add_to_board div button')); actionManager.destroy(); }); diff --git a/addons/google_drive/static/tests/gdrive_test.js b/addons/google_drive/static/tests/gdrive_test.js index 158330376bd..b04ebf27c26 100644 --- a/addons/google_drive/static/tests/gdrive_test.js +++ b/addons/google_drive/static/tests/gdrive_test.js @@ -1,166 +1,129 @@ odoo.define('google_drive.gdrive_integration', function (require) { -"use strict"; -//rebuild -var FormView = require('web.FormView'); -var testUtils = require('web.test_utils'); -var GoogleDriveSideBar = require('google_drive.sidebar'); - -var createView = testUtils.createView; - -/* - * @override - * Avoid breaking other tests because of the new route - * that the module introduces - */ -var _addGoogleDocItemsOriginal = GoogleDriveSideBar.prototype._addGoogleDocItems; - -var _addGoogleDocItemsMocked = function (model, resID) { - return Promise.resolve(); -}; - -GoogleDriveSideBar.prototype._addGoogleDocItems = _addGoogleDocItemsMocked; - -QUnit.module('gdrive_integration', { - beforeEach: function () { - // For our test to work, the _addGoogleDocItems function needs to be the original - GoogleDriveSideBar.prototype._addGoogleDocItems = _addGoogleDocItemsOriginal; - - this.data = { - partner: { - fields: { - display_name: {string: "Displayed name", type: "char", searchable: true}, + "use strict"; + + const FormView = require('web.FormView'); + const testUtils = require('web.test_utils'); + + const cpHelpers = testUtils.controlPanel; + + QUnit.module('Google Drive Integration', { + beforeEach() { + this.data = { + partner: { + fields: { + display_name: { string: "Displayed name", type: "char", searchable: true }, + }, + records: [ + { id: 1, display_name: "Locomotive Breath" }, + { id: 2, display_name: "Hey Macarena" }, + ], }, - records: [{ - id: 1, - display_name: "Locomotive Breath", - }, { - id: 2, - display_name: "Hey Macarena", - }], - }, - 'google.drive.config': { - fields: { - model_id: {string: 'Model', type: 'int'}, - name: {string: 'Name', type: 'char'}, - google_drive_resource_id: {string: 'Resource ID', type: 'char'}, + }; + }, + }, function () { + + QUnit.module('Google Drive ActionMenus'); + + QUnit.test('rendering of the google drive attachments in action menus', async function (assert) { + assert.expect(3); + + const form = await testUtils.createView({ + actionMenusRegistry: true, + arch: + `<form string="Partners"> + <field name="display_name"/> + </form>`, + data: this.data, + async mockRPC(route, args) { + switch (route) { + case '/web/dataset/call_kw/google.drive.config/get_google_drive_config': + assert.deepEqual(args.args, ['partner', 1], + 'The route to get google drive config should have been called'); + return [{ + id: 27, + name: 'Cyberdyne Systems', + }]; + case '/web/dataset/call_kw/google.drive.config/search_read': + return [{ + google_drive_resource_id: "T1000", + google_drive_client_id: "cyberdyne.org", + id: 1, + }]; + case '/web/dataset/call_kw/google.drive.config/get_google_drive_url': + assert.deepEqual(args.args, [27, 1, 'T1000'], + 'The route to get the Google url should have been called'); + return; // do not return anything or it will open a new tab. + } }, - records: [{ - id: 27, - name: 'Cyberdyne Systems', - model_id: 1, - google_drive_resource_id: 'T1000', - }], - }, - 'ir.attachment': { - fields: { - name: {string: 'Name', type:'char'} + model: 'partner', + res_id: 1, + View: FormView, + viewOptions: { + hasActionMenus: true, }, - records: [], - } - }; - }, - - afterEach: function() { - GoogleDriveSideBar.prototype._addGoogleDocItems = _addGoogleDocItemsMocked; - } + }); + await cpHelpers.toggleActionMenu(form); -}, function () { - QUnit.module('Google Drive Sidebar'); + assert.containsOnce(form, '.oe_share_gdoc_item', + "The button to the google action should be present"); - QUnit.test('rendering of the google drive attachments in Sidebar', async function (assert) { - assert.expect(3); + await cpHelpers.toggleMenuItem(form, "Cyberdyne Systems"); - var form = await createView({ - View: FormView, - model: 'partner', - data: this.data, - arch: '<form string="Partners">' + - '<field name="display_name"/>' + - '</form>', - res_id: 1, - viewOptions: {hasSidebar: true}, - mockRPC: function (route, args) { - if (route === '/web/dataset/call_kw/google.drive.config/get_google_drive_config') { - assert.deepEqual(args.args, ['partner', 1], - 'The route to get google drive config should have been called'); - return Promise.resolve([{id: 27, name: 'Cyberdyne Systems'}]); - } - if (route === '/web/dataset/call_kw/google.drive.config/search_read'){ - return Promise.resolve([{google_drive_resource_id: "T1000", - google_drive_client_id: "cyberdyne.org", - id: 1}]); - } - if (route === '/web/dataset/call_kw/google.drive.config/get_google_drive_url') { - assert.deepEqual(args.args, [27, 1, '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 Promise.resolve(); - } - return this._super.apply(this, arguments); - }, + form.destroy(); }); - var $googleAction = form.sidebar.$('.oe_share_gdoc'); - - assert.strictEqual($googleAction.length, 1, - 'The button to the google action should be present'); - - // click on gdrive sidebar item - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click($googleAction); + QUnit.test('click on the google drive attachments after switching records', async function (assert) { + assert.expect(4); + + let currentID; + const form = await testUtils.createView({ + actionMenusRegistry: true, + arch: + `<form string="Partners"> + <field name="display_name"/> + </form>`, + data: this.data, + async mockRPC(route, args) { + switch (route) { + case '/web/dataset/call_kw/google.drive.config/get_google_drive_config': + assert.deepEqual(args.args, ['partner', currentID], + 'The route to get google drive config should have been called'); + return [{ + id: 27, + name: 'Cyberdyne Systems', + }]; + case '/web/dataset/call_kw/google.drive.config/search_read': + return [{ + google_drive_resource_id: "T1000", + google_drive_client_id: "cyberdyne.org", + id: 1, + }]; + case '/web/dataset/call_kw/google.drive.config/get_google_drive_url': + assert.deepEqual(args.args, [27, currentID, 'T1000'], + 'The route to get the Google url should have been called'); + return; // do not return anything or it will open a new tab. + } + }, + model: 'partner', + res_id: 1, + View: FormView, + viewOptions: { + hasActionMenus: true, + ids: [1, 2], + index: 0, + }, + }); + currentID = 1; + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Cyberdyne Systems"); - form.destroy(); - }); + await cpHelpers.pagerNext(form); - QUnit.test('click on the google drive attachments after switching records', async function (assert) { - assert.expect(3); + currentID = 2; + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Cyberdyne Systems"); - var currentID; - var form = await createView({ - View: FormView, - model: 'partner', - data: this.data, - arch: '<form string="Partners">' + - '<field name="display_name"/>' + - '</form>', - res_id: 1, - viewOptions: { - hasSidebar: true, - ids: [1, 2], - index: 0, - }, - mockRPC: function (route, args) { - if (route === '/web/dataset/call_kw/google.drive.config/get_google_drive_config') { - assert.deepEqual(args.args, ['partner', 1], - 'The route to get google drive config should have been called'); - return Promise.resolve([{id: 27, name: 'Cyberdyne Systems'}]); - } - if (route === '/web/dataset/call_kw/google.drive.config/search_read'){ - return Promise.resolve([{google_drive_resource_id: "T1000", - google_drive_client_id: "cyberdyne.org", - id: 1}]); - } - if (route === '/web/dataset/call_kw/google.drive.config/get_google_drive_url') { - 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 Promise.resolve(); - } - return this._super.apply(this, arguments); - }, + form.destroy(); }); - - currentID = 1; - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('.oe_share_gdoc')); - - await testUtils.dom.click(form.pager.$('.o_pager_next')); - currentID = 2; - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('.oe_share_gdoc')); - - form.destroy(); }); }); - -}); 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 80e3d443597..c56e371bc0e 100644 --- a/addons/im_support/static/tests/systray_no_support_tests.js +++ b/addons/im_support/static/tests/systray_no_support_tests.js @@ -38,7 +38,7 @@ QUnit.test('messaging menu does not display the Support channel if not available assert.expect(1); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); diff --git a/addons/im_support/static/tests/systray_tests.js b/addons/im_support/static/tests/systray_tests.js index 9df4c3b2bd8..75358276bc3 100644 --- a/addons/im_support/static/tests/systray_tests.js +++ b/addons/im_support/static/tests/systray_tests.js @@ -33,7 +33,7 @@ QUnit.test('messaging menu displays the Support channel', async function (assert assert.expect(1); var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, services: this.services, session: this.supportParams, @@ -51,7 +51,7 @@ QUnit.test('clicking on Support channel: channel not available', async function assert.expect(9); var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, mockRPC: function (route, args) { if (!_.string.endsWith(route, '.png')) { // ignore images @@ -100,7 +100,7 @@ QUnit.test('clicking on Support channel: channel available', async function (ass assert.expect(9); var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, mockRPC: function (route, args) { if (!_.string.endsWith(route, '.png')) { // ignore images @@ -145,7 +145,7 @@ QUnit.test('post messages in Support channel', async function (assert) { assert.expect(8); var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, mockRPC: function (route, args) { if (!_.string.endsWith(route, '.png')) { // ignore images @@ -190,7 +190,7 @@ QUnit.test('fold Support channel', async function (assert) { assert.expect(11); var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, mockRPC: function (route, args) { if (!_.string.endsWith(route, '.png')) { // ignore images @@ -245,7 +245,7 @@ QUnit.test('restore Support channel if necessary', async function (assert) { assert.expect(5); var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, enableSupportPoll: true, mockRPC: function (route, args) { @@ -270,8 +270,8 @@ QUnit.test('restore Support channel if necessary', async function (assert) { "should have open a chat window"); assert.verifySteps([ - 'cors: /odoo_im_support/get_support_channel', '/mail/init_messaging', + 'cors: /odoo_im_support/get_support_channel', 'cors: /odoo_im_support/fetch_messages', ]); @@ -284,7 +284,7 @@ QUnit.test('receive messages in the Support channel', async function (assert) { var supportChannelID; var messagingMenu = new MessagingMenu(); - addMockSupportEnvironment(messagingMenu, { + await addMockSupportEnvironment(messagingMenu, { data: this.data, enableSupportPoll: true, mockRPC: function (route, args) { @@ -330,8 +330,8 @@ QUnit.test('receive messages in the Support channel', async function (assert) { 'A message', "message is correct"); assert.verifySteps([ - 'cors: /odoo_im_support/get_support_channel', '/mail/init_messaging', + 'cors: /odoo_im_support/get_support_channel', 'cors: /odoo_im_support/fetch_messages', ]); diff --git a/addons/mail/static/tests/activity_tests.js b/addons/mail/static/tests/activity_tests.js index c32702d8c45..570bf2165af 100644 --- a/addons/mail/static/tests/activity_tests.js +++ b/addons/mail/static/tests/activity_tests.js @@ -316,7 +316,6 @@ QUnit.test('activity view: activity widget', async function (assert) { }, }; - owl.Component.env = testUtils.mock.getMockedOwlEnv(params); var activity = await createView(params); var today = activity.$('table tbody tr:first td:nth-child(2).today'); var dropdown = today.find('.dropdown-menu.o_activity'); @@ -391,9 +390,9 @@ QUnit.test('activity view: no group_by_menu and no time_range_menu', async funct assert.containsN(actionManager, '.o_search_options .o_dropdown button:visible', 2, "only two elements should be available in view search"); - assert.isVisible(actionManager.$('.o_search_options .o_dropdown button.o_filters_menu_button'), + assert.isVisible(actionManager.$('.o_search_options .o_dropdown.o_filter_menu > button'), "filter should be available in view search"); - assert.isVisible(actionManager.$('.o_search_options .o_dropdown button.o_favorites_menu_button'), + assert.isVisible(actionManager.$('.o_search_options .o_dropdown.o_favorite_menu > button'), "favorites should be available in view search"); actionManager.destroy(); }); diff --git a/addons/mail/static/tests/discuss_tests.js b/addons/mail/static/tests/discuss_tests.js index b12b4b1d9b3..8cf73248754 100644 --- a/addons/mail/static/tests/discuss_tests.js +++ b/addons/mail/static/tests/discuss_tests.js @@ -7,6 +7,7 @@ var mailTestUtils = require('mail.testUtils'); var testUtils = require('web.test_utils'); var createDiscuss = mailTestUtils.createDiscuss; +const cpHelpers = testUtils.controlPanel; QUnit.module('mail', {}, function () { QUnit.module('Discuss', { @@ -139,6 +140,7 @@ QUnit.test('basic rendering', async function (assert) { var $history = $sidebar.find('.o_mail_discuss_item[data-thread-id=mailbox_history]'); assert.strictEqual($history.length, 1, "should have the mailbox item 'mailbox_history' in the sidebar"); + discuss.destroy(); }); @@ -305,43 +307,44 @@ QUnit.test('searchview filter messages', async function (assert) { '</search>', }, }); - 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"); - assert.strictEqual($('.o_searchview_input').val(), '', - "the searchview should be empty initially"); - - // interact with searchview so that there is only once message - $('.o_searchview_input').val("ab").trigger('keyup'); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER })); - await testUtils.nextTick(); - assert.strictEqual($('.o_searchview_facet').length, 1, - "the searchview should have a facet"); - assert.strictEqual($('.o_facet_values').text().trim(), 'ab', - "the facet should be a search on 'ab'"); - 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 - await testUtils.dom.click($('.o_facet_remove')); - $('.o_searchview_input').val("abcd").trigger('keyup'); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER })); - await testUtils.nextTick(); - - assert.strictEqual($('.o_searchview_facet').length, 1, - "the searchview should have a facet"); - assert.strictEqual($('.o_facet_values').text().trim(), 'abcd', - "the facet should be a search on 'abcd'"); - 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", - "should display that there are no matching messages"); + // needed to handle events triggered by the controlPanelModel + discuss.on_attach_callback(); + await testUtils.nextTick(); - discuss.destroy(); + 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"); + assert.strictEqual($('.o_searchview_input').val(), '', + "the searchview should be empty initially"); + + // interact with searchview so that there is only once message + await cpHelpers.editSearch(discuss, "ab"); + await cpHelpers.validateSearch(discuss); + assert.strictEqual($('.o_searchview_facet').length, 1, + "the searchview should have a facet"); + assert.strictEqual($('.o_facet_values').text().trim(), 'ab', + "the facet should be a search on 'ab'"); + 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 + await testUtils.dom.click($('.o_facet_remove')); + await cpHelpers.editSearch(discuss, "abcd"); + await cpHelpers.validateSearch(discuss); + + assert.strictEqual($('.o_searchview_facet').length, 1, + "the searchview should have a facet"); + assert.strictEqual($('.o_facet_values').text().trim(), 'abcd', + "the facet should be a search on 'abcd'"); + 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", + "should display that there are no matching messages"); + + discuss.on_detach_callback(); + discuss.destroy(); }); @@ -1147,6 +1150,7 @@ QUnit.test('mark all messages as read from Inbox', async function (assert) { await testUtils.dom.click($markAllReadButton); + markAllReadDef.then(function () { // immediately jump to end of the fadeout animation on messages $inbox = discuss.$('.o_mail_discuss_item[data-thread-id="mailbox_inbox"]'); @@ -1964,33 +1968,38 @@ QUnit.test('save filter discuss', async function (assert) { } return this._super.apply(this,arguments); }, - intercepts: { - create_filter: function (ev) { - assert.deepEqual( - JSON.parse(ev.data.filter.domain), [ - "|", - ["subject", "ilike", "she was born in a hurricane"], - ["body", "ilike", "she was born in a hurricane"] - ], 'The filter should have been saved with the right domain'); + env: { + dataManager: { + create_filter: async function (filter) { + assert.deepEqual( + JSON.parse(filter.domain), [ + "|", + ["subject", "ilike", "she was born in a hurricane"], + ["body", "ilike", "she was born in a hurricane"] + ], 'The filter should have been saved with the right domain'); + } } } }); + // needed to handle events triggered by the controlPanelModel + discuss.on_attach_callback(); + await testUtils.nextTick(); assert.containsOnce(discuss, '.o_searchview_input_container', 'search view input present'); - $('.o_searchview_input').val("she was born in a hurricane").trigger('keyup'); - await testUtils.nextTick(); + await cpHelpers.editSearch(discuss, "she was born in a hurricane"); messageFetchCount = 1; - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER })); - await testUtils.nextTick(); - await testUtils.dom.click(discuss.$('.o_favorites_menu_button')); - await testUtils.dom.click(discuss.$('.o_add_favorite')); + await cpHelpers.validateSearch(discuss); + + await cpHelpers.toggleFavoriteMenu(discuss); + await cpHelpers.toggleSaveFavorite(discuss); - await testUtils.fields.editInput(discuss.$('.o_favorite_name input'), 'War'); - await testUtils.dom.click(discuss.$('.o_save_favorite button')); + await cpHelpers.editFavoriteName(discuss, "War"); + await cpHelpers.saveFavorite(discuss); + discuss.on_detach_callback(); discuss.destroy(); }); diff --git a/addons/mail/static/tests/document_thread_window_tests.js b/addons/mail/static/tests/document_thread_window_tests.js index d10f32c1e89..f01ab0925f2 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', async function (assert) assert.expect(6); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -129,7 +129,7 @@ QUnit.test('expand a document thread window', async function (assert) { assert.expect(4); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -177,7 +177,7 @@ QUnit.test('post messages in a document thread window', async function (assert) res_id: 1, }; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -229,7 +229,7 @@ QUnit.test('post messages in a document thread window', async function (assert) QUnit.test('open, fold, unfold and close a document thread window', async function (assert) { assert.expect(20); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, @@ -285,7 +285,7 @@ QUnit.test('do not open thread window on fetch message failure', async function assert.expect(4); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: this.session, 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 f2c8e95ac29..3f07f84cbfd 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,7 +82,7 @@ QUnit.test('preview of mail failure', async function (assert) { }]; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); @@ -138,7 +138,7 @@ QUnit.test('preview grouped failures by document', async function (assert) { }]; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); @@ -194,7 +194,7 @@ QUnit.test('preview grouped failures by document model', async function (assert) }]; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); 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 5cca1454b95..f3e2131862c 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', async function (assert assert.expect(1); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, mockRPC: function (route, args) { if (args.method === 'message_fetch') { @@ -114,7 +114,7 @@ QUnit.test('messaging menu widget: menu with no records', async function (assert return this._super.apply(this, arguments); } }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.hasClass(messagingMenu.$('.o_no_activity'),'o_no_activity', "should not have instance of widget"); messagingMenu.destroy(); @@ -126,7 +126,7 @@ QUnit.test('messaging menu widget: messaging not ready', async function (assert) const messagingReadyProm = testUtils.makeTestPromise(); const messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, async mockRPC(route, args) { if (route === '/mail/init_messaging') { @@ -142,7 +142,7 @@ QUnit.test('messaging menu widget: messaging not ready', async function (assert) return this._super(...arguments); }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); assert.verifySteps(['/mail/init_messaging:pending']); assert.ok( messagingMenu.el, @@ -170,11 +170,11 @@ QUnit.test('messaging menu widget: messaging not ready', async function (assert) QUnit.test('messaging menu widget: messaging menu with 1 record', async function (assert) { assert.expect(3); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); @@ -197,14 +197,14 @@ QUnit.test('messaging menu widget: open inbox for needaction not linked to any d assert.expect(4); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 1, }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); // Simulate received needaction message without associated document, // so that we have a message in inbox without a model and a resID @@ -272,12 +272,12 @@ QUnit.test("messaging menu widget: mark as read on thread preview", async functi }]; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.hasClass(messagingMenu.$el,'o_mail_systray_item', 'should be the instance of widget'); @@ -335,14 +335,14 @@ QUnit.test('needaction messages in channels should appear, in addition to channe this.data['mail.message'].records = [needactionMessage, lastMessage]; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: partnerID, }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); @@ -391,14 +391,15 @@ QUnit.test('preview of message on a document + mark as read', async function (as this.data['mail.message'].records.push(needactionMessage); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: partnerID, }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); + await testUtils.nextTick(); assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1', "should display a counter of 1 on the messaging menu icon"); @@ -427,11 +428,11 @@ QUnit.test('update messaging preview on receiving a new message in channel previ assert.expect(8); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); @@ -478,11 +479,11 @@ QUnit.test('new message of type "notification" are not considered as unread mess assert.expect(8); const messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); // open messaging menu await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.containsOnce( @@ -580,7 +581,7 @@ QUnit.test('preview of inbox message not linked to document + mark as read', asy this.data['mail.message'].records.concat(needactionMessages); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { @@ -593,7 +594,9 @@ QUnit.test('preview of inbox message not linked to document + mark as read', asy return this._super.apply(this, arguments); }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); + await testUtils.nextTick(); + assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '2', "should display a counter of 2 on the messaging menu icon"); @@ -673,14 +676,14 @@ QUnit.test('grouped preview for needaction messages linked to same document', as this.data.initMessaging.needaction_inbox_counter = 2; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 44, }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); var $previews = messagingMenu.$('.o_mail_preview'); @@ -719,13 +722,13 @@ QUnit.test("messaging menu widget: channel seen notification", async function (a }; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 3 }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '1', @@ -767,13 +770,13 @@ QUnit.test("messaging menu widget: no traceback when receiving channel_fetched n }; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 3 }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.containsOnce(messagingMenu, '.o_new_message', "should have button to open blank thread window"); @@ -806,12 +809,12 @@ QUnit.test("messaging menu widget: preview with no message should be undated", a this.data['mail.message'].records[0].channel_ids = []; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 1, @@ -836,12 +839,12 @@ QUnit.test("messaging menu widget: sort dated previews before undated previews", this.data.initMessaging.channel_slots.direct_message = [dm]; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 2, @@ -924,16 +927,19 @@ QUnit.test('global counter with channel previews', async function (assert) { this.data['mail.message'].records = messages; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 3, }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); + await testUtils.nextTick(); + assert.strictEqual(messagingMenu.$('.o_notification_counter').text(), '2', "should display a counter of 2 on the messaging menu icon"); + await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.strictEqual(messagingMenu.$('.o_mail_preview').length, 3, @@ -965,7 +971,7 @@ QUnit.test('messaging menu widget: do not open chat window twice on preview clic var messageFetchDef = testUtils.makeTestPromise(); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 1 }, @@ -991,7 +997,7 @@ QUnit.test('messaging menu widget: do not open chat window twice on preview clic return this._super.apply(this, arguments); }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); // Opening chat window from messaging menu (pending from `messageFetchDef`) await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); @@ -1023,7 +1029,7 @@ QUnit.test('messaging menu widget: expand on thread preview', async function (as }); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 44 }, @@ -1036,7 +1042,7 @@ QUnit.test('messaging menu widget: expand on thread preview', async function (as }, }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); var $preview = messagingMenu.$('.o_mail_preview'); @@ -1062,7 +1068,7 @@ QUnit.test('messaging menu widget: click twice preview on slow message_fetch sho const messageFetchProm = testUtils.makeTestPromise(); const messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, session: { partner_id: 1 }, @@ -1086,7 +1092,7 @@ QUnit.test('messaging menu widget: click twice preview on slow message_fetch sho return this._super(...arguments); }, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); // Opening chat window 1st time from messaging menu (pending from `messageFetchDef`) await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); @@ -1113,11 +1119,11 @@ QUnit.test('no code injection in message body preview', async function (assert) `<p><script>throw new Error('CodeInjectionError');</script></p>`; const messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { services: this.services, data: this.data, }); - await messagingMenu.appendTo($('#qunit-fixture')); + await messagingMenu.appendTo(testUtils.prepareTarget()); await testUtils.dom.click(messagingMenu.$('.dropdown-toggle')); assert.containsOnce( messagingMenu, 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 e2d4af883bf..2494d639b29 100644 --- a/addons/mail_bot/static/tests/systray_messaging_menu_tests.js +++ b/addons/mail_bot/static/tests/systray_messaging_menu_tests.js @@ -70,7 +70,7 @@ QUnit.test('messaging menu widget: rendering with OdooBot has a request', async assert.expect(5); var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); @@ -99,7 +99,7 @@ QUnit.test('messaging menu widget: rendering without OdooBot has a request (deni window.Notification.permission = 'denied'; var messagingMenu = new MessagingMenu(); - testUtils.mock.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); @@ -122,7 +122,7 @@ QUnit.test('messaging menu widget: rendering without OdooBot has a request (acce window.Notification.permission = 'granted'; var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); @@ -143,7 +143,7 @@ QUnit.test('messaging menu widget: respond to notification prompt', async functi assert.expect(4); var messagingMenu = new MessagingMenu(); - testUtils.addMockEnvironment(messagingMenu, { + await testUtils.mock.addMockEnvironment(messagingMenu, { data: this.data, services: this.services, }); diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js index 6af38ce02de..2c987215d43 100644 --- a/addons/web/static/tests/chrome/action_manager_tests.js +++ b/addons/web/static/tests/chrome/action_manager_tests.js @@ -16,7 +16,9 @@ var ReportService = require('web.ReportService'); var SessionStorageService = require('web.SessionStorageService'); var testUtils = require('web.test_utils'); var Widget = require('web.Widget'); + var createActionManager = testUtils.createActionManager; +const cpHelpers = testUtils.controlPanel; QUnit.module('ActionManager', { beforeEach: function () { @@ -198,8 +200,9 @@ QUnit.module('ActionManager', { var n = delta; await actionManager.doAction(4); + // kanban view is loaded, switch to list view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); // open a record in form view await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); // go back to action 7 in breadcrumbs @@ -1336,12 +1339,13 @@ QUnit.module('ActionManager', { }, }); await actionManager.doAction(4); + // kanban view is loaded, switch to list view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); // here, list view is not ready yet, because def is not resolved // switch back to kanban view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); // here, we want the kanban view to reload itself, regardless of list view assert.verifySteps([ @@ -1607,8 +1611,8 @@ QUnit.module('ActionManager', { 'load_views', // action 3 '/web/dataset/search_read', // search read of list view of action 3 '/web/action/load', // action 4 - 'load_views', // action 4 'read', // read the opened record of action 3 (this request is blocked) + 'load_views', // action 4 '/web/dataset/search_read', // search read action 4 ]); @@ -1753,7 +1757,7 @@ QUnit.module('ActionManager', { // reload (the search_read RPC will be blocked) def = testUtils.makeTestPromise(); await testUtils.nextTick(); - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsN(actionManager, '.o_list_view .o_data_row', 5, "list view should still contain 5 records"); @@ -1822,11 +1826,11 @@ QUnit.module('ActionManager', { var ClientAction = AbstractAction.extend({ hasControlPanel: true, - start: function () { + start: async function () { this.$('.o_content').text('Hello World'); this.$el.addClass('o_client_action_test'); - this._setTitle('Hello'); - return this._super.apply(this, arguments); + this.controlPanelProps.title = 'Hello'; + await this._super.apply(this, arguments); }, }); core.action_registry.add('HelloWorldTest', ClientAction); @@ -1885,14 +1889,14 @@ QUnit.module('ActionManager', { hasControlPanel: true, events: { click: function () { - this._setTitle('new title'); + this.updateControlPanel({ title: 'new title' }); }, }, - start: function () { - this._setTitle('initial title'); + start: async function () { this.$('.o_content').text('Hello World'); this.$el.addClass('o_client_action_test'); - return this._super.apply(this, arguments); + this.controlPanelProps.title = 'initial title'; + await this._super.apply(this, arguments); }, }); var actionManager = await createActionManager(); @@ -1902,7 +1906,7 @@ QUnit.module('ActionManager', { assert.strictEqual($('ol.breadcrumb').text(), "initial title", "should have initial title as breadcrumb content"); - testUtils.dom.click(actionManager.$('.o_client_action_test')); + await testUtils.dom.click(actionManager.$('.o_client_action_test')); assert.strictEqual($('ol.breadcrumb').text(), "new title", "should have updated title as breadcrumb content"); @@ -2322,7 +2326,7 @@ QUnit.module('ActionManager', { }); QUnit.test('sidebar is present in list view', async function (assert) { - assert.expect(5); + assert.expect(4); var actionManager = await createActionManager({ actions: this.actions, @@ -2345,11 +2349,11 @@ QUnit.module('ActionManager', { }); await actionManager.doAction(3); - assert.isNotVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Print")')); - assert.isNotVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Action")')); + assert.containsNone(actionManager, '.o_cp_action_menus'); + await testUtils.dom.clickFirst(actionManager.$('input.custom-control-input')); - assert.isVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Print")')); - assert.isVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Action")')); + assert.isVisible(actionManager.$('.o_cp_action_menus button.o_dropdown_toggler_btn:contains("Print")')); + assert.isVisible(actionManager.$('.o_cp_action_menus button.o_dropdown_toggler_btn:contains("Action")')); actionManager.destroy(); }); @@ -2372,14 +2376,14 @@ QUnit.module('ActionManager', { "should display the list view"); // switch to kanban view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.containsNone(actionManager, '.o_list_view', "should no longer display the list view"); assert.containsOnce(actionManager, '.o_kanban_view', "should display the kanban view"); // switch back to list view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_list_view', "should display the list view"); assert.containsNone(actionManager, '.o_kanban_view', @@ -2486,7 +2490,7 @@ QUnit.module('ActionManager', { "breadcrumbs should display the display_name of the action"); // switch to kanban view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, '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', @@ -2508,7 +2512,7 @@ QUnit.module('ActionManager', { "breadcrumbs should display the display_name of the action"); // switch back to list view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, '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', @@ -2543,43 +2547,43 @@ QUnit.module('ActionManager', { }); await actionManager.doAction(3); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, + assert.containsN(actionManager, '.o_control_panel button.o_switch_view', 2, "should have two switch buttons (list and kanban)"); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1, + assert.containsOnce(actionManager, '.o_control_panel button.o_switch_view.active', "should have only one active button"); - assert.hasClass($('.o_control_panel .o_cp_switch_buttons button:first'),'o_cp_switch_list', + assert.hasClass($('.o_control_panel .o_switch_view:first'),'o_list', "list switch button should be the first one"); - assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', + assert.hasClass($('.o_control_panel .o_switch_view.o_list'), 'active', "list should be the active view"); // switch to kanban view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, + await cpHelpers.switchView(actionManager, 'kanban'); + assert.containsN(actionManager, '.o_control_panel .o_switch_view', 2, "should still have two switch buttons (list and kanban)"); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1, + assert.containsOnce(actionManager, '.o_control_panel .o_switch_view.active', "should still have only one active button"); - assert.hasClass($('.o_control_panel .o_cp_switch_buttons button:first'),'o_cp_switch_list', + assert.hasClass($('.o_control_panel .o_switch_view:first'), 'o_list', "list switch button should still be the first one"); - assert.hasClass($('.o_control_panel .o_cp_switch_kanban'),'active', + assert.hasClass($('.o_control_panel .o_switch_view.o_kanban'),'active', "kanban should now be the active view"); // switch back to list view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, + await cpHelpers.switchView(actionManager, 'list'); + assert.containsN(actionManager, '.o_control_panel .o_switch_view', 2, "should still have two switch buttons (list and kanban)"); - assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', + assert.hasClass($('.o_control_panel .o_switch_view.o_list'),'active', "list should now be the active view"); // open a record in form view await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first')); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 0, + assert.containsNone(actionManager, '.o_control_panel .o_switch_view', "should not have any switch buttons"); // go back to list view using the breadcrumbs await testUtils.dom.click($('.o_control_panel .breadcrumb a')); - assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2, + assert.containsN(actionManager, '.o_control_panel .o_switch_view', 2, "should have two switch buttons (list and kanban)"); - assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', + assert.hasClass($('.o_control_panel .o_switch_view.o_list'),'active', "list should be the active view"); actionManager.destroy(); @@ -2601,7 +2605,7 @@ QUnit.module('ActionManager', { "limit should be correct for kanban"); // switch to list view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, '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', @@ -2622,7 +2626,7 @@ QUnit.module('ActionManager', { "limit should be correct for list"); // switch back to kanban view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, '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', @@ -2646,12 +2650,12 @@ QUnit.module('ActionManager', { assert.containsN(actionManager, '.o_data_row', 5); // activate a domain - await testUtils.dom.click(actionManager.$('.o_search_options .o_filters_menu_button')); - await testUtils.dom.click(actionManager.$('.o_search_options .o_filters_menu a:contains(Bar)')); + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleMenuItem(actionManager, "Bar"); assert.containsN(actionManager, '.o_data_row', 2); // switch to kanban - await testUtils.dom.click(actionManager.$('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 2); // remove the domain @@ -2659,7 +2663,7 @@ QUnit.module('ActionManager', { assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 5); // switch back to list - await testUtils.dom.click(actionManager.$('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsN(actionManager, '.o_data_row', 5); actionManager.destroy(); @@ -2682,7 +2686,7 @@ QUnit.module('ActionManager', { // switch to kanban view def = testUtils.makeTestPromise(); - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.containsOnce(actionManager, '.o_list_view', "should still display the list view"); assert.containsNone(actionManager, '.o_kanban_view', @@ -2696,7 +2700,7 @@ QUnit.module('ActionManager', { // switch back to list view def = testUtils.makeTestPromise(); - await testUtils.dom.click($('.o_control_panel .o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_kanban_view', "should still display the kanban view"); assert.containsNone(actionManager, '.o_list_view', @@ -3044,11 +3048,11 @@ QUnit.module('ActionManager', { "line chart button is now active"); // switch to kanban and back to graph view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.strictEqual($('.o_control_panel .fa-area-chart').length, 0, "graph buttons are no longer in control panel"); - await testUtils.dom.click($('.o_control_panel .o_cp_switch_graph')); + await cpHelpers.switchView(actionManager, 'graph'); assert.hasClass($('.o_control_panel .fa-area-chart'),'active', "line chart button is still active"); actionManager.destroy(); @@ -3069,16 +3073,16 @@ QUnit.module('ActionManager', { }); await actionManager.doAction(3); - assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active', + assert.hasClass($('.o_control_panel .o_switch_view.o_list'),'active', "list button in control panel is active"); - assert.doesNotHaveClass($('.o_control_panel .o_cp_switch_graph'), 'active', + assert.doesNotHaveClass($('.o_control_panel .o_switch_view.o_graph'), 'active', "graph button in control panel is not active"); // switch to graph view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_graph')); - assert.doesNotHaveClass($('.o_control_panel .o_cp_switch_list'), 'active', + await cpHelpers.switchView(actionManager, 'graph'); + assert.doesNotHaveClass($('.o_control_panel .o_switch_view.o_list'), 'active', "list button in control panel is not active"); - assert.hasClass($('.o_control_panel .o_cp_switch_graph'),'active', + assert.hasClass($('.o_control_panel .o_switch_view.o_graph'),'active', "graph button in control panel is active"); actionManager.destroy(); }); @@ -3222,7 +3226,7 @@ QUnit.module('ActionManager', { "should only display 2 record"); // switch to kanban view - await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.strictEqual(actionManager.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2, "should only display 2 record"); @@ -3412,14 +3416,19 @@ QUnit.module('ActionManager', { actions: this.actions, archs: this.archs, data: this.data, - intercepts: { - create_filter: function (event) { - var filter = event.data.filter; - assert.deepEqual(filter.domain, `[("bar", "=", 1)]`, - "should save the correct domain"); - assert.deepEqual(filter.context, {shouldBeInFilterContext: true}, - "should save the correct context"); - }, + env: { + dataManager: { + create_filter: function (filter) { + assert.strictEqual(filter.domain, `[("bar", "=", 1)]`, + "should save the correct domain"); + const expectedContext = { + group_by: [], // default groupby is an empty list + shouldBeInFilterContext: true, + }; + assert.deepEqual(filter.context, expectedContext, + "should save the correct context"); + }, + } }, }); await actionManager.doAction(33); @@ -3428,16 +3437,16 @@ QUnit.module('ActionManager', { "should contain 5 records"); // filter on bar - await testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Filters)')); - await testUtils.dom.click($('.o_control_panel .o_filters_menu a:contains(Bar)')); + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleMenuItem(actionManager, "Bar"); assert.containsN(actionManager, '.o_data_row', 2); // save filter - await testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Favorites)')); - await testUtils.dom.click($('.o_control_panel .o_add_favorite')); - $('.o_control_panel .o_favorite_name input[type=text]').val('some name'); // name the filter - await testUtils.dom.click($('.o_control_panel .o_save_favorite button')); + await cpHelpers.toggleFavoriteMenu(actionManager); + await cpHelpers.toggleSaveFavorite(actionManager); + await cpHelpers.editFavoriteName(actionManager, "some name"); + await cpHelpers.saveFavorite(actionManager); testUtils.mock.unpatch(ListController); actionManager.destroy(); @@ -3460,29 +3469,23 @@ QUnit.module('ActionManager', { actions: this.actions, archs: this.archs, data: this.data, - intercepts: { - load_filters: function (ev) { - ev.data.on_success([ - { - user_id: [2, "Mitchell Admin"], - name: 'favorite filter', - id: 5, - context: {}, - sort: '[]', - domain: '[("bar", "=", 1)]' - } - ]); - }, - }, + favoriteFilters: [{ + user_id: [2, "Mitchell Admin"], + name: 'favorite filter', + id: 5, + context: {}, + sort: '[]', + domain: '[("bar", "=", 1)]' + }], }); - await actionManager.doAction(12); + assert.strictEqual(actionManager.$('.o_list_view tr.o_data_row .o_data_cell').text(), 'zoupyopplopgnapblip', 'record should be in descending order as default_order applies'); - // apply favorite filter - await testUtils.dom.click(actionManager.$('.o_favorites_menu_button')); - await testUtils.dom.click(actionManager.$('.o_menu_item a:contains("favorite filter")')); + await cpHelpers.toggleFavoriteMenu(actionManager); + await cpHelpers.toggleMenuItem(actionManager, "favorite filter"); + assert.strictEqual(actionManager.$('.o_control_panel .o_facet_values').text().trim(), 'favorite filter', 'favorite filter should be applied'); assert.strictEqual(actionManager.$('.o_list_view tr.o_data_row .o_data_cell').text(), 'gnapblip', @@ -3495,7 +3498,7 @@ QUnit.module('ActionManager', { 'order of records should not be changed, while coming back through breadcrumb'); // remove filter - await testUtils.dom.click(actionManager.$('.o_searchview .o_facet_remove')); + await cpHelpers.removeFacet(actionManager, 0); assert.strictEqual(actionManager.$('.o_list_view tr.o_data_row .o_data_cell').text(), 'zoupyopplopgnapblip', 'order of records should not be changed, after removing current filter'); @@ -3512,16 +3515,16 @@ QUnit.module('ActionManager', { }); await actionManager.doAction(1); - assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1, + assert.isVisible(actionManager.el.querySelector('.o_search_options .o_dropdown.o_filter_menu'), "the search options should be available"); await actionManager.doAction(3); - assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1, + assert.isVisible(actionManager.el.querySelector('.o_search_options .o_dropdown.o_filter_menu'), "the search options should be available"); // go back using the breadcrumbs await testUtils.dom.click($('.o_control_panel .breadcrumb a:first')); - assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1, + assert.isVisible(actionManager.el.querySelector('.o_search_options .o_dropdown.o_filter_menu'), "the search options should be available"); actionManager.destroy(); @@ -3772,11 +3775,11 @@ QUnit.module('ActionManager', { }); await actionManager.doAction(5); - assert.strictEqual($('.o_technical_modal .modal-body button.infooter').length, 0, + assert.containsNone($('.o_technical_modal .modal-body'), 'button.infooter', "the button should not be in the body"); - assert.strictEqual($('.o_technical_modal .modal-footer button.infooter').length, 1, + assert.containsOnce($('.o_technical_modal .modal-footer'), 'button.infooter', "the button should be in the footer"); - assert.strictEqual($('.o_technical_modal .modal-footer button').length, 1, + assert.containsOnce($('.o_technical_modal .modal-footer'), 'button', "the modal footer should only contain one button"); actionManager.destroy(); @@ -4235,7 +4238,7 @@ QUnit.module('ActionManager', { <t t-name="kanban-box"> <div class="oe_kanban_global_click"> <field name="display_name"/> - <button + <button name="1" string="Execute action" type="action" @@ -4294,28 +4297,21 @@ QUnit.module('ActionManager', { return this._super.apply(this, arguments); }, }); - await actionManager.doAction(3); - var $searchInput = $('.o_searchview input'); - $searchInput.val('m'); // the searchbar checks the contents of the input on keypress events - await testUtils.fields.triggerKey('press', $searchInput, 'm'); - await testUtils.fields.triggerKeydown($searchInput, 'enter'); + await cpHelpers.editSearch(actionManager, "m"); + await cpHelpers.validateSearch(actionManager); - assert.verifySteps(["search_read ", - "search_read foo,ilike,m"]); + assert.verifySteps(["search_read ", "search_read foo,ilike,m"]); // Triggering the do_search above will kill the current searchview Input - $searchInput = $('.o_searchview input'); - $searchInput.val('o'); // the searchbar checks the contents of the input on keypress events - await testUtils.fields.triggerKey('press', $searchInput, 'o'); + await cpHelpers.editSearch(actionManager, "o"); // We have something in the input of the search view. Making the search_read // return at this point will trigger the redraw of the view. // However we want to hold on to what we just typed searchPromise.resolve(); - await testUtils.nextTick(); - await testUtils.fields.triggerKeydown($searchInput, 'enter'); + await cpHelpers.validateSearch(actionManager); assert.verifySteps(["search_read |,foo,ilike,m,foo,ilike,o"]); diff --git a/addons/web/static/tests/chrome/pager_tests.js b/addons/web/static/tests/chrome/pager_tests.js deleted file mode 100644 index 18a4ae7fc37..00000000000 --- a/addons/web/static/tests/chrome/pager_tests.js +++ /dev/null @@ -1,93 +0,0 @@ -odoo.define('web.pager_tests', function (require) { -"use strict"; - -var Pager = require('web.Pager'); -var concurrency = require('web.concurrency'); -var testUtils = require('web.test_utils'); - -QUnit.module('chrome', {}, function () { - - QUnit.module('Pager'); - - QUnit.test('basic stuff', async function (assert) { - assert.expect(2); - - var pager = new Pager(null, 10, 1, 4); - pager.appendTo($('#qunit-fixture')); - await testUtils.nextTick(); - - assert.strictEqual(pager.state.current_min, 1, - "current_min should be set to 1"); - - // click on next - await testUtils.dom.click(pager.$('.o_pager_next')); - assert.strictEqual(pager.state.current_min, 5, - "current_min should now be 5"); - - pager.destroy(); - }); - - QUnit.test('edit the pager', async function (assert) { - assert.expect(5); - - var pager = new Pager(null, 10, 1, 4); - pager.appendTo($('#qunit-fixture')); - await testUtils.nextTick(); - - // enter edition - await 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"); - - // change the limit - await testUtils.fields.editInput(pager.$('input'), '1-6'); - await testUtils.fields.triggerKeydown(pager.$('input'), 'enter'); - assert.strictEqual(pager.state.limit, 6, - "the limit should have been updated"); - assert.strictEqual(pager.state.current_min, 1, - "the current_min should not have changed"); - assert.strictEqual(pager.$('.o_pager_value').text(), '1-6', - "the input should have correct value"); - - pager.destroy(); - }); - - QUnit.test('disabling the pager', async function (assert) { - assert.expect(4); - - var pager = new Pager(null, 10, 1, 4); - pager.appendTo($('#qunit-fixture')); - await testUtils.nextTick(); - await pager.disable(); - - // try to go to the next or previous pages - await testUtils.dom.click(pager.$('.o_pager_next')); - assert.strictEqual(pager.state.current_min, 1, - "current_min should still be 1"); - await 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 - await 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 - // re-enable it once they have been loaded - // the following emulates this situation - pager.on('pager_changed', null, function () { - pager.disable(); - concurrency.delay(0).then(function () { - assert.ok(pager.disabled, "pager should still be disabled"); - pager.destroy(); - }); - }); - pager.enable(); - await testUtils.dom.click(pager.$('.o_pager_next')); - }); -}); - -}); diff --git a/addons/web/static/tests/components/custom_file_input_tests.js b/addons/web/static/tests/components/custom_file_input_tests.js index 0131213f6e9..279bf67f11b 100644 --- a/addons/web/static/tests/components/custom_file_input_tests.js +++ b/addons/web/static/tests/components/custom_file_input_tests.js @@ -2,102 +2,89 @@ odoo.define('web.custom_file_input_tests', function (require) { "use strict"; const CustomFileInput = require('web.CustomFileInput'); - const makeTestEnvironment = require('web.test_env'); const testUtils = require('web.test_utils'); - const { Component, tags, useState } = owl; - const { xml } = tags; + const { createComponent } = testUtils; QUnit.module('Components', {}, function () { // This module cannot be tested as thoroughly as we want it to be: // browsers do not let scripts programmatically assign values to inputs // of type file - QUnit.module('CustomFileInput', {}, function () { - QUnit.test("Rendering of all props", async function (assert) { - assert.expect(12); - - class Parent extends Component { - constructor() { - super(...arguments); - this.state = useState({ innerContent: '<a href="#">Trigger</a>' }); - } - // Handlers - _onFileUploaded(ev) { - assert.strictEqual(ev.detail.files.length, 0, - "'files' property should be an empty array"); - } - } - Parent.components = { CustomFileInput }; - Parent.env = makeTestEnvironment({ + QUnit.module('CustomFileInput'); + + QUnit.test("Upload a file: default props", async function (assert) { + assert.expect(6); + + const customFileInput = await createComponent(CustomFileInput, { + env: { + services: { + async httpRequest(route, params) { + assert.deepEqual(params, { + csrf_token: odoo.csrf_token, + ufile: [], + }); + assert.step(route); + return '[]'; + }, + }, + }, + }); + const input = customFileInput.el.querySelector('input'); + + assert.strictEqual(customFileInput.el.innerText.trim().toUpperCase(), "CHOOSE FILE", + "File input total text should match its given inner element's text"); + assert.strictEqual(input.accept, '*', + "Input should accept all files by default"); + + await testUtils.dom.triggerEvent(input, 'change'); + + assert.notOk(input.multiple, "'multiple' attribute should not be set"); + assert.verifySteps(['/web/binary/upload']); + + customFileInput.destroy(); + }); + + QUnit.test("Upload a file: custom attachment", async function (assert) { + assert.expect(6); + + const customFileInput = await createComponent(CustomFileInput, { + env: { services: { - httpRequest: (route, params) => { - if (route === '/web/binary/upload') { - assert.deepEqual(params, { - csrf_token: odoo.csrf_token, - ufile: [], - }); - assert.step(route); - return Promise.resolve('[]'); - } else if (route === '/web/binary/upload_attachment') { - assert.deepEqual(params, { - id: 5, - model: 'res.model', - csrf_token: odoo.csrf_token, - ufile: [], - }); - assert.step(route); - return Promise.resolve('[]'); - } + async httpRequest(route, params) { + assert.deepEqual(params, { + id: 5, + model: 'res.model', + csrf_token: odoo.csrf_token, + ufile: [], + }); + assert.step(route); + return '[]'; }, }, - }); - Parent.template = xml` - <CustomFileInput - accepted_file_extensions="state.accepted_file_extensions" - action="state.action" - id="state.id" - model="state.model" - multi_upload="state.multi_upload" - t-on-uploaded="_onFileUploaded" - > - <t t-raw="state.innerContent"/> - </CustomFileInput>`; - - const parent = new Parent(); - await parent.mount(testUtils.prepareTarget()); - const fileInput = parent.el; - const input = fileInput.querySelector('input'); - - // Default props - assert.strictEqual(fileInput.innerText.trim(), "Trigger", - "File input total text should match its given inner element's text"); - assert.strictEqual(input.accept, '*', - "Input should accept all files by default"); - await testUtils.dom.triggerEvent(input, 'change'); - assert.notOk(input.multiple, - "'multiple' attribute should not be set"); - - // Change props - Object.assign(parent.state, { + }, + props: { accepted_file_extensions: '.png', action: '/web/binary/upload_attachment', id: 5, model: 'res.model', multi_upload: true, - }); - await testUtils.nextTick(); + }, + intercepts: { + 'uploaded': ev => assert.strictEqual(ev.detail.files.length, 0, + "'files' property should be an empty array"), + }, + }); + const input = customFileInput.el.querySelector('input'); - assert.strictEqual(input.accept, '.png', - "Input should now only accept pngs"); - await testUtils.dom.triggerEvent(input, 'change'); - assert.ok(input.multiple, - "'multiple' attribute should be set"); + assert.strictEqual(input.accept, '.png', "Input should now only accept pngs"); - assert.verifySteps(['/web/binary/upload', '/web/binary/upload_attachment']); + await testUtils.dom.triggerEvent(input, 'change'); - parent.destroy(); - }); + assert.ok(input.multiple, "'multiple' attribute should be set"); + assert.verifySteps(['/web/binary/upload_attachment']); + + customFileInput.destroy(); }); }); }); diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js index ada71b91429..eaa41651c20 100644 --- a/addons/web/static/tests/fields/basic_fields_tests.js +++ b/addons/web/static/tests/fields/basic_fields_tests.js @@ -19,6 +19,10 @@ var DebouncedField = basicFields.DebouncedField; var JournalDashboardGraph = basicFields.JournalDashboardGraph; var _t = core._t; +// Base64 images for testing purpose +const MY_IMAGE = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='; +const PRODUCT_IMAGE = 'R0lGODlhDAAMAKIFAF5LAP/zxAAAANyuAP/gaP///wAAAAAAACH5BAEAAAUALAAAAAAMAAwAAAMlWLPcGjDKFYi9lxKBOaGcF35DhWHamZUW0K4mAbiwWtuf0uxFAgA7'; + QUnit.module('fields', {}, function () { QUnit.module('basic_fields', { @@ -2516,7 +2520,7 @@ QUnit.module('basic_fields', { assert.expect(7); this.data.partner.records[0].__last_update = '2017-02-08 10:00:00'; - this.data.partner.records[0].document = 'myimage'; + this.data.partner.records[0].document = MY_IMAGE; var form = await createView({ View: FormView, @@ -2526,13 +2530,13 @@ QUnit.module('basic_fields', { '<field name="document" widget="image" options="{\'size\': [90, 90]}"/> ' + '</form>', res_id: 1, - mockRPC: function (route, args) { + async mockRPC(route, args) { if (route === '/web/dataset/call_kw/partner/read') { assert.deepEqual(args.args[1], ['document', '__last_update', 'display_name'], "The fields document, display_name and __last_update should be present when reading an image"); } - if (route === 'data:image/png;base64,myimage') { + if (route === `data:image/png;base64,${MY_IMAGE}`) { assert.ok(true, "should called the correct route"); - return Promise.resolve('wow'); + return 'wow'; } return this._super.apply(this, arguments); }, @@ -2551,6 +2555,59 @@ QUnit.module('basic_fields', { form.destroy(); }); + QUnit.test('image fields are correctly replaced when given an incorrect value', async function (assert) { + assert.expect(7); + + this.data.partner.records[0].__last_update = '2017-02-08 10:00:00'; + this.data.partner.records[0].document = 'incorrect_base64_value'; + + testUtils.mock.patch(basicFields.FieldBinaryImage, { + // Delay the _render function: this will ensure that the error triggered + // by the incorrect base64 value is dispatched before the src is replaced + // (see test_utils_mock.removeSrcAttribute), since that function is called + // when the element is inserted into the DOM. + async _render() { + const result = this._super.apply(this, arguments); + await concurrency.delay(100); + return result; + }, + }); + + const form = await createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: ` + <form string="Partners"> + <field name="document" widget="image" options="{'size': [90, 90]}"/> + </form>`, + res_id: 1, + async mockRPC(route, args) { + const _super = this._super; + if (route === '/web/static/src/img/placeholder.png') { + assert.step('call placeholder route'); + } + return _super.apply(this, arguments); + }, + }); + + assert.hasClass(form.$('div[name="document"]'),'o_field_image', + "the widget should have the correct class"); + assert.containsOnce(form, 'div[name="document"] > img', + "the widget should contain an image"); + assert.hasClass(form.$('div[name="document"] > img'), 'img-fluid', + "the image should have the correct class"); + 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"); + + assert.verifySteps(['call placeholder route']); + + form.destroy(); + testUtils.mock.unpatch(basicFields.FieldBinaryImage); + }); + QUnit.test('image: option accepted_file_extensions', async function (assert) { assert.expect(2); @@ -2583,9 +2640,9 @@ QUnit.module('basic_fields', { assert.expect(6); this.data.partner.records[0].__last_update = '2017-02-08 10:00:00'; - this.data.partner.records[0].document = 'myimage'; + this.data.partner.records[0].document = MY_IMAGE; this.data.partner_type.fields.image = {name: 'image', type: 'binary'}; - this.data.partner_type.records[0].image = 'product_image'; + this.data.partner_type.records[0].image = PRODUCT_IMAGE; this.data.partner.records[0].timmy = [12]; var form = await createView({ @@ -2604,14 +2661,14 @@ QUnit.module('basic_fields', { '</field>' + '</form>', res_id: 1, - mockRPC: function (route) { - if (route === 'data:image/png;base64,myimage') { + async mockRPC(route) { + if (route === `data:image/png;base64,${MY_IMAGE}`) { assert.step("The view's image should have been fetched"); - return Promise.resolve('wow'); + return 'wow'; } - if (route === 'data:image/png;base64,product_image') { + if (route === `data:image/gif;base64,${PRODUCT_IMAGE}`) { assert.step("The dialog's image should have been fetched"); - return Promise.resolve(); + return; } return this._super.apply(this, arguments); }, @@ -2634,7 +2691,7 @@ QUnit.module('basic_fields', { assert.expect(2); this.data.partner_type.fields.image = {name: 'image', type: 'binary'}; - this.data.partner_type.records[0].image = 'product_image'; + this.data.partner_type.records[0].image = PRODUCT_IMAGE; this.data.partner.records[0].timmy = [12]; var form = await createView({ @@ -2649,10 +2706,10 @@ QUnit.module('basic_fields', { '</field>' + '</form>', res_id: 1, - mockRPC: function (route) { - if (route === 'data:image/png;base64,product_image') { + async mockRPC(route) { + if (route === `data:image/gif;base64,${PRODUCT_IMAGE}`) { assert.ok(true, "The list's image should have been fetched"); - return Promise.resolve(); + return; } return this._super.apply(this, arguments); }, @@ -2961,7 +3018,7 @@ QUnit.module('basic_fields', { QUnit.module('FieldDateRange'); - QUnit.test('Datetime field', async function (assert) { + QUnit.test('Datetime field [REQUIRE FOCUS]', async function (assert) { assert.expect(20); this.data.partner.fields.datetime_end = {string: 'Datetime End', type: 'datetime'}; @@ -3039,7 +3096,7 @@ QUnit.module('basic_fields', { form.destroy(); }); - QUnit.test('Date field', async function (assert) { + QUnit.test('Date field [REQUIRE FOCUS]', async function (assert) { assert.expect(18); this.data.partner.fields.date_end = {string: 'Date End', type: 'date'}; 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 a1c306a432c..47fe687d773 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 @@ -3,6 +3,8 @@ odoo.define('web.field_many_to_many_tests', function (require) { var FormView = require('web.FormView'); var testUtils = require('web.test_utils'); + +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; QUnit.module('fields', {}, function () { @@ -1003,8 +1005,8 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('.modal .o_data_row').length, 1, "should contain only one row (gold)"); - await testUtils.fields.triggerKey('press', $('.modal .o_searchview_input'), 's'); - await testUtils.fields.triggerKeydown($('.modal .o_searchview_input'), 'enter'); + await cpHelpers.editSearch('.modal', 's'); + await cpHelpers.validateSearch('.modal'); assert.strictEqual($('.modal .o_data_row').length, 0, "should contain no row"); 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 21d74bf0d99..04c934290a1 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 @@ -9,6 +9,7 @@ var StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin'); var testUtils = require('web.test_utils'); var Widget = require('web.Widget'); +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; QUnit.module('fields', {}, function () { @@ -244,11 +245,11 @@ QUnit.module('fields', {}, function () { // save form await testUtils.form.clickSave(form); // click next on pager - await testUtils.dom.click(form.pager.$('.o_pager_next')); + await testUtils.dom.click(form.el.querySelector('.o_pager .o_pager_next')); // this checks that the view did not ask for confirmation that the // record is dirty - assert.strictEqual(form.pager.$el.text().trim(), '2 / 2', + assert.strictEqual(form.el.querySelector('.o_pager').innerText.trim(), '2 / 2', 'pager should be at second page'); form.destroy(); }); @@ -316,11 +317,11 @@ QUnit.module('fields', {}, function () { // save form await testUtils.form.clickSave(form); // click next on pager - await testUtils.dom.click(form.pager.$('.o_pager_next')); + await testUtils.dom.click(form.el.querySelector('.o_pager .o_pager_next')); // this checks that the view did not ask for confirmation that the // record is dirty - assert.strictEqual(form.pager.$el.text().trim(), '2 / 2', + assert.strictEqual(form.el.querySelector('.o_pager').innerText.trim(), '2 / 2', 'pager should be at second page'); form.destroy(); }); @@ -506,11 +507,11 @@ QUnit.module('fields', {}, function () { assert.strictEqual($('tr.o_data_row').length, 9, "should display 9 records"); - await testUtils.dom.click($('button:contains(Filters)')); - await testUtils.dom.click($('.o_add_custom_filter:visible')); - assert.strictEqual($('.o_filter_condition select.o_searchview_extended_prop_field').val(), 'datetime', + await cpHelpers.toggleFilterMenu('.modal'); + await cpHelpers.toggleAddCustomFilter('.modal'); + assert.strictEqual(document.querySelector('.modal .o_generator_menu_field').value, 'datetime', "datetime field should be selected"); - await testUtils.dom.click($('.o_apply_filter')); + await cpHelpers.applyFilter('.modal'); assert.strictEqual($('tr.o_data_row').length, 0, "should display 0 records"); form.destroy(); @@ -592,7 +593,6 @@ QUnit.module('fields', {}, function () { assert.containsNone(document.body, '.modal', "No save should be triggered when removing value"); - await testUtils.fields.many2one.clickOpenDropdown('trululu'); await testUtils.fields.many2one.clickHighlightedItem('trululu'); assert.containsOnce(document.body, '.modal', @@ -741,8 +741,8 @@ QUnit.module('fields', {}, function () { assert.ok(!$('.modal .modal-footer .o_select_button').length, "there should be no 'Select' button in the footer"); assert.ok($('.modal tbody tr').length > 10, "list should contain more than 10 records"); - await testUtils.fields.triggerKey('press', $('.modal .o_searchview_input'), 'P'), - await testUtils.fields.triggerKeydown($('.modal .o_searchview_input'), 'enter'); + await cpHelpers.editSearch('.modal', "P"); + await cpHelpers.validateSearch('.modal'); assert.strictEqual($('.modal tbody tr').length, 10, "list should be restricted to records containing a P (10 records)"); // choose a record 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 e24341b1019..e93dc2f39ca 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 @@ -12,6 +12,7 @@ var relationalFields = require('web.relational_fields'); var testUtils = require('web.test_utils'); var fieldUtils = require('web.field_utils'); +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; QUnit.module('fields', {}, function () { @@ -1505,7 +1506,7 @@ QUnit.module('fields', {}, function () { "second dialog should be closed"); assert.strictEqual($('.modal .o_data_row').length, 1, "there should be one record in the one2many in the dialog"); - assert.notOk($('.modal .o_x2m_control_panel .o_cp_pager div').is(':visible'), + assert.containsNone($('.modal'), '.o_x2m_control_panel .o_pager', 'm2m pager should be hidden'); // click on 'Save & Close' @@ -1756,16 +1757,14 @@ QUnit.module('fields', {}, function () { // move to record 2, which has 3 related records (and shouldn't contain the // related records of record 1 anymore). Two additional RPCs should have // been done - form.pager.next(); - await testUtils.nextTick(); + await cpHelpers.pagerNext(form); assert.strictEqual(count, 4, 'two RPCs should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 3, 'one2many kanban should contain 3 cards for record 2'); // move back to record 1, which should contain again its first 40 related // records - form.pager.previous(); - await testUtils.nextTick(); + await cpHelpers.pagerPrevious(form); assert.strictEqual(count, 6, 'two RPCs should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40, 'one2many kanban should contain 40 cards for record 1'); @@ -1778,16 +1777,14 @@ QUnit.module('fields', {}, function () { 'one2many kanban should contain 2 cards for record 1 at page 2'); // move to record 2 again and check that everything is correctly updated - form.pager.next(); - await testUtils.nextTick(); + await cpHelpers.pagerNext(form); assert.strictEqual(count, 9, 'two RPCs should have been done'); assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 3, 'one2many kanban should contain 3 cards for record 2'); // move back to record 1 and move to page 2 again: all data should have // been correctly reloaded - form.pager.previous(); - await testUtils.nextTick(); + await cpHelpers.pagerPrevious(form); assert.strictEqual(count, 11, 'two RPCs should have been done'); await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next')); assert.strictEqual(count, 12, 'one RPC should have been done'); @@ -2565,7 +2562,7 @@ QUnit.module('fields', {}, function () { await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); await testUtils.dom.click(form.$el); - assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 5', + assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 5', "pager should display the correct total"); form.destroy(); }); @@ -2898,7 +2895,7 @@ QUnit.module('fields', {}, function () { await testUtils.form.clickEdit(form); await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a')); // the record currently being added should not count in the pager - assert.isNotVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager')); + assert.containsNone(form, '.o_field_widget[name=turtles] .o_pager'); form.destroy(); }); @@ -2931,8 +2928,8 @@ QUnit.module('fields', {}, function () { // confirm the discard operation await testUtils.dom.click($('.modal .modal-footer .btn-primary')); - assert.isVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager')); - assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4', + assert.isVisible(form.$('.o_field_widget[name=turtles] .o_pager')); + assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 4', "pager should display correct values"); form.destroy(); @@ -3001,13 +2998,13 @@ QUnit.module('fields', {}, function () { // see a confirm dialog await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next')); - assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4', + assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 4', "pager should still display the correct total"); // click on cancel await testUtils.dom.click($('.modal .modal-footer .btn-secondary')); - assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4', + assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_pager').text().trim(), '1-3 / 4', "pager should again display the correct total"); assert.containsOnce(form, '.o_field_one2many input.o_field_invalid', "there should be an invalid input in the one2many"); @@ -3048,7 +3045,7 @@ QUnit.module('fields', {}, function () { await testUtils.dom.click($('.modal .modal-footer .btn-primary')); assert.containsOnce(form, 'tr.o_data_row'); - assert.isNotVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager')); + assert.containsNone(form, '.o_field_widget[name=turtles] .o_pager'); form.destroy(); }); @@ -3911,14 +3908,14 @@ QUnit.module('fields', {}, function () { '</form>', }); - assert.ok(!form.$('.o_x2m_control_panel .o_cp_pager div').is(':visible'), + assert.containsNone(form, '.o_x2m_control_panel .o_pager', 'o2m pager should be hidden'); // click to create a subrecord await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a')); assert.containsOnce(form, 'tr.o_data_row'); - assert.ok(!form.$('.o_x2m_control_panel .o_cp_pager div').is(':visible'), + assert.containsNone(form, '.o_x2m_control_panel .o_pager', 'o2m pager should be hidden'); 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 11d67bd3752..47703a4ce1f 100644 --- a/addons/web/static/tests/fields/relational_fields_tests.js +++ b/addons/web/static/tests/fields/relational_fields_tests.js @@ -8,6 +8,7 @@ var RamStorage = require('web.RamStorage'); var relationalFields = require('web.relational_fields'); var testUtils = require('web.test_utils'); +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; QUnit.module('fields', {}, function () { @@ -153,24 +154,10 @@ QUnit.module('relational_fields', { QUnit.test('search more pager is reset when doing a new search', async function (assert) { assert.expect(6); - for(var i = 10; i < 180; i++) { - this.data.partner.records.push({ - id: i, - display_name: "Partner " + i, - }); - } - - async function stringToEvent ($element, string) { - for (var i = 0; i < string.length; i++) { - var keyAscii = string.charCodeAt(i); - $element.val($element.val()+string[i]); - $element.trigger($.Event('keyup', {which: keyAscii, keyCode:keyAscii})); - await testUtils.nextTick(); - } - $element.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER, keyCode:$.ui.keyCode.ENTER})); - await testUtils.nextTick(); - } + this.data.partner.records.push( + ...new Array(170).fill().map((_, i) => ({ id: i + 10, name: "Partner " + i })) + ); this.data.partner.fields.datetime.searchable = true; var form = await createView({ View: FormView, @@ -192,7 +179,6 @@ QUnit.module('relational_fields', { await testUtils.form.clickEdit(form); - await testUtils.fields.many2one.clickOpenDropdown('trululu'); await testUtils.fields.many2one.clickItem('trululu','Search'); await testUtils.dom.click($('.modal .o_pager_next')); @@ -201,7 +187,8 @@ QUnit.module('relational_fields', { assert.strictEqual($('.o_pager_value').text(), "181-160", "should display the second page"); assert.strictEqual($('tr.o_data_row').length, 80, "should display 80 record"); - await stringToEvent($('.modal .o_searchview_input'), 'first'); + await cpHelpers.editSearch('.modal', "first"); + await cpHelpers.validateSearch('.modal'); assert.strictEqual($('.o_pager_limit').text(), "11", "there should be 1 record"); assert.strictEqual($('.o_pager_value').text(), "11-1", "should display the first page"); @@ -1708,8 +1695,8 @@ QUnit.module('relational_fields', { }); await testUtils.fields.many2one.clickOpenDropdown('trululu'); await testUtils.fields.many2one.clickItem('trululu', 'Search'); - await testUtils.dom.click($('.modal .o_search_options .fa-bars')); - await testUtils.dom.click($('.modal .o_search_options .o_group_by_menu a:contains(Bar)')); + await cpHelpers.toggleGroupByMenu('.modal'); + await cpHelpers.toggleMenuItem('.modal', "Bar"); await testUtils.dom.click($('.modal .o_group_header:first')); @@ -1977,7 +1964,7 @@ QUnit.module('relational_fields', { await testUtils.form.clickSave(form); - assert.strictEqual(form.el.querySelector('.o_field_many2manytags').innerText, 'new value'); + assert.strictEqual(form.el.querySelector('.o_field_many2manytags').innerText.trim(), "new value"); form.destroy(); }); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index a58c857d49e..5865d4be80b 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -305,6 +305,8 @@ QUnit.module('Views', { }); await actionManager.doAction(1); + await testUtils.nextTick(); + // displays month mode by default assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Meetings Test (Dec 11 – 17, 2016)', "should display the current week"); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index 52e2e3354c5..00a73d9a6fd 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -16,6 +16,7 @@ var widgetRegistry = require('web.widget_registry'); var Widget = require('web.Widget'); var _t = core._t; +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; var createActionManager = testUtils.createActionManager; @@ -213,7 +214,7 @@ QUnit.module('Views', { bar: true, foo: "blip", int_field: 9, - }) + }); var form = await createView({ View: FormView, viewOptions: { mode: 'edit' }, @@ -249,7 +250,7 @@ QUnit.module('Views', { this.data.partner.records.push({ id: 6, p: [1], - }) + }); var form = await createView({ View: FormView, viewOptions: { mode: 'edit' }, @@ -1858,7 +1859,7 @@ QUnit.module('Views', { form.destroy(); }); - QUnit.test('sidebar is hidden when switching to edit mode', async function (assert) { + QUnit.test('toolbar is hidden when switching to edit mode', async function (assert) { assert.expect(3); var form = await createView({ @@ -1870,15 +1871,19 @@ QUnit.module('Views', { '<field name="foo"/>' + '</sheet>' + '</form>', - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, res_id: 1, }); - assert.isVisible(form.sidebar); + assert.containsOnce(form, '.o_cp_action_menus'); + await testUtils.form.clickEdit(form); - assert.isNotVisible(form.sidebar); + + assert.containsNone(form, '.o_cp_action_menus'); + await testUtils.form.clickDiscard(form); - assert.isVisible(form.sidebar); + + assert.containsOnce(form, '.o_cp_action_menus'); form.destroy(); }); @@ -2013,14 +2018,14 @@ QUnit.module('Views', { '<field name="foo"/>' + '</form>', res_id: 1, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, }); assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'first record', "should have the display name of the record as title"); - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Duplicate"); assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'first record (copy)', "should have duplicated the record"); @@ -2040,7 +2045,7 @@ QUnit.module('Views', { '<field name="foo"/>' + '</form>', res_id: 1, - viewOptions: {hasSidebar: true, context: {hey: 'hoy'}}, + viewOptions: {hasActionMenus: true, context: {hey: 'hoy'}}, mockRPC: function (route, args) { if (args.method === 'read') { // should have 2 read, one for initial load, second for @@ -2052,8 +2057,8 @@ QUnit.module('Views', { }, }); - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Duplicate"); form.destroy(); }); @@ -2069,12 +2074,12 @@ QUnit.module('Views', { '<field name="foo"/>' + '</form>', res_id: 1, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, }); assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'first record', "should have the display name of the record as title"); - assert.containsNone(form.sidebar, 'a:contains(Duplicate)', + assert.containsNone(form, '.o_cp_action_menus a:contains(Duplicate)', "should not contains a 'Duplicate' action"); form.destroy(); }); @@ -2603,14 +2608,14 @@ QUnit.module('Views', { data: this.data, arch: '<form string="Partners"><field name="foo"></field></form>', res_id: 1, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, }); await testUtils.form.clickEdit(form); await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala'); await testUtils.form.clickSave(form); - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Duplicate"); assert.strictEqual(form.$('input[name=foo]').val(), 'tralala', 'input should contain ABC'); @@ -2643,8 +2648,8 @@ QUnit.module('Views', { }, }); - assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should be 1"); - assert.strictEqual(form.$('.o_pager_limit').text(), '2', "pager limit should be 2"); + assert.strictEqual(cpHelpers.getPagerValue(form), '1', "pager value should be 1"); + assert.strictEqual(cpHelpers.getPagerSize(form), '2', "pager limit should be 2"); // switch to edit mode await testUtils.form.clickEdit(form); @@ -2655,19 +2660,19 @@ QUnit.module('Views', { 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 - await testUtils.dom.click('.o_pager_next'); // click on next + await cpHelpers.pagerNext(form); assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed"); await testUtils.dom.click('.modal-footer .btn-secondary'); // click on cancel assert.strictEqual(form.$('input[name=foo]').val(), 'new value', "input should still contain new value"); - assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should still be 1"); + assert.strictEqual(cpHelpers.getPagerValue(form), '1', "pager value should still be 1"); // click on the pager to switch to the next record and confirm - await testUtils.dom.click('.o_pager_next'); // click on next + await cpHelpers.pagerNext(form); assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed"); await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm assert.strictEqual(form.$('input[name=foo]').val(), 'blip', "input should contain blip"); - assert.strictEqual(form.$('.o_pager_value').text(), '2', "pager value should be 2"); + assert.strictEqual(cpHelpers.getPagerValue(form), '2', "pager value should be 2"); assert.strictEqual(nbWrite, 0, 'no write RPC should have been done'); form.destroy(); @@ -2690,7 +2695,8 @@ QUnit.module('Views', { }, res_id: 1, }); - assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should be 1"); + + assert.strictEqual(cpHelpers.getPagerValue(form), '1', "pager value should be 1"); // switch to edit mode await testUtils.form.clickEdit(form); @@ -2704,10 +2710,10 @@ QUnit.module('Views', { await testUtils.form.clickSave(form); // click on the pager to switch to the next record and cancel the confirm request - await testUtils.dom.click('.o_pager_next'); // click on next + await cpHelpers.pagerNext(form); assert.containsNone(document.body, '.modal:visible', "no confirm modal should be displayed"); - assert.strictEqual(form.$('.o_pager_value').text(), '2', "pager value should be 2"); + assert.strictEqual(cpHelpers.getPagerValue(form), '2', "pager value should be 2"); assert.containsN(form, '.o_priority .fa-star-o', 2, 'priority widget should have been rendered with correct value'); @@ -2717,10 +2723,10 @@ QUnit.module('Views', { assert.containsOnce(form, '.o_priority .fa-star', 'priority widget should have been updated'); - await testUtils.dom.click('.o_pager_next'); // click on next - assert.containsNone(document.body, '.modal:visible', + await cpHelpers.pagerNext(form); + assert.containsNone(document.body, '.modal:visible', "no confirm modal should be displayed"); - assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should be 1"); + assert.strictEqual(cpHelpers.getPagerValue(form), '1', "pager value should be 1"); // switch to edit mode await testUtils.form.clickEdit(form); @@ -2733,8 +2739,8 @@ QUnit.module('Views', { await testUtils.form.clickDiscard(form); assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed"); await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm - await testUtils.dom.click('.o_pager_next'); // click on next - assert.strictEqual(form.$('.o_pager_value').text(), '2', "pager value should be 2"); + await cpHelpers.pagerNext(form); + assert.strictEqual(cpHelpers.getPagerValue(form), '2', "pager value should be 2"); form.destroy(); }); @@ -2769,7 +2775,7 @@ QUnit.module('Views', { assert.hasClass(form.$('.o_notebook .nav-link:eq(1)'), 'active'); // click on the pager to switch to the next record - await testUtils.dom.click('.o_pager_next'); + await cpHelpers.pagerNext(form); assert.doesNotHaveClass(form.$('.o_notebook .nav-link:eq(0)'), 'active'); assert.hasClass(form.$('.o_notebook .nav-link:eq(1)'), 'active'); @@ -2793,20 +2799,22 @@ QUnit.module('Views', { }, }); - assert.isVisible(form.pager); - assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", + assert.containsOnce(form, '.o_pager'); + assert.strictEqual(cpHelpers.getPagerValue(form), "1", "current pager value should be 1"); - assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2", + assert.strictEqual(cpHelpers.getPagerSize(form), "2", "current pager limit should be 1"); await testUtils.form.clickCreate(form); - assert.isNotVisible(form.pager); + + assert.containsNone(form, '.o_pager'); await testUtils.form.clickSave(form); - assert.isVisible(form.pager); - assert.strictEqual(form.pager.$('.o_pager_value').text(), "3", + + assert.containsOnce(form, '.o_pager'); + assert.strictEqual(cpHelpers.getPagerValue(form), "3", "current pager value should be 3"); - assert.strictEqual(form.pager.$('.o_pager_limit').text(), "3", + assert.strictEqual(cpHelpers.getPagerSize(form), "3", "current pager limit should be 3"); form.destroy(); @@ -2835,10 +2843,11 @@ 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'); - await testUtils.dom.click(form.pager.$('.o_pager_next')); + assert.strictEqual(cpHelpers.getPagerValue(form), "1", 'pager value should be 1'); + + await cpHelpers.pagerNext(form); - assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2'); + assert.strictEqual(cpHelpers.getPagerValue(form), "2", 'pager value should be 2'); assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode'); assert.strictEqual(pushStateCount, 2, "should have triggered 2 push_state"); @@ -2935,28 +2944,28 @@ QUnit.module('Views', { viewOptions: { ids: [1, 2, 4], index: 0, - hasSidebar: true, + hasActionMenus: true, }, res_id: 1, }); - assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1'); - assert.strictEqual(form.pager.$('.o_pager_limit').text(), "3", 'pager limit should be 3'); + assert.strictEqual(cpHelpers.getPagerValue(form), "1", 'pager value should be 1'); + assert.strictEqual(cpHelpers.getPagerSize(form), "3", 'pager limit should be 3'); assert.strictEqual(form.$('span:contains(yop)').length, 1, 'should have a field with foo value for record 1'); assert.ok(!$('.modal:visible').length, 'no confirm modal should be displayed'); - // open sidebar and delete - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); + // open action menu and delete + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Delete"); assert.ok($('.modal').length, 'a confirm modal should be displayed'); // confirm the delete await 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'); + assert.strictEqual(cpHelpers.getPagerValue(form), "1", 'pager value should be 1'); + assert.strictEqual(cpHelpers.getPagerSize(form), "2", 'pager limit should be 2'); assert.strictEqual(form.$('span:contains(blip)').length, 1, 'should have a field with foo value for record 2'); form.destroy(); @@ -2973,7 +2982,7 @@ QUnit.module('Views', { viewOptions: { ids: [1], index: 0, - hasSidebar: true, + hasActionMenus: true, }, res_id: 1, mockRPC: function (route, args) { @@ -2982,9 +2991,8 @@ QUnit.module('Views', { } }); - // open sidebar, click on delete and confirm - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Delete"); await testUtils.mock.intercept(form, 'history_back', function () { assert.step('history_back'); @@ -5209,13 +5217,13 @@ QUnit.module('Views', { device: {size_class: size_class}, }, }); - } + }; var assertFormContainsNButtonsWithSizeClass = async function (size_class, n) { var form = await createFormWithDeviceSizeClass(size_class); assert.containsN(form, statButtonSelector, n, 'The form has the expected amount of buttons'); form.destroy(); - } + }; await assertFormContainsNButtonsWithSizeClass(0, 2); await assertFormContainsNButtonsWithSizeClass(1, 2); @@ -5510,7 +5518,7 @@ QUnit.module('Views', { print: [], }, viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, mockRPC: function (route, args) { if (route === '/web/action/load') { @@ -5524,17 +5532,15 @@ QUnit.module('Views', { }, }); - var $printMenu = form.$('.o_cp_sidebar .o_dropdown:contains(Print)'); - assert.isNotVisible($printMenu); - var $actionMenu = form.$('.o_cp_sidebar .o_dropdown:contains(Action)'); - assert.isVisible($actionMenu); + assert.containsNone(form, '.o_cp_action_menus .o_dropdown:contains(Print)'); + assert.containsOnce(form, '.o_cp_action_menus .o_dropdown:contains(Action)'); - testUtils.dom.click($actionMenu.find('button')); // open Action menu - assert.strictEqual($actionMenu.find('.dropdown-item').length, 3, - 'there should be 3 actions'); - var $customAction = $actionMenu.find('.dropdown-item:last'); - assert.strictEqual($customAction.text().trim(), 'Action partner', + await cpHelpers.toggleActionMenu(form); + + assert.containsN(form, '.o_cp_action_menus .dropdown-item', 3, "there should be 3 actions"); + assert.strictEqual(form.$('.o_cp_action_menus .dropdown-item:last').text().trim(), 'Action partner', "the custom action should have 'Action partner' as name"); + await testUtils.mock.intercept(form, 'do_action', function (event) { var context = event.data.action.context.__contexts[1]; assert.strictEqual(context.active_id, 1, @@ -5542,7 +5548,7 @@ QUnit.module('Views', { assert.deepEqual(context.active_ids, [1], "the active_ids should be an array with 1 inside."); }); - await testUtils.dom.click($customAction); + await cpHelpers.toggleMenuItem(form, "Action partner"); form.destroy(); }); @@ -5687,14 +5693,16 @@ QUnit.module('Views', { "first tab should be active"); // click on the pager to switch to the next record - await testUtils.dom.click(form.pager.$('.o_pager_next')); + await cpHelpers.pagerNext(form); + assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 1, "only the second tab should be visible"); 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 - await testUtils.dom.click(form.pager.$('.o_pager_previous')); + await cpHelpers.pagerPrevious(form); + assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 2, "both tabs should be visible again"); assert.hasClass(form.$('.o_notebook .nav-link:nth(1)'),'active', @@ -6205,24 +6213,22 @@ QUnit.module('Views', { await testUtils.fields.editInput(form.$('input[name="foo"]'), "test"); await testUtils.form.clickSave(form); - assert.containsOnce(form, '.o_form_view .alert > div',"should have a translation alert"); + assert.containsOnce(form, '.o_form_view .alert > div', "should have a translation alert"); // click on the pager to switch to the next record - await testUtils.dom.click(form.pager.$('.o_pager_next')); - assert.strictEqual(form.$('.o_form_view .alert > div').length, 0, - "should not have a translation alert"); + await cpHelpers.pagerNext(form); + assert.containsNone(form, '.o_form_view .alert > div', "should not have a translation alert"); // click on the pager to switch back to the previous record - await testUtils.dom.click(form.pager.$('.o_pager_previous')); - assert.containsOnce(form, '.o_form_view .alert > div',"should have a translation alert"); + await cpHelpers.pagerPrevious(form); + assert.containsOnce(form, '.o_form_view .alert > div', "should have a translation alert"); // remove translation alert by click X and check alert even after form reload await testUtils.dom.click(form.$('.o_form_view .alert > .close')); - assert.strictEqual(form.$('.o_form_view > .alert > div').length, 0, - "should not have a translation alert"); + assert.containsNone(form, '.o_form_view .alert > div', "should not have a translation alert"); + await form.reload(); - assert.strictEqual(form.$('.o_form_view .alert > div').length, 0, - "should not have a translation alert after reload"); + assert.containsNone(form, '.o_form_view .alert > div', "should not have a translation alert after reload"); form.destroy(); _t.database.multi_lang = multi_lang; @@ -7017,7 +7023,7 @@ QUnit.module('Views', { '<field name="display_name"/>' + '</form>', res_id: 1, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, mockRPC: function (route, args) { var result = this._super.apply(this, arguments); if (args.method === 'copy') { @@ -7035,8 +7041,9 @@ QUnit.module('Views', { }); // duplicate record 1 - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Duplicate"); + assert.containsOnce(form, '.o_form_editable', "form should be in edit mode"); assert.strictEqual(form.$('.o_field_widget').val(), 'first record (copy)', @@ -7044,8 +7051,8 @@ QUnit.module('Views', { await testUtils.form.clickSave(form); // save duplicated record // delete duplicated record - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Delete"); assert.strictEqual($('.modal').length, 1, "should have opened a confirm dialog"); await testUtils.dom.click($('.modal-footer .btn-primary')); @@ -7320,7 +7327,7 @@ QUnit.module('Views', { '</form>', }); - var onFileLoadedEventName = form.$('.o_form_binary_form').attr('target') + var onFileLoadedEventName = form.$('.o_form_binary_form').attr('target'); // trigger _onFileLoaded function $(window).trigger(onFileLoadedEventName, [{id: 5}, {id:2}]); @@ -7629,7 +7636,7 @@ QUnit.module('Views', { }); QUnit.test('do not change pager when discarding current record', async function (assert) { - assert.expect(2); + assert.expect(4); var form = await createView({ View: FormView, @@ -7645,14 +7652,18 @@ QUnit.module('Views', { res_id: 2, }); - assert.strictEqual(form.pager.$('.o_pager_counter').text().trim(), '2 / 2', + assert.strictEqual(cpHelpers.getPagerValue(form), "2", + 'pager should indicate that we are on second record'); + assert.strictEqual(cpHelpers.getPagerSize(form), "2", 'pager should indicate that we are on second record'); await testUtils.form.clickEdit(form); await testUtils.form.clickDiscard(form); - assert.strictEqual(form.pager.$('.o_pager_counter').text().trim(), '2 / 2', - 'pager should not have changed'); + assert.strictEqual(cpHelpers.getPagerValue(form), "2", + 'pager value should not have changed'); + assert.strictEqual(cpHelpers.getPagerSize(form), "2", + 'pager limit should not have changed'); form.destroy(); }); @@ -7801,13 +7812,13 @@ QUnit.module('Views', { }, res_id: 1, viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, }); core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache')); - await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(form.sidebar.$('a:contains(Delete)')); + await cpHelpers.toggleActionMenu(form); + await cpHelpers.toggleMenuItem(form, "Delete"); await testUtils.dom.click($('.modal-footer .btn-primary')); assert.verifySteps(['unlink', 'clear_cache']); @@ -8166,7 +8177,7 @@ QUnit.module('Views', { await testUtils.fields.many2one.clickOpenDropdown('trululu'); // switch to another record (should ask to discard changes, and reset the domain) - await testUtils.dom.click(form.pager.$('.o_pager_next')); + await cpHelpers.pagerNext(form); // discard changes by clicking on confirm in the dialog await testUtils.dom.click($('.modal .modal-footer .btn-primary:first')); diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js index d0cbe9d7a2e..05d490927ea 100644 --- a/addons/web/static/tests/views/graph_tests.js +++ b/addons/web/static/tests/views/graph_tests.js @@ -1,24 +1,26 @@ odoo.define('web.graph_view_tests', function (require) { "use strict"; -var concurrency = require('web.concurrency'); -var controlPanelViewParameters = require('web.controlPanelViewParameters'); +var searchUtils = require('web.searchUtils'); var GraphView = require('web.GraphView'); var testUtils = require('web.test_utils'); +const cpHelpers = testUtils.controlPanel; var createActionManager = testUtils.createActionManager; var createView = testUtils.createView; var patchDate = testUtils.mock.patchDate; -var INTERVAL_OPTIONS = controlPanelViewParameters.INTERVAL_OPTIONS.map(o => o.optionId); -var TIME_RANGE_OPTIONS = controlPanelViewParameters.TIME_RANGE_OPTIONS.map(o => o.optionId); -var COMPARISON_TIME_RANGE_OPTIONS = controlPanelViewParameters.COMPARISON_TIME_RANGE_OPTIONS.map(o => o.optionId); +const { INTERVAL_OPTIONS, TIME_RANGE_OPTIONS, COMPARISON_TIME_RANGE_OPTIONS } = searchUtils; + +var INTERVAL_OPTION_IDS = Object.keys(INTERVAL_OPTIONS); +var TIME_RANGE_OPTION_IDS = Object.keys(TIME_RANGE_OPTIONS); +var COMPARISON_TIME_RANGE_OPTION_IDS = Object.keys(COMPARISON_TIME_RANGE_OPTIONS); var f = (a, b) => [].concat(...a.map(d => b.map(e => [].concat(d, e)))); var cartesian = (a, b, ...c) => (b ? cartesian(f(a, b), ...c) : a); -var COMBINATIONS = cartesian(TIME_RANGE_OPTIONS, COMPARISON_TIME_RANGE_OPTIONS); -var COMBINATIONS_WITH_DATE = cartesian(TIME_RANGE_OPTIONS, COMPARISON_TIME_RANGE_OPTIONS, INTERVAL_OPTIONS); +var COMBINATIONS = cartesian(TIME_RANGE_OPTION_IDS, COMPARISON_TIME_RANGE_OPTION_IDS); +var COMBINATIONS_WITH_DATE = cartesian(TIME_RANGE_OPTION_IDS, COMPARISON_TIME_RANGE_OPTION_IDS, INTERVAL_OPTION_IDS); QUnit.assert.checkDatasets = function (graph, keys, expectedDatasets) { keys = keys instanceof Array ? keys : [keys]; @@ -192,7 +194,7 @@ QUnit.module('Views', { 'groupby should not contain id field'); } return this._super.apply(this, arguments); - } + }, }); graph.destroy(); }); @@ -298,9 +300,9 @@ QUnit.module('Views', { return this._super(route, args); }, }); + await cpHelpers.toggleMenu(graph, "Measures"); + await cpHelpers.toggleMenuItem(graph, "Foo"); - testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)')); - await testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="foo"]')); assert.checkLegend(graph, 'Foo'); assert.strictEqual(rpcCount, 2, "should have done 2 rpcs (2 readgroups)"); @@ -330,7 +332,7 @@ QUnit.module('Views', { QUnit.test('no content helper (pie chart)', async function (assert) { assert.expect(2); - this.data.foo.records = [] + this.data.foo.records = []; var graph = await createView({ View: GraphView, @@ -357,14 +359,11 @@ QUnit.module('Views', { model: "foo", data: this.data, context: { - timeRangeMenuData: { - //Q3 2018 - timeRange: ['&', ["date", ">=", "2018-07-01"],["date", "<=", "2018-09-30"]], - timeRangeDescription: 'This Quarter', - //Q4 2018 - comparisonTimeRange: ['&', ["date", ">=", "2018-10-01"],["date", "<=", "2018-12-31"]], - comparisonTimeRangeDescription: 'Previous Period', - }, + time_ranges: { + field: 'date', + range: 'this_quarter', + comparisonRange: 'previous_period', + } }, arch: '<graph type="pie">' + '<field name="product_id"/>' + @@ -443,8 +442,9 @@ QUnit.module('Views', { } }, "context should be correct"); - testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)')); - await testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="foo"]')); + await cpHelpers.toggleMenu(graph, "Measures"); + await cpHelpers.toggleMenuItem(graph, "Foo"); + assert.deepEqual(graph.getOwnedQueryParams(), { context: { graph_mode: 'bar', @@ -567,7 +567,7 @@ QUnit.module('Views', { assert.hasClass(graph.$buttons.find('button[data-mode="line"]'),'active', 'line chart button should be active'); // check groupby values ('Undefined' is rejected in line chart) are in labels - assert.checkLabels(graph, [['red'], ['black']]) + assert.checkLabels(graph, [['red'], ['black']]); graph.destroy(); }); @@ -687,10 +687,11 @@ QUnit.module('Views', { additionalMeasures: ['product_id'], }, }); + // need to set the measure this way because it cannot be set in the // arch. - await testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)')); - await testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="product_id"]')); + await cpHelpers.toggleMenu(graph, "Measures"); + await cpHelpers.toggleMenuItem(graph, "Product"); assert.checkLabels(graph, [['xphone'], ['xpad']]); assert.checkLegend(graph, 'Product'); @@ -729,8 +730,10 @@ QUnit.module('Views', { additionalMeasures: ['product_id'], }, }); - assert.ok(graph.measures.product_id, + + assert.ok(graph.measures.find(m => m.fieldName === 'product_id'), "should have product_id as measure"); + graph.destroy(); }); @@ -766,9 +769,10 @@ QUnit.module('Views', { '</graph>', }); - assert.strictEqual(graph.$buttons.find('.o_graph_measures_list .dropdown-item:first').data('field'), 'bouh', + await cpHelpers.toggleMenu(graph, "Measures"); + assert.strictEqual(graph.$buttons.find('.o_graph_measures_list .dropdown-item:first').text(), 'bouh', "Bouh should be the first measure"); - assert.strictEqual(graph.$buttons.find('.o_graph_measures_list .dropdown-item:last').data('field'), '__count__', + assert.strictEqual(graph.$buttons.find('.o_graph_measures_list .dropdown-item:last').text(), 'Count', "Count should be the last measure"); graph.destroy(); @@ -788,7 +792,7 @@ QUnit.module('Views', { }); function _indexOf (label) { - return graph.renderer._indexOf(graph.renderer.chart.data.labels, label) + return graph.renderer._indexOf(graph.renderer.chart.data.labels, label); } assert.strictEqual(_indexOf(['Undefined']), -1); @@ -816,7 +820,7 @@ QUnit.module('Views', { }); function _indexOf (label) { - return graph.renderer._indexOf(graph.renderer.chart.data.labels, label) + return graph.renderer._indexOf(graph.renderer.chart.data.labels, label); } assert.strictEqual(_indexOf(['Undefined']), -1); @@ -825,7 +829,7 @@ QUnit.module('Views', { assert.ok(_indexOf(['Undefined']) >= 0); await testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=pie]')); - var labels = graph.renderer.chart.data.labels + var labels = graph.renderer.chart.data.labels; assert.ok(labels.filter(label => /Undefined/.test(label.join(''))).length >= 1); // Undefined should not appear after switching back to line chart @@ -908,7 +912,7 @@ QUnit.module('Views', { groupBy: ['product_id', 'color_id'], }); - assert.checkLabels(graph, [['xphone'], ['xpad']]) + assert.checkLabels(graph, [['xphone'], ['xpad']]); assert.checkLegend(graph, ['Undefined', 'red']); assert.checkDatasets(graph, ['label', 'data'], [ { @@ -922,7 +926,7 @@ QUnit.module('Views', { ]); await testUtils.dom.click(graph.$('.o_graph_button[data-mode=line]')); - assert.checkLabels(graph, [['xphone'], ['xpad']]) + assert.checkLabels(graph, [['xphone'], ['xpad']]); assert.checkLegend(graph, ['Undefined', 'red']); assert.checkDatasets(graph, ['label', 'data'], [ { @@ -936,7 +940,7 @@ QUnit.module('Views', { ]); await testUtils.dom.click(graph.$('.o_graph_button[data-mode=pie]')); - assert.checkLabels(graph, [['xphone', 'Undefined'], ['xphone', 'red'], ['xpad', 'Undefined']]) + assert.checkLabels(graph, [['xphone', 'Undefined'], ['xphone', 'red'], ['xpad', 'Undefined']]); assert.checkLegend(graph, ['xphone/Undefined', 'xphone/red', 'xpad/Undefined']); assert.checkDatasets(graph, ['label', 'data'], { label: '', @@ -1015,7 +1019,7 @@ QUnit.module('Views', { if (exhaustiveTest) { i++; } else { - i += Math.floor(1 + Math.random() * 20) + i += Math.floor(1 + Math.random() * 20); } yield combination; } @@ -1033,7 +1037,7 @@ QUnit.module('Views', { self.combinationsToCheck[combination].errorMessage ); } else { - assert.checkLabels(graph, self.combinationsToCheck[combination].labels) + assert.checkLabels(graph, self.combinationsToCheck[combination].labels); assert.checkLegend(graph, self.combinationsToCheck[combination].legend); assert.checkDatasets(graph, ['label', 'data'], self.combinationsToCheck[combination].datasets); } @@ -1041,76 +1045,62 @@ QUnit.module('Views', { } }; + const GROUPBY_NAMES = ['Date', 'Bar', 'Product', 'Color']; + // time range menu is assumed to be closed this.selectTimeRanges = async function (timeRangeOption, comparisonTimeRangeOption) { comparisonTimeRangeOption = comparisonTimeRangeOption || 'previous_period'; - // open time range menu - await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button')); - // select range - await testUtils.fields.editInput($('.o_control_panel .o_time_range_selector'), timeRangeOption); - // check checkbox 'Compare To' - if (!$('.o_control_panel .o_time_range_menu .o_comparison_checkbox').prop('checked')) { - await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); + await cpHelpers.toggleTimeRangeMenu(document); + await cpHelpers.selectRange(document, timeRangeOption); + if (!document.querySelector('div.o_time_range_section input').checked) { + await cpHelpers.toggleTimeRangeMenuBox(document); } - // select 'Previous period' or 'Previous year' acording to comparisonTimeRangeOption - await testUtils.fields.editInput($('.o_control_panel .o_comparison_time_range_selector'), comparisonTimeRangeOption); - // Click on 'Apply' button - await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range')); + await cpHelpers.selectComparisonRange(document, comparisonTimeRangeOption); + await cpHelpers.applyTimeRange(document); + await cpHelpers.toggleTimeRangeMenu(document); }; // groupby menu is assumed to be closed this.selectDateIntervalOption = async function (intervalOption) { - const self = this; intervalOption = intervalOption || 'month'; + const optionIndex = INTERVAL_OPTION_IDS.indexOf(intervalOption); - // open group by menu - await testUtils.dom.click($('.o_control_panel .o_dropdown span.fa-bars')); - + await cpHelpers.toggleGroupByMenu(document); let wasSelected = false; if (this.keepFirst) { - if ($('.o_control_panel .o_group_by_menu .o_menu_item:contains(Product) a').hasClass('selected')) { + if (cpHelpers.isItemSelected(document, 2)) { wasSelected = true; - await testUtils.dom.click($('.o_control_panel .o_group_by_menu .o_menu_item:contains(Product)')); + await cpHelpers.toggleMenuItem(document, 2); } } - - // open option submenu - await testUtils.dom.click($('.o_control_panel .o_group_by_menu .o_menu_item:contains("Date")')); - // check interval option if not already selected - if (!$('.o_control_panel .o_group_by_menu .o_item_option[data-option_id="' + intervalOption + '"] a').hasClass('selected')) { - await testUtils.dom.click($('.o_control_panel .o_group_by_menu .o_item_option[data-option_id="' + intervalOption + '"]')); + await cpHelpers.toggleMenuItem(document, 0); + if (!cpHelpers.isOptionSelected(document, 0, optionIndex)) { + await cpHelpers.toggleMenuItemOption(document, 0, optionIndex); } - await INTERVAL_OPTIONS.filter(oId => oId !== intervalOption).forEach(async function(oId) { - if ($('.o_control_panel .o_group_by_menu .o_item_option[data-option_id="' + oId + '"] a').hasClass('selected')) { - await testUtils.dom.click($('.o_control_panel .o_group_by_menu .o_item_option[data-option_id="' + oId + '"]')); + for (let i = 0; i < INTERVAL_OPTION_IDS.length; i++) { + const oId = INTERVAL_OPTION_IDS[i]; + if (oId !== intervalOption && cpHelpers.isOptionSelected(document, 0, i)) { + await cpHelpers.toggleMenuItemOption(document, 0, i); } - }); + } if (this.keepFirst) { - if (wasSelected && !$('.o_control_panel .o_group_by_menu .o_menu_item:contains(Product) a').hasClass('selected')) { - await testUtils.dom.click($('.o_control_panel .o_group_by_menu .o_menu_item:contains(Product)')); + if (wasSelected && !cpHelpers.isItemSelected(document, 2)) { + await cpHelpers.toggleMenuItem(document, 2); } } + await cpHelpers.toggleGroupByMenu(document); - // close group by menu - await testUtils.dom.click($('.o_control_panel .o_dropdown span.fa-bars')); }; // groupby menu is assumed to be closed this.selectGroupBy = async function (groupByName) { - // open group by menu - await testUtils.dom.click($('.o_control_panel .o_dropdown span.fa-bars')); - // check groupBy if not already selected - if (!$('.o_control_panel .o_group_by_menu .o_menu_item:contains(' + groupByName + ') a').hasClass('selected')) { - await testUtils.dom.click($('.o_control_panel .o_group_by_menu .o_menu_item:contains(' + groupByName + ')')); + await cpHelpers.toggleGroupByMenu(document); + const index = GROUPBY_NAMES.indexOf(groupByName); + if (!cpHelpers.isItemSelected(document, index)) { + await cpHelpers.toggleMenuItem(document, index); } - // close group by menu - await testUtils.dom.click($('.o_control_panel .o_dropdown span.fa-bars')); - }; - // groupby menu is assumed to be closed - this.unselectGroupBy = async function (groupByName) { - // check groupBy if already selected - + await cpHelpers.toggleGroupByMenu(document); }; this.setConfig = async function (combination) { @@ -1121,7 +1111,7 @@ QUnit.module('Views', { }; this.setMode = async function (mode) { - await testUtils.dom.click($('.o_control_panel .o_graph_button[data-mode=' + mode + ']')); + await testUtils.dom.click($(`.o_control_panel .o_graph_button[data-mode="${mode}"]`)); }; // // create an action manager to test the interactions with the search view @@ -1148,7 +1138,7 @@ QUnit.module('Views', { graph: { additionalMeasures: ['product_id'], } - } + }, }); }, afterEach: function () { diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index 47c3862ba8f..9adc2f00069 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -14,6 +14,7 @@ var widgetRegistry = require('web.widget_registry'); var makeTestPromise = testUtils.makeTestPromise; var nextTick = testUtils.nextTick; +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; QUnit.module('Views', { @@ -345,10 +346,9 @@ QUnit.module('Views', { '</t></templates></kanban>', groupBy: ['bar'], }); - await kanban.renderPager(); - assert.isNotVisible(kanban.pager.$el, - "pager should be hidden in grouped kanban"); + assert.containsNone(kanban, '.o_pager'); + kanban.destroy(); }); @@ -369,9 +369,8 @@ QUnit.module('Views', { }, }); - 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"); + assert.containsOnce(kanban, '.o_pager'); + assert.strictEqual(cpHelpers.getPagerSize(kanban), "4", "pager's size should be 4"); kanban.destroy(); }); @@ -395,8 +394,8 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.pager.state.limit, 2, "pager's limit should be 2"); - assert.strictEqual(kanban.pager.state.size, 4, "pager's size should be 4"); + assert.strictEqual(cpHelpers.getPagerValue(kanban), "1-2", "pager's limit should be 2"); + assert.strictEqual(cpHelpers.getPagerSize(kanban), "4", "pager's size should be 4"); kanban.destroy(); }); @@ -421,8 +420,8 @@ QUnit.module('Views', { }, }); - assert.strictEqual(kanban.pager.state.limit, 3, "pager's limit should be 3"); - assert.strictEqual(kanban.pager.state.size, 4, "pager's size should be 4"); + assert.strictEqual(cpHelpers.getPagerValue(kanban), "1-3", "pager's limit should be 3"); + assert.strictEqual(cpHelpers.getPagerSize(kanban), "4", "pager's size should be 4"); kanban.destroy(); }); @@ -577,7 +576,7 @@ QUnit.module('Views', { }, }); - assert.containsOnce(kanban, '.o_cp_controller', 'should have one control panel'); + assert.containsOnce(kanban, '.o_control_panel', 'should have one control panel'); assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record', "first column should contain one record"); @@ -589,7 +588,7 @@ QUnit.module('Views', { "should have a quick create element in the first column"); assert.strictEqual($quickCreate.find('.o_form_view.o_xxs_form_view').length, 1, "should have rendered an XXS form view"); - assert.containsOnce(kanban, '.o_cp_controller', 'should not have instantiated an extra control panel'); + assert.containsOnce(kanban, '.o_control_panel', 'should not have instantiated an extra control panel'); assert.strictEqual($quickCreate.find('input').length, 2, "should have two inputs"); assert.strictEqual($quickCreate.find('.o_field_widget').length, 3, @@ -1160,7 +1159,7 @@ QUnit.module('Views', { assert.step('onchange'); if (shouldDelayOnchange) { return Promise.resolve(prom).then(function () { - return result + return result; }); } } @@ -1255,7 +1254,7 @@ QUnit.module('Views', { assert.step('onchange'); if (shouldDelayOnchange) { return Promise.resolve(prom).then(function () { - return result + return result; }); } } @@ -4836,7 +4835,7 @@ QUnit.module('Views', { '</t></templates>' + '</kanban>', mockRPC: function (route, args) { - assert.step(route) + assert.step(route); return this._super(route, args); }, }); @@ -4971,12 +4970,12 @@ QUnit.module('Views', { mockRPC: function (route, args) { if (route === '/web/dataset/call_kw/partner/action_archive') { var partnerIDS = args.args[0]; - var records = this.data.partner.records + var records = this.data.partner.records; _.each(partnerIDS, function(partnerID) { _.find(records, function (record) { return record.id === partnerID; }).active = false; - }) + }); this.data.partner.records[0].active; return Promise.resolve(); } diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 19648bfb44b..b5ae51af648 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -15,11 +15,12 @@ var testUtils = require('web.test_utils'); var widgetRegistry = require('web.widget_registry'); var Widget = require('web.Widget'); + var _t = core._t; +const cpHelpers = testUtils.controlPanel; var createActionManager = testUtils.createActionManager; var createView = testUtils.createView; - QUnit.module('Views', { beforeEach: function () { this.data = { @@ -178,20 +179,26 @@ QUnit.module('Views', { QUnit.test('list with delete="0"', async function (assert) { assert.expect(4); - var list = await createView({ + const list = await createView({ View: ListView, model: 'foo', data: this.data, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, arch: '<tree delete="0"><field name="foo"/></tree>', }); - assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible'); + + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); assert.ok(list.$('tbody td.o_list_record_selector').length, 'should have at least one record'); await 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'); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus'); + await cpHelpers.toggleActionMenu(list); + assert.deepEqual( + cpHelpers.getMenuItemTexts(list), + ['Export'], + 'action menu should not have Delete button' + ); list.destroy(); }); @@ -203,7 +210,7 @@ QUnit.module('Views', { View: ListView, model: 'foo', data: this.data, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, arch: '<tree editable="top" edit="0"><field name="foo"/></tree>', }); @@ -762,33 +769,31 @@ QUnit.module('Views', { } return this._super.apply(this,arguments); }, - intercepts: { - load_filters: function (event) { - return Promise.resolve([ - { - context: "{}", - domain: "[]", - id: 7, - is_default: true, - name: "My favorite", - sort: "[\"date asc\", \"foo desc\"]", - user_id: [2, "Mitchell Admin"], - }, { - context: "{}", - domain: "[]", - id: 8, - is_default: false, - name: "My second favorite", - sort: "[\"date desc\", \"foo asc\"]", - user_id: [2, "Mitchell Admin"], - } - ]).then(event.data.on_success); - }, - }, + favoriteFilters : [ + { + context: "{}", + domain: "[]", + id: 7, + is_default: true, + name: "My favorite", + sort: "[\"date asc\", \"foo desc\"]", + user_id: [2, "Mitchell Admin"], + }, { + context: "{}", + domain: "[]", + id: 8, + is_default: false, + name: "My second favorite", + sort: "[\"date desc\", \"foo asc\"]", + user_id: [2, "Mitchell Admin"], + } + ] }); - await testUtils.dom.click(list.$('.o_control_panel .o_search_options button.o_favorites_menu_button')); - await testUtils.dom.click(list.$('.o_control_panel .o_search_options .o_favorites_menu .o_menu_item').eq(1)); + + await cpHelpers.toggleFavoriteMenu(list); + await cpHelpers.toggleMenuItem(list, "My second favorite"); + list.destroy(); }); @@ -843,9 +848,10 @@ QUnit.module('Views', { assert.ok("list view should trigger 'open_record' event"); }); - testUtils.dom.click(list.$('tr td:not(.o_list_record_selector)').first()); + await testUtils.dom.click(list.$('tr td:not(.o_list_record_selector)').first()); list.update({groupBy: ['foo']}); await testUtils.nextTick(); + assert.containsN(list, 'tr.o_group_header', 3, "list should be grouped"); await testUtils.dom.click(list.$('th.o_group_name').first()); @@ -1007,11 +1013,13 @@ QUnit.module('Views', { domain: [['foo', '=', 'yop']], }); + assert.containsN(list, 'tbody tr', 4, "list should contain 4 rows"); 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', + + assert.strictEqual(cpHelpers.getPagerValue(list), '1-1', "pager should be correct"); await testUtils.dom.click(list.$buttons.find('.o_list_button_add')); @@ -1020,7 +1028,7 @@ QUnit.module('Views', { "list should still contain 4 rows"); 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', + assert.strictEqual(cpHelpers.getPagerValue(list), '1-2', "pager should be correct"); await testUtils.dom.click(list.$buttons.find('.o_list_button_discard')); @@ -1029,7 +1037,7 @@ QUnit.module('Views', { "list should still contain 4 rows"); 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', + assert.strictEqual(cpHelpers.getPagerValue(list), '1-1', "pager should be correct"); assert.verifySteps(['destroy'], "should have destroyed the widget of the removed line"); @@ -1285,32 +1293,32 @@ QUnit.module('Views', { model: 'foo', data: this.data, groupBy: ['foo'], - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, arch: '<tree>' + '<field name="foo"/>' + '<field name="int_field" sum="Sum"/>' + '</tree>', }); - assert.isNotVisible(list.sidebar); + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); // open blip grouping and check all lines await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")')); await testUtils.dom.click(list.$('.o_data_row:first input')); - assert.isVisible(list.sidebar); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus'); // open yop grouping and verify blip are still checked await 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.isVisible(list.sidebar); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus'); // close and open blip grouping and verify blip are unchecked await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")')); await 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.isNotVisible(list.sidebar); + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); list.destroy(); }); @@ -1599,10 +1607,9 @@ QUnit.module('Views', { limit: 2, }, }); - var widthPage1 = list.$(`th[data-name=foo]`)[0].offsetWidth; - await testUtils.dom.click(list.$('.o_pager_next')); + await cpHelpers.pagerNext(list); var widthPage2 = list.$(`th[data-name=foo]`)[0].offsetWidth; assert.ok(widthPage1 > widthPage2, @@ -2477,19 +2484,20 @@ QUnit.module('Views', { View: ListView, model: 'foo', data: this.data, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, arch: '<tree><field name="foo"/></tree>', }); - assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible'); + + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); assert.containsN(list, 'tbody td.o_list_record_selector', 4, "should have 4 records"); await testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input')); - assert.isVisible(list.sidebar.$el, 'sidebar should be visible'); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus'); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Delete)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Delete"); assert.hasClass($('body'),'modal-open', 'body should have modal-open clsss'); await testUtils.dom.click($('body .modal button span:contains(Ok)')); @@ -2508,7 +2516,7 @@ QUnit.module('Views', { View: ListView, model: 'foo', data: this.data, - viewOptions: {hasSidebar: true}, + viewOptions: {hasActionMenus: true}, arch: '<tree><field name="foo"/></tree>', mockRPC: function (route) { assert.step(route); @@ -2520,22 +2528,23 @@ QUnit.module('Views', { }, }); - assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible'); + + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); assert.containsN(list, 'tbody td.o_list_record_selector', 4, "should have 4 records"); await testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input')); - assert.isVisible(list.sidebar.$el, 'sidebar should be visible'); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus'); assert.verifySteps(['/web/dataset/search_read']); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Archive)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Archive"); assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); await testUtils.dom.click($('.modal-footer .btn-secondary')); assert.containsN(list, 'tbody td.o_list_record_selector', 4, "still should have 4 records"); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Archive)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Archive"); assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed'); await testUtils.dom.click($('.modal-footer .btn-primary')); assert.containsN(list, 'tbody td.o_list_record_selector', 3, "should have 3 records"); @@ -2559,10 +2568,10 @@ QUnit.module('Views', { }, }); - assert.isVisible(list.pager.$el, "pager should be visible"); - assert.strictEqual(list.pager.state.size, 4, "pager's size should be 4"); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_pager'); + assert.strictEqual(cpHelpers.getPagerSize(list), "4", "pager's size should be 4"); await list.update({ groupBy: ['bar']}); - assert.strictEqual(list.pager.state.size, 2, "pager's size should be 2"); + assert.strictEqual(cpHelpers.getPagerSize(list), "2", "pager's size should be 2"); list.destroy(); }); @@ -2803,8 +2812,7 @@ QUnit.module('Views', { res_id: 1, }); - // Change page - await testUtils.dom.click(form.$('.o_field_widget[name=o2m] .o_pager_next')); + await cpHelpers.pagerNext('.o_field_widget[name=o2m]'); assert.strictEqual(form.$('tbody tr:first').text(), 'Value 44', "record 44 should be first"); assert.strictEqual(form.$('tbody tr:eq(4)').text(), 'Value 48', @@ -3819,23 +3827,23 @@ QUnit.module('Views', { limit: 3, }, }); - var headerHeight = list.$('.o_group_header').css('height'); // basic rendering checks await testUtils.dom.click(list.$('.o_group_header')); assert.strictEqual(list.$('.o_group_header').css('height'), headerHeight, "height of group header shouldn't have changed"); - assert.hasClass(list.$('.o_group_header th:eq(1) > div'), 'o_pager', + assert.hasClass(list.$('.o_group_header th:eq(1) > nav'), 'o_pager', "last cell of open group header should have classname 'o_pager'"); - assert.strictEqual(list.$('.o_group_header .o_pager_value').text(), '1-3', + + assert.strictEqual(cpHelpers.getPagerValue('.o_group_header'), '1-3', "pager's value should be correct"); assert.containsN(list, '.o_data_row', 3, "open group should display 3 records"); // go to next page - await testUtils.dom.click(list.$('.o_group_header .o_pager_next')); - assert.strictEqual(list.$('.o_group_header .o_pager_value').text(), '4-4', + await cpHelpers.pagerNext('.o_group_header'); + assert.strictEqual(cpHelpers.getPagerValue('.o_group_header'), '4-4', "pager's value should be correct"); assert.containsOnce(list, '.o_data_row', "open group should display 1 record"); @@ -4109,14 +4117,14 @@ QUnit.module('Views', { "3rd row should be selected"); // press enter in input - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'enter'); assert.hasClass(list.$('tr.o_data_row:eq(3)'),'o_selected_row', "4rd row should be selected"); assert.doesNotHaveClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row', "3rd row should no longer be selected"); // press enter on last row - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'enter'); assert.containsN(list, 'tr.o_data_row', 5, "should have created a 5th row"); assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/default_get']); @@ -4220,7 +4228,7 @@ QUnit.module('Views', { }); QUnit.test('display toolbar', async function (assert) { - assert.expect(6); + assert.expect(2); var list = await createView({ View: ListView, @@ -4237,31 +4245,22 @@ QUnit.module('Views', { print: [], }, viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, }); - var $printMenu = list.$('.o_cp_sidebar .o_dropdown:contains(Print)'); - assert.isNotVisible($printMenu); - var $actionMenu = list.$('.o_cp_sidebar .o_dropdown:contains(Action)'); - assert.isNotVisible($actionMenu); - testUtils.dom.click(list.$('.o_list_record_selector:first input')); + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); - assert.isNotVisible($printMenu); - assert.isVisible($actionMenu); + await testUtils.dom.click(list.$('.o_list_record_selector:first input')); - testUtils.dom.click($actionMenu.find('button')); // open Action menu - assert.strictEqual($actionMenu.find('.dropdown-item').length, 3, - "there should be 3 actions"); - var $customAction = $actionMenu.find('.dropdown-item:last'); - assert.strictEqual($customAction.text().trim(), 'Action event', - "the custom action should have 'Action event' as name"); + await cpHelpers.toggleActionMenu(list); + assert.deepEqual(cpHelpers.getMenuItemTexts(list), ['Export', 'Delete', 'Action event']); list.destroy(); }); - QUnit.test('execute a sidebar actions with correct params', async function (assert) { + QUnit.test('execute ActionMenus actions with correct params', async function (assert) { assert.expect(12); const list = await createView({ @@ -4285,39 +4284,40 @@ QUnit.module('Views', { return this._super(...arguments); }, viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, }); - let $actionMenu = list.$('.o_cp_sidebar .o_dropdown:contains(Action)'); - assert.isNotVisible($actionMenu); + assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus'); + assert.containsN(list, '.o_data_row', 4); // select all records await testUtils.dom.click(list.$('thead .o_list_record_selector input')); assert.containsN(list, '.o_list_record_selector input:checked', 5); - assert.isVisible($actionMenu); + assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus'); - await testUtils.dom.click($actionMenu.find('button')); // open Action menu - await testUtils.dom.click($actionMenu.find('.dropdown-item:contains(Custom Action)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Custom Action"); // unselect first record (will unselect the thead checkbox as well) await testUtils.dom.click(list.$('tbody .o_list_record_selector:first input')); assert.containsN(list, '.o_list_record_selector input:checked', 3); - await testUtils.dom.click($actionMenu.find('button')); // open Action menu - await testUtils.dom.click($actionMenu.find('.dropdown-item:contains(Custom Action)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Custom Action"); // add a domain and select first two records await list.reload({ domain: [['bar', '=', true]] }); assert.containsN(list, '.o_data_row', 3); assert.containsNone(list, '.o_list_record_selector input:checked'); - $actionMenu = list.$('.o_cp_sidebar .o_dropdown:contains(Action)'); + await testUtils.dom.click(list.$('tbody .o_list_record_selector:nth(0) input')); await testUtils.dom.click(list.$('tbody .o_list_record_selector:nth(1) input')); assert.containsN(list, '.o_list_record_selector input:checked', 2); - await testUtils.dom.click($actionMenu.find('button')); // open Action menu - await testUtils.dom.click($actionMenu.find('.dropdown-item:contains(Custom Action)')); + + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Custom Action"); assert.verifySteps([ '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3,4],"active_model":"foo","select_all":true,"active_domain":[]}}', @@ -4374,13 +4374,13 @@ QUnit.module('Views', { assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); assert.strictEqual(document.activeElement, list.$('.o_data_row:first .o_data_cell:first input')[0]); - // Press 'Tab' -> should go to next cell (still in first row) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + // // Press 'Tab' -> should go to next cell (still in first row) + await testUtils.fields.triggerKeydown(list.$('.o_selected_row input[name="foo"]'), 'tab'); assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); assert.strictEqual(document.activeElement, list.$('.o_data_row:first .o_data_cell:last input')[0]); - // Press 'Tab' -> should go to next line (first cell) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + // // Press 'Tab' -> should go to next line (first cell) + await testUtils.fields.triggerKeydown(list.$('.o_selected_row input[name="int_field"]'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(1)'), 'o_selected_row'); assert.strictEqual(document.activeElement, list.$('.o_data_row:nth(1) .o_data_cell:first input')[0]); @@ -4507,13 +4507,13 @@ QUnit.module('Views', { // Press 'Tab' -> should go to next line // add a value in the cell because the Tab on an empty first cell would activate the next widget in the view await testUtils.fields.editInput(list.$('.o_selected_row input').eq(1), 11); - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row input[name="display_name"]'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(3)'),'o_selected_row', "fourth row should be in edition"); // Press 'Tab' -> should go back to first line as the create action isn't available await testUtils.fields.editInput(list.$('.o_selected_row input').eq(1), 11); - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row input[name="display_name"]'), 'tab'); assert.hasClass(list.$('.o_data_row:first'),'o_selected_row', "first row should be in edition"); @@ -6080,7 +6080,7 @@ QUnit.module('Views', { "the second row should be selected"); // Keyboard navigation only interracts with selected elements - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input.o_field_widget'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input.o_field_widget[name="int_field"]'), 'enter'); assert.hasClass(list.$('.o_data_row:eq(3)'), 'o_selected_row', "the fourth row should be selected"); @@ -6493,7 +6493,7 @@ QUnit.module('Views', { }); QUnit.test('use the limit attribute in arch', async function (assert) { - assert.expect(3); + assert.expect(4); var list = await createView({ View: ListView, @@ -6507,8 +6507,9 @@ QUnit.module('Views', { }, }); - assert.strictEqual(list.pager.$el.text().trim(), '1-2 / 4', - "pager should be correct"); + + assert.strictEqual(cpHelpers.getPagerValue(list), '1-2'); + assert.strictEqual(cpHelpers.getPagerSize(list), '4'); assert.containsN(list, '.o_data_row', 2, 'should display 2 data rows'); @@ -6641,7 +6642,7 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, }); core.bus.on('clear_cache', list, assert.step.bind(assert, 'clear_cache')); @@ -6658,8 +6659,8 @@ QUnit.module('Views', { // delete a record await testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input')); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Delete)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, "Delete"); await testUtils.dom.click($('.modal-footer .btn-primary')); assert.verifySteps([ @@ -6696,23 +6697,21 @@ QUnit.module('Views', { }, }); + // switch pages (should ask to scroll) - await testUtils.dom.click(list.pager.$('.o_pager_next')); - await testUtils.dom.click(list.pager.$('.o_pager_previous')); + await cpHelpers.pagerNext(list); + await cpHelpers.pagerPrevious(list); assert.verifySteps(['scroll', 'scroll'], "should ask to scroll when switching pages"); // change the limit (should not ask to scroll) - await testUtils.dom.click(list.pager.$('.o_pager_value')); - await testUtils.fields.editAndTrigger(list.pager.$('.o_pager_value input'), - '1-2', ['blur']); - assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-2', - "should have changed the limit"); - + await cpHelpers.setPagerValue(list, '1-2'); + await testUtils.nextTick(); + assert.strictEqual(cpHelpers.getPagerValue(list), '1-2'); assert.verifySteps([], "should not ask to scroll when changing the limit"); // switch pages again (should still ask to scroll) - await testUtils.dom.click(list.pager.$('.o_pager_next')); + await cpHelpers.pagerNext(list); assert.verifySteps(['scroll'], "this is still working after a limit change"); @@ -6895,9 +6894,9 @@ QUnit.module('Views', { assert.containsN(list, '.o_group_header', 3); // page 1 assert.containsNone(list, '.o_data_row'); - assert.containsOnce(list, '.o_pager_counter'); // has a pager + assert.containsOnce(list, '.o_pager'); // has a pager - await testUtils.dom.click(list.$('.o_pager_next')); // switch to page 2 + await cpHelpers.pagerNext(list); // switch to page 2 assert.containsN(list, '.o_group_header', 1); // page 2 assert.containsNone(list, '.o_data_row'); @@ -6986,9 +6985,9 @@ QUnit.module('Views', { assert.containsN(list, '.o_group_header', 10); // page 1 assert.containsN(list, '.o_data_row', 11); // one group contains two records - assert.containsOnce(list, '.o_pager_counter'); // has a pager + assert.containsOnce(list, '.o_pager'); // has a pager - await testUtils.dom.click(list.$('.o_pager_next')); // switch to page 2 + await cpHelpers.pagerNext(list); // switch to page 2 assert.containsN(list, '.o_group_header', 7); // page 2 assert.containsN(list, '.o_data_row', 7); @@ -7044,8 +7043,8 @@ QUnit.module('Views', { assert.containsN(actionManager, '.o_group_header', 1); // page 2 // toggle a filter -> there should be only one group left (on page 1) - await testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options .o_filters_menu_button')); - await testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options .o_filters_menu .o_menu_item:first')); + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleMenuItem(actionManager, 0); assert.strictEqual(actionManager.$('.o_pager_counter').text().trim(), '1-1 / 1'); assert.containsN(actionManager, '.o_group_header', 1); // page 1 @@ -7314,19 +7313,19 @@ QUnit.module('Views', { assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); // Press 'Tab' -> should go to next line (still in first group) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(1)'), 'o_selected_row'); // Press 'Tab' -> should go to next line (still in first group) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(2)'), 'o_selected_row'); // Press 'Tab' -> should go to first line of next group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(3)'), 'o_selected_row'); // Press 'Tab' -> should go back to first line of first group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); list.destroy(); @@ -7354,19 +7353,19 @@ QUnit.module('Views', { assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); // Press 'Tab' -> should go to next line (still in first group) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(1)'), 'o_selected_row'); // Press 'Tab' -> should go to next line (still in first group) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(2)'), 'o_selected_row'); // Press 'Tab' -> should go to first line of next group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(3)'), 'o_selected_row'); // Press 'Tab' -> should go back to first line of first group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); list.destroy(); @@ -7394,19 +7393,19 @@ QUnit.module('Views', { assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); // Press 'Tab' -> should go to next line (still in first group) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(1)'), 'o_selected_row'); // Press 'Tab' -> should go to next line (still in first group) - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(2)'), 'o_selected_row'); // Press 'Tab' -> should go to first line of next group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:nth(3)'), 'o_selected_row'); // Press 'Tab' -> should go back to first line of first group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.hasClass(list.$('.o_data_row:first'), 'o_selected_row'); list.destroy(); @@ -7550,20 +7549,20 @@ QUnit.module('Views', { await testUtils.fields.editInput(list.$('.o_selected_row input[name="foo"]'), 'new value'); // Press 'Tab' -> should create a new record as we edited the previous one - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.containsN(list, '.o_data_row', 5); assert.hasClass(list.$('.o_data_row:nth(3)'), 'o_selected_row'); // fill foo field for the new record and press 'tab' -> should create another record await testUtils.fields.editInput(list.$('.o_selected_row input[name="foo"]'), 'new record'); - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.containsN(list, '.o_data_row', 6); assert.hasClass(list.$('.o_data_row:nth(4)'), 'o_selected_row'); // leave this new row empty and press tab -> should discard the new record and move to the // next group - await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab'); + await testUtils.fields.triggerKeydown(list.$('.o_selected_row .o_input'), 'tab'); assert.containsN(list, '.o_data_row', 5); assert.hasClass(list.$('.o_data_row:nth(4)'), 'o_selected_row'); @@ -7637,13 +7636,13 @@ QUnit.module('Views', { assert.hasClass(list.$('tr.o_data_row:eq(1)'), 'o_selected_row'); // press enter in input should move to next record - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row .o_input'), 'enter'); assert.hasClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row'); assert.doesNotHaveClass(list.$('tr.o_data_row:eq(1)'), 'o_selected_row'); // press enter on last row should create a new record - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row .o_input'), 'enter'); assert.containsN(list, 'tr.o_data_row', 5); assert.hasClass(list.$('tr.o_data_row:eq(3)'), 'o_selected_row'); @@ -7680,13 +7679,13 @@ QUnit.module('Views', { assert.hasClass(list.$('tr.o_data_row:eq(1)'), 'o_selected_row'); // press enter in input should move to next record - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row .o_input'), 'enter'); assert.hasClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row'); assert.doesNotHaveClass(list.$('tr.o_data_row:eq(1)'), 'o_selected_row'); // press enter on last row should move to first record of next group - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row .o_input'), 'enter'); assert.hasClass(list.$('tr.o_data_row:eq(3)'), 'o_selected_row'); assert.doesNotHaveClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row'); @@ -7722,13 +7721,13 @@ QUnit.module('Views', { assert.hasClass(list.$('tr.o_data_row:eq(1)'), 'o_selected_row'); // press enter in input should move to next record - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row .o_input'), 'enter'); assert.hasClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row'); assert.doesNotHaveClass(list.$('tr.o_data_row:eq(1)'), 'o_selected_row'); // press enter on last row should move to first record of next group - await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter'); + await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row .o_input'), 'enter'); assert.hasClass(list.$('tr.o_data_row:eq(3)'), 'o_selected_row'); assert.doesNotHaveClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row'); diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js index 8ab46a0ca8d..0d17797ad74 100644 --- a/addons/web/static/tests/views/pivot_tests.js +++ b/addons/web/static/tests/views/pivot_tests.js @@ -3,11 +3,11 @@ odoo.define('web.pivot_tests', function (require) { var core = require('web.core'); var PivotView = require('web.PivotView'); -var PivotRenderer = require('web.PivotRenderer'); var testUtils = require('web.test_utils'); var testUtilsDom = require('web.test_utils_dom'); var _t = core._t; +const cpHelpers = testUtils.controlPanel; var createActionManager = testUtils.createActionManager; var createView = testUtils.createView; var patchDate = testUtils.mock.patchDate; @@ -388,10 +388,9 @@ QUnit.module('Views', { var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0); var context = { - timeRangeMenuData: { - timeRange: ["&",["date",">=","2016-12-01"],["date","<","2017-01-01"]], - timeRangeDescription: 'This Month', - comparisonTimeRange: [], + time_ranges: { + field: 'date', + range: 'this_month' } }; var pivot = await createView({ @@ -411,7 +410,7 @@ QUnit.module('Views', { viewOptions: { context: context, title: 'Partners', - } + }, }); assert.hasClass(pivot.$('table'), 'o_enable_linking', @@ -433,11 +432,10 @@ QUnit.module('Views', { this.data.partner.records[3].date = '2016-11-03'; var context = { - timeRangeMenuData: { - timeRange: ["&",["date",">=","2016-12-01"],["date","<","2017-01-01"]], - timeRangeDescription: 'This Month', - comparisonTimeRange: ["&",["date",">=","2016-11-01"],["date","<","2017-12-01"]], - comparisonTimeRangeDescription: 'Previous Period' + time_ranges: { + field: 'date', + range: 'this_month', + comparisonRange: 'previous_period', } }; @@ -470,7 +468,7 @@ QUnit.module('Views', { viewOptions: { context: context, title: 'Partners', - } + }, }); assert.hasClass(pivot.$('table'), 'o_enable_linking', "root node should have classname 'o_enable_linking'"); @@ -1945,7 +1943,7 @@ QUnit.module('Views', { }); QUnit.test('rendering of pivot view with comparison', async function (assert) { - assert.expect(7); + assert.expect(8); this.data.partner.records[0].date = '2016-12-15'; this.data.partner.records[1].date = '2016-12-17'; @@ -1966,31 +1964,40 @@ QUnit.module('Views', { viewOptions: { additionalMeasures: ['product_id'], }, - intercepts: { - create_filter: function (ev) { - var data = ev.data; - assert.deepEqual(data.filter.context.timeRangeMenuData, { - timeRange: ["&", ["date", ">=", "2016-12-01"], ["date", "<", "2017-01-01"]], - timeRangeDescription: 'This Month', - comparisonTimeRange: ["&", ["date", ">=", "2016-11-01"], ["date", "<", "2016-12-01"]], - comparisonTimeRangeDescription: 'Previous Period', - }); + mockRPC: function () { + return this._super.apply(this, arguments); + }, + env: { + dataManager: { + create_filter: async function (filter) { + assert.deepEqual(filter.context, { + pivot_measures: ['__count'], + pivot_column_groupby: [], + pivot_row_groupby: ['product_id'], + group_by: [], + time_ranges: { + field: 'date', + range: 'this_month', + comparisonRange: 'previous_period', + } + }) + } } }, }); + // with no data - await testUtils.dom.click(pivot.$('.o_time_range_menu_button')); - await testUtils.dom.click(pivot.$('.o_time_range_menu .o_comparison_checkbox')); - pivot.$('.o_time_range_selector').val('today'); - await testUtils.dom.click(pivot.$('.o_time_range_menu .o_apply_range')); + await cpHelpers.toggleTimeRangeMenu(pivot); + await cpHelpers.toggleTimeRangeMenuBox(pivot); + await cpHelpers.selectRange(pivot, 'today'); + await cpHelpers.applyTimeRange(pivot); assert.strictEqual(pivot.$('.o_pivot p.o_view_nocontent_empty_folder').length, 1); // with data, no row groupby - await testUtils.dom.click(pivot.$('.o_time_range_menu_button')); - pivot.$('.o_time_range_selector').val('this_month'); - await testUtils.dom.click(pivot.$('.o_time_range_menu .o_apply_range')); + await cpHelpers.selectRange(pivot, 'this_month'); + await cpHelpers.applyTimeRange(pivot); assert.containsN(pivot, '.o_pivot thead tr:last th', 9, "last header row should contains 9 cells (3*[This month, Previous Period, Variation]"); var values = [ @@ -2035,11 +2042,10 @@ QUnit.module('Views', { ]; assert.strictEqual(getCurrentValues(pivot), values.join()); - pivot.$('.o_search_options button:contains("Favorites")').click(); - var $favorites = pivot.$('.dropdown-menu.o_favorites_menu'); - $favorites.find('a.o_save_search').click(); - $favorites.find('.o_input').val('Fav').trigger('input'); - $favorites.find('button').click(); + await cpHelpers.toggleFavoriteMenu(pivot); + await cpHelpers.toggleSaveFavorite(pivot); + await cpHelpers.editFavoriteName(pivot, 'Fav'); + await cpHelpers.saveFavorite(pivot); unpatchDate(); pivot.destroy(); @@ -2093,14 +2099,15 @@ QUnit.module('Views', { }, }); + // open time range menu - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu_button')); + await cpHelpers.toggleTimeRangeMenu(pivot); // select 'Today' as range - pivot.$('.o_control_panel .o_time_range_selector').val('today'); + await cpHelpers.selectRange(pivot, 'today'); // check checkbox 'Compare To' - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); + await cpHelpers.toggleTimeRangeMenuBox(pivot); // Click on 'Apply' button - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu .o_apply_range')); + await cpHelpers.applyTimeRange(pivot); // the time range menu configuration is by now: Date, Today, checkbox checked, Previous Period // With the data above, the time ranges contain no record. @@ -2109,13 +2116,11 @@ QUnit.module('Views', { // are deactivated (exception: the 'Measures' button). assert.ok(pivot.$('.o_control_panel button.o_pivot_download').prop('disabled')); - // open time range menu - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu_button')); // select 'This Month' as date range - pivot.$('.o_control_panel .o_time_range_selector').val('this_month'); + await cpHelpers.selectRange(pivot, 'this_month'); // Click on 'Apply' button - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu .o_apply_range')); + await cpHelpers.applyTimeRange(pivot); // the time range menu configuration is by now: Date, This Month, checkbox checked, Previous Period // With the data above, the time ranges contain some records. // export data. Should execute 'get_file' @@ -2177,11 +2182,12 @@ QUnit.module('Views', { mockMock = true; + // activate 'This Month' and 'Previous Period' in time range menu - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu_button')); - pivot.$('.o_control_panel .o_time_range_selector').val('this_month'); - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); - await testUtils.dom.click(pivot.$('.o_control_panel .o_time_range_menu .o_apply_range')); + await cpHelpers.toggleTimeRangeMenu(pivot); + await cpHelpers.selectRange(pivot, 'this_month'); + await cpHelpers.toggleTimeRangeMenuBox(pivot); + await cpHelpers.applyTimeRange(pivot); var values = [ "4", "0", "100%", @@ -2219,16 +2225,12 @@ QUnit.module('Views', { }, }); + // enable comparison mode - var $cp = pivot.$('.o_control_panel'); - // open time range menu - await testUtils.dom.click($cp.find('.o_time_range_menu_button')); - // select 'This month' as range - await testUtils.fields.editInput($cp.find('.o_time_range_selector'), 'this_month'); - // check checkbox 'Compare To' - await testUtils.dom.click($cp.find('.o_time_range_menu .o_comparison_checkbox')); - // click on 'Apply' button - await testUtils.dom.click($cp.find('.o_time_range_menu .o_apply_range')); + await cpHelpers.toggleTimeRangeMenu(pivot); + await cpHelpers.selectRange(pivot, 'this_month'); + await cpHelpers.toggleTimeRangeMenuBox(pivot); + await cpHelpers.applyTimeRange(pivot); // initial sanity check var values = [ @@ -2303,6 +2305,7 @@ QUnit.module('Views', { assert.expect(16); // create an action manager to test the interactions with the search view var readGroupCount = 0; + var actionManager = await createActionManager({ data: this.data, archs: { @@ -2322,9 +2325,9 @@ QUnit.module('Views', { mockRPC: function (route, args) { if (args.method === 'read_group') { assert.step('read_group'); - var domain = args.kwargs.domain; + const domain = args.kwargs.domain; if ([0,1].indexOf(readGroupCount) !== -1) { - assert.deepEqual(domain, [], 'initial domain empty'); + assert.deepEqual(domain, [], 'domain empty'); } else if ([2,3,4,5].indexOf(readGroupCount) !== -1) { assert.deepEqual(domain, [['foo', '=', 12]], 'domain conserved when back with breadcrumbs'); @@ -2333,12 +2336,12 @@ QUnit.module('Views', { } if (route === '/web/dataset/search_read') { assert.step('search_read'); - var domain = args.domain; + const domain = args.domain; assert.deepEqual(domain, [['customer', '=', 1], ['foo', '=', 12]], 'list domain is correct'); } return this._super.apply(this, arguments); - } + }, }); await actionManager.doAction({ @@ -2347,20 +2350,23 @@ QUnit.module('Views', { views: [[false, 'pivot']], }); - await testUtilsDom.click(actionManager.$('.o_filters_menu_button')); - await testUtilsDom.click(actionManager.$('.o_menu_item:contains("Bayou")')); - await testUtilsDom.click(actionManager.$('.o_pivot_cell_value:nth(1)')) + await cpHelpers.toggleFilterMenu(actionManager); + await cpHelpers.toggleMenuItem(actionManager, 0); + await testUtils.nextTick(); + + await testUtilsDom.click(actionManager.$('.o_pivot_cell_value:nth(1)')); + await testUtils.nextTick(); assert.containsOnce(actionManager, '.o_list_view'); - await testUtilsDom.click(actionManager.$('.o_control_panel .breadcrumb-item:first() a')); + await testUtilsDom.click(actionManager.$('.o_control_panel ol.breadcrumb li.breadcrumb-item').eq(0)); assert.verifySteps([ 'read_group', 'read_group', 'read_group', 'read_group', 'search_read', - 'read_group', 'read_group']) + 'read_group', 'read_group']); actionManager.destroy(); }); @@ -2387,16 +2393,12 @@ QUnit.module('Views', { }, }); + // enable comparison mode - var $cp = pivot.$('.o_control_panel'); - // open time range menu - await testUtils.dom.click($cp.find('.o_time_range_menu_button')); - // select 'This month' as range - await testUtils.fields.editInput($cp.find('.o_time_range_selector'), 'this_month'); - // check checkbox 'Compare To' - await testUtils.dom.click($cp.find('.o_time_range_menu .o_comparison_checkbox')); - // click on 'Apply' button - await testUtils.dom.click($cp.find('.o_time_range_menu .o_apply_range')); + await cpHelpers.toggleTimeRangeMenu(pivot); + await cpHelpers.selectRange(pivot, 'this_month'); + await cpHelpers.toggleTimeRangeMenuBox(pivot); + await cpHelpers.applyTimeRange(pivot); // initial sanity check var values = [ @@ -2474,8 +2476,7 @@ QUnit.module('Views', { [ '', 'Total', '', '2016-12-15', '2016-12-17', '2016-11-22', '2016-11-03', - ].join('') - , + ].join(''), "The col headers should be as expected" ); assert.strictEqual( @@ -2489,24 +2490,19 @@ QUnit.module('Views', { "The row headers should be as expected" ); + // enable comparison mode - var $cp = pivot.$('.o_control_panel'); - // open time range menu - await testUtils.dom.click($cp.find('.o_time_range_menu_button')); - // select 'This month' as range - await testUtils.fields.editInput($cp.find('.o_time_range_selector'), 'this_month'); - // check checkbox 'Compare To' - await testUtils.dom.click($cp.find('.o_time_range_menu .o_comparison_checkbox')); - // click on 'Apply' button - await testUtils.dom.click($cp.find('.o_time_range_menu .o_apply_range')); + await cpHelpers.toggleTimeRangeMenu(pivot); + await cpHelpers.selectRange(pivot, 'this_month'); + await cpHelpers.toggleTimeRangeMenuBox(pivot); + await cpHelpers.applyTimeRange(pivot); assert.strictEqual( pivot.$('th').slice(0, 7).text(), [ '', 'Total', '', '2016-12-15', '2016-12-17', '2016-11-22', '2016-11-03', - ].join('') - , + ].join(''), "The col headers should be as expected" ); assert.strictEqual( @@ -2551,10 +2547,10 @@ QUnit.module('Views', { QUnit.test('Does not identify "false" with false as keys when creating group trees', async function (assert) { assert.expect(2); - this.data.partner.fields['favorite_animal'] = {string: "Favorite animal", type: "char", store: true} - this.data.partner.records[0]['favorite_animal'] = 'Dog' - this.data.partner.records[1]['favorite_animal'] = 'false' - this.data.partner.records[2]['favorite_animal'] = 'Undefined' + this.data.partner.fields.favorite_animal = {string: "Favorite animal", type: "char", store: true}; + this.data.partner.records[0].favorite_animal = 'Dog'; + this.data.partner.records[1].favorite_animal = 'false'; + this.data.partner.records[2].favorite_animal = 'Undefined'; var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0); var pivot = await createView({ @@ -2571,8 +2567,7 @@ QUnit.module('Views', { pivot.$('th').slice(0, 2).text(), [ '', 'Total', '', - ].join('') - , + ].join(''), "The col headers should be as expected" ); assert.strictEqual( @@ -2595,7 +2590,7 @@ QUnit.module('Views', { QUnit.test('group bys added via control panel and expand Header do not stack', async function (assert) { assert.expect(8); - delete this.data.partner.fields['date']; + delete this.data.partner.fields.date; var pivot = await createView({ View: PivotView, @@ -2624,11 +2619,11 @@ QUnit.module('Views', { "The row headers should be as expected" ); - var $cp = pivot.$('.o_control_panel'); + // open group by menu and add new groupby - await testUtils.dom.click($cp.find('button span.fa-bars')); - await testUtils.dom.click($cp.find('button.o_add_custom_group')); - await testUtils.dom.click($cp.find('button.o_apply_group')); + await cpHelpers.toggleGroupByMenu(pivot); + await cpHelpers.toggleAddCustomGroup(pivot); + await cpHelpers.applyGroup(pivot); assert.strictEqual( pivot.$('th').slice(0, 2).text(), @@ -2670,10 +2665,11 @@ QUnit.module('Views', { "The row headers should be as expected" ); - // open group by menu and add new groupby - await testUtils.dom.click($cp.find('button span.fa-bars')); - await testUtils.dom.click($cp.find('button.o_add_custom_group')); - await testUtils.dom.click($cp.find('button.o_apply_group')); + // open groupby menu generator and add a new groupby + await cpHelpers.toggleGroupByMenu(pivot); + await cpHelpers.toggleAddCustomGroup(pivot); + await cpHelpers.selectGroup(pivot, 'bar'); + await cpHelpers.applyGroup(pivot); assert.strictEqual( pivot.$('th').slice(0, 2).text(), diff --git a/addons/web/static/tests/views/qweb_tests.js b/addons/web/static/tests/views/qweb_tests.js index c7872690e49..19acf9b06c3 100644 --- a/addons/web/static/tests/views/qweb_tests.js +++ b/addons/web/static/tests/views/qweb_tests.js @@ -1,7 +1,6 @@ odoo.define('web.qweb_view_tests', function (require) { "use strict"; -var qweb = require('web.qweb'); var utils = require('web.test_utils'); QUnit.module("Views", { diff --git a/addons/web/static/tests/views/search_filter_menu_tests.js b/addons/web/static/tests/views/search_filter_menu_tests.js deleted file mode 100644 index 62cfaccdc93..00000000000 --- a/addons/web/static/tests/views/search_filter_menu_tests.js +++ /dev/null @@ -1,206 +0,0 @@ -odoo.define('web.search_filters_menu_tests', function (require) { -"use strict"; - -var Domain = require('web.Domain'); -var FilterMenu = require('web.FilterMenu'); -var pyUtils = require('web.py_utils'); -var testUtils = require('web.test_utils'); - -function createFilterMenu(filters, fields, params) { - params = params || {}; - var target = params.debug ? document.body : $('#qunit-fixture'); - var menu = new FilterMenu(null, filters, fields); - testUtils.mock.addMockEnvironment(menu, params); - return menu.appendTo(target).then(function() { - return menu; - }); -} - -QUnit.module('FilterMenu', { - beforeEach: function () { - this.filters = [ - { - isActive: false, - description: 'some filter', - domain: '', - groupNumber: 1, - }, - ]; - this.fields = { - boolean_field: {string: "Boolean Field", type: "boolean", default: true, searchable: true}, - date_field: {string: "A date", type: "date", searchable: true}, - char_field: {string: "Char Field", type: "char", default: "foo", searchable: true, trim: true}, - }; - }, -}, function () { - - QUnit.test('simple rendering with no filter', async function (assert) { - assert.expect(3); - - var filterMenu = await createFilterMenu([], this.fields); - await testUtils.dom.click(filterMenu.$('span.fa-filter')); - assert.containsNone(filterMenu, '.dropdown-divider'); - assert.containsNone(filterMenu, '.o_add_filter_menu'); - assert.containsOnce(filterMenu, '.o_add_custom_filter', - 'should have one element: a add custom filter item'); - filterMenu.destroy(); - }); - - QUnit.test('simple rendering with a filter', async function (assert) { - assert.expect(2); - - var filterMenu = await createFilterMenu(this.filters, this.fields); - assert.containsN(filterMenu, '.dropdown-divider, .dropdown-item, .o_add_custom_filter', 4, - 'should have 4 elements: a hidden separator, a filter, a separator, a add custom filter item'); - assert.containsOnce(filterMenu, '.o_add_custom_filter'); - filterMenu.destroy(); - }); - - QUnit.test('click on add custom filter opens the submenu', async function (assert) { - assert.expect(3); - - var filterMenu = await createFilterMenu([], this.fields); - // open menu dropdown - await testUtils.dom.click(filterMenu.$('span.fa-filter')); - // open add custom filter submenu - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - assert.containsNone(filterMenu, '.dropdown-divider'); - assert.isVisible(filterMenu.$('.o_add_filter_menu')); - assert.containsN(filterMenu, '.dropdown-item, .dropdown-item-text', 3, - 'should have 3 elements: a add custom filter item, a proposition, a apply button + add condition button'); - - filterMenu.destroy(); - }); - - QUnit.test('removing last prop disable the apply button', async function (assert) { - assert.expect(2); - - var filterMenu = await createFilterMenu([], this.fields); - // open menu dropdown and custom filter submenu - await testUtils.dom.click(filterMenu.$('span.fa-filter')); - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - - // remove the current unique proposition - await testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop')); - - assert.containsNone(filterMenu, '.dropdown-divider'); - assert.containsN(filterMenu, '.dropdown-item, .dropdown-item-text', 2, - 'should have 2 elements: a add custom filter item, a apply button + add condition button'); - - filterMenu.destroy(); - }); - - QUnit.test('readding a proposition reenable apply button', async function (assert) { - assert.expect(1); - - var filterMenu = await createFilterMenu([], this.fields); - // open menu dropdown and custom filter submenu, remove existing prop - await testUtils.dom.click(filterMenu.$('span.fa-filter')); - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop')); - // read a proposition - await testUtils.dom.click(filterMenu.$('.o_add_condition')); - assert.ok(!filterMenu.$('.o_apply_filter').attr('disabled')); - - filterMenu.destroy(); - }); - - QUnit.test('adding a simple filter works', async function (assert) { - assert.expect(6); - - delete this.fields.date_field; - var filterMenu = await createFilterMenu([], this.fields, { - intercepts: { - new_filters: function (ev) { - var filter = ev.data.filters[0]; - assert.strictEqual(filter.type, 'filter'); - assert.strictEqual(filter.description, 'Boolean Field is true'); - assert.strictEqual(filter.domain, '[[\"boolean_field\",\"=\",True]]'); - filterMenu.update([{ - isActive: true, - description: '?', - domain: '?', - groupNumber: 1, - }]); - }, - }, - }); - // open menu dropdown and custom filter submenu, remove existing prop - await testUtils.dom.click(filterMenu.$('span.fa-filter')); - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - // click on apply to activate filter - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - assert.containsNone(filterMenu, '.o_filter_condition'); - assert.containsN(filterMenu, '.dropdown-divider', 2); - assert.isNotVisible(filterMenu.$('.dropdown-divider').eq(0)); - filterMenu.destroy(); - }); - - QUnit.test('commit search with an extended proposition with field char does not cause a crash', async function (assert) { - assert.expect(6); - - this.fields = {many2one_field: {string: "Trululu", type: "many2one", relation: 'partner', selectable: true, searchable: true}}; - - var expectedDomains = [ - [['many2one_field','ilike', `a`]], - [['many2one_field','ilike', `"a"`]], - [['many2one_field','ilike', `'a'`]], - [['many2one_field','ilike', `'`]], - [['many2one_field','ilike', `"`]], - [['many2one_field','ilike', `\\`]], - ]; - - var filterMenu = await createFilterMenu([], this.fields, { - intercepts: { - new_filters: function (ev) { - var filter = ev.data.filters[0]; - // this step combine a tokenization/parsing followed by a string formatting - var domain = pyUtils.assembleDomains([filter.domain]); - domain = Domain.prototype.stringToArray(domain); - assert.deepEqual(domain, expectedDomains.shift()); - }, - } - }); - - // open menu dropdown and custom filter submenu, select trululu field and enter string `a`, then click apply - await testUtils.dom.click(filterMenu.$('span.fa-filter')); - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field'); - await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `a`); - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - - - // open custom filter submenu, select trululu field and enter string `"a"`, then click apply - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field'); - await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `"a"`); - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - - // open custom filter submenu, select trululu field and enter string `'a'`, then click apply - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field'); - await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `'a'`); - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - - // open custom filter submenu, select trululu field and enter string `'`, then click apply - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field'); - await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `'`); - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - - // open custom filter submenu, select trululu field and enter string `"`, then click apply - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field'); - await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `"`); - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - - // open custom filter submenu, select trululu field and enter string `\`, then click apply - await testUtils.dom.click(filterMenu.$('.o_add_custom_filter')); - await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field'); - await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `\\`); - await testUtils.dom.click(filterMenu.$('.o_apply_filter')); - - filterMenu.destroy(); - }); -}); -}); diff --git a/addons/web/static/tests/views/search_groupby_menu_tests.js b/addons/web/static/tests/views/search_groupby_menu_tests.js deleted file mode 100644 index 6ff0e7eaf13..00000000000 --- a/addons/web/static/tests/views/search_groupby_menu_tests.js +++ /dev/null @@ -1,200 +0,0 @@ -odoo.define('web.search_groupby_menu_tests', function (require) { -"use strict"; - -var GroupByMenu = require('web.GroupByMenu'); -var testUtils = require('web.test_utils'); -var controlPanelViewParameters = require('web.controlPanelViewParameters'); -var INTERVAL_OPTIONS = controlPanelViewParameters.INTERVAL_OPTIONS; - -function createGroupByMenu(groupBys, fields, params) { - params = params || {}; - var target = params.debug ? document.body : $('#qunit-fixture'); - var menu = new GroupByMenu(null, groupBys, fields); - testUtils.mock.addMockEnvironment(menu, params); - return menu.appendTo(target).then(function() { - return menu; - }); -} - -QUnit.module('GroupByMenu', { - beforeEach: function () { - this.groupBys = [ - { - description: 'some group by', - groupNumber: 1, - isActive: false, - }, - ]; - this.fields = { - fieldName: {sortable: true, string: 'Super Date', type: 'date'} - }; - }, -}, function () { - - QUnit.test('simple rendering with no filter and no field', async function (assert) { - assert.expect(1); - - var groupByMenu = await createGroupByMenu([], {}); - // open groupBy menu - testUtils.dom.click(groupByMenu.$('button:first')); - assert.containsNone(groupByMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', - 'should have 0 element'); - - groupByMenu.destroy(); - }); - - QUnit.test('simple rendering', async function (assert) { - assert.expect(2); - - var groupByMenu = await createGroupByMenu(this.groupBys, this.fields); - // open groupBy menu - await testUtils.dom.click(groupByMenu.$('button:first')); - assert.containsN(groupByMenu, '.dropdown-divider, .dropdown-item', 4); - assert.strictEqual(groupByMenu.$('.o_menu_item').text().trim(), 'some group by', - 'should have proper filter name'); - - groupByMenu.destroy(); - }); - - QUnit.test('simple rendering with no filter but fields', async function (assert) { - assert.expect(1); - - var groupByMenu = await createGroupByMenu( - [], - {fieldName: {sortable: true, string: 'Super Date', type: 'date'}} - ); - await testUtils.nextTick(); - await testUtils.dom.click(groupByMenu.$('button:first')); - assert.containsOnce(groupByMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 'should have 1 element'); - - groupByMenu.destroy(); - }); - - QUnit.test('click on add custom group toggle group selector', async function (assert) { - assert.expect(2); - - var groupByMenu = await createGroupByMenu([], - {fieldName: {sortable: true, string: 'Super Date', type: 'date'}} - ); - await testUtils.dom.click(groupByMenu.$('button:first')); - var selector = groupByMenu.$('select.o_group_selector'); - assert.ok(!selector.is(":visible"), 'should be invisible'); - await testUtils.dom.click(groupByMenu.$('.o_add_custom_group')); - selector = groupByMenu.$('select.o_group_selector'); - assert.ok(selector.is(":visible"), 'should be visible'); - - groupByMenu.destroy(); - }); - - QUnit.test('select a groupBy of no date type in Add Custom Group menu add properly that groupBy to menu', async function (assert) { - assert.expect(6); - - var groupByMenu = await createGroupByMenu( - [], - { - fieldName: {sortable: true, name: 'candlelight', string: 'Candlelight', type: 'boolean'}, - }, - { - intercepts: { - new_groupBy: function (ev) { - assert.strictEqual(ev.data.description, 'Candlelight'); - assert.strictEqual(ev.data.fieldName, 'fieldName'); - assert.strictEqual(ev.data.fieldType, 'boolean'); - assert.strictEqual(ev.data.type, 'groupBy'); - groupByMenu.update([{ - description: 'Candlelight', - groupNumber: 1, - isActive: true, - }]); - }, - }, - } - ); - await testUtils.nextTick(); - await testUtils.dom.click(groupByMenu.$('button:first')); - await testUtils.dom.click(groupByMenu.$('.o_add_custom_group')); - assert.strictEqual(groupByMenu.$('select').val(), 'fieldName', - 'the select value should be "fieldName"'); - await testUtils.dom.click(groupByMenu.$('button.o_apply_group')); - assert.containsOnce(groupByMenu, '.o_menu_item > .dropdown-item.selected', 'there should be a groupby selected'); - groupByMenu.destroy(); - }); - - QUnit.test('select a groupBy of date type in Add Custom Group menu add properly that groupBy to menu', async function (assert) { - assert.expect(13); - - INTERVAL_OPTIONS = INTERVAL_OPTIONS.map(function (option) { - return _.extend(option, {description: option.description.toString()}); - }); - - var groupByMenu = await createGroupByMenu( - [], - this.fields, - { - intercepts: { - new_groupBy: function (ev) { - assert.strictEqual(ev.data.description, 'Super Date'); - assert.strictEqual(ev.data.fieldName, 'fieldName'); - assert.strictEqual(ev.data.fieldType, 'date'); - assert.strictEqual(ev.data.type, 'groupBy'); - assert.strictEqual(ev.data.hasOptions, true); - assert.deepEqual(ev.data.options, controlPanelViewParameters.INTERVAL_OPTIONS); - assert.strictEqual(ev.data.defaultOptionId, controlPanelViewParameters.DEFAULT_INTERVAL); - assert.strictEqual(ev.data.currentOptionIds.size, 0); - groupByMenu.update([{ - description: 'Super Date', - fieldName: 'fieldName', - groupNumber: 1, - isActive: true, - hasOptions: true, - options: controlPanelViewParameters.INTERVAL_OPTIONS, - currentOptionIds: new Set([controlPanelViewParameters.DEFAULT_INTERVAL]), - }]); - }, - }, - } - ); - // open groupBy menu - await testUtils.dom.click(groupByMenu.$('button:first')); - // open Add Custom Group submenu - await testUtils.dom.click(groupByMenu.$('.o_add_custom_group')); - // select fieldName - assert.strictEqual(groupByMenu.$('select').val(), 'fieldName', - 'the select value should be "fieldName"'); - // create new groupBy of type date - await testUtils.dom.click(groupByMenu.$('button.o_apply_group')); - assert.strictEqual(groupByMenu.$('.o_menu_item > .dropdown-item.selected').length, 1, - 'there should be a groupby selected'); - assert.strictEqual(groupByMenu.$('.o_menu_item .o_submenu_switcher').length, 1, - 'there should be options available'); - // open options submenu - await testUtils.dom.click(groupByMenu.$('.o_menu_item .o_submenu_switcher')); - assert.strictEqual(groupByMenu.$('.o_item_option').length, 5, - 'there should be five options available'); - assert.strictEqual(groupByMenu.$('.o_add_custom_group').length, 0, - 'there should be no more a Add Custome Group submenu'); - - groupByMenu.destroy(); - }); - - QUnit.test('custom group by dropdown should not have ID field', async function (assert) { - assert.expect(2); - - this.fields.id = {sortable: true, string: 'ID', type: 'integer'}; - - var groupByMenu = await createGroupByMenu([], this.fields); - // open groupBy menu - await testUtils.dom.click(groupByMenu.$('button:first')); - // open Add Custom Group submenu - await testUtils.dom.click(groupByMenu.$('.o_add_custom_group')) - - assert.containsOnce(groupByMenu, '.o_group_selector option', - 'groupby menu should have only one option'); - // custom group by should not have 'ID' field - assert.containsNone(groupByMenu, '.o_group_selector option[value="id"]', - 'id field should not be in custom group by'); - - groupByMenu.destroy(); - }); -}); -}); diff --git a/addons/web/static/tests/views/search_panel_tests.js b/addons/web/static/tests/views/search_panel_tests.js index 632158d9b1e..11cf8b03513 100644 --- a/addons/web/static/tests/views/search_panel_tests.js +++ b/addons/web/static/tests/views/search_panel_tests.js @@ -7,6 +7,7 @@ var KanbanView = require('web.KanbanView'); var RamStorage = require('web.RamStorage'); var testUtils = require('web.test_utils'); +const cpHelpers = testUtils.controlPanel; var createActionManager = testUtils.createActionManager; var createView = testUtils.createView; @@ -1396,7 +1397,7 @@ QUnit.module('Views', { ]); // go to page 2 (the domain doesn't change, so the filters should not be reloaded) - await testUtils.dom.click(kanban.$('.o_pager_next')); + await cpHelpers.pagerNext(kanban); assert.verifySteps([ '/web/dataset/search_read', @@ -1935,16 +1936,17 @@ QUnit.module('Views', { archs: this.archs, data: this.data, }); - await actionManager.doAction(1); + assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_kanban_view'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_search_panel'); - await testUtils.dom.click(actionManager.$('.o_cp_switch_pivot')); + await cpHelpers.switchView(actionManager, 'pivot'); + await testUtils.nextTick(); assert.containsOnce(actionManager, '.o_content .o_pivot'); assert.containsNone(actionManager, '.o_content .o_search_panel'); - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_list_view'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_search_panel'); @@ -1972,16 +1974,16 @@ QUnit.module('Views', { archs: this.archs, data: this.data, }); - await actionManager.doAction(1); + assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_kanban_view'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_search_panel'); - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_content .o_list_view'); assert.containsNone(actionManager, '.o_content .o_search_panel'); - await testUtils.dom.click(actionManager.$('.o_cp_switch_pivot')); + await cpHelpers.switchView(actionManager, 'pivot'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_pivot'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_search_panel'); @@ -2003,8 +2005,8 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - await actionManager.doAction(1); + assert.hasClass(actionManager.$('.o_search_panel_category_value:first header'), 'active'); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 4); @@ -2013,7 +2015,7 @@ QUnit.module('Views', { assert.hasClass(actionManager.$('.o_search_panel_category_value:nth(1) header'), 'active'); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 2); - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.hasClass(actionManager.$('.o_search_panel_category_value:nth(1) header'), 'active'); assert.containsN(actionManager, '.o_data_row', 2); @@ -2022,7 +2024,7 @@ QUnit.module('Views', { assert.hasClass(actionManager.$('.o_search_panel_category_value:nth(2) header'), 'active'); assert.containsN(actionManager, '.o_data_row', 2); - await testUtils.dom.click(actionManager.$('.o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.hasClass(actionManager.$('.o_search_panel_category_value:nth(2) header'), 'active'); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 2); @@ -2052,8 +2054,8 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - await actionManager.doAction(1); + assert.containsNone(actionManager, '.o_search_panel_filter_value input:checked'); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 4); @@ -2062,7 +2064,7 @@ QUnit.module('Views', { assert.containsOnce(actionManager, '.o_search_panel_filter_value input:checked'); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 1); - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_search_panel_filter_value input:checked'); assert.containsN(actionManager, '.o_data_row', 1); @@ -2071,7 +2073,7 @@ QUnit.module('Views', { assert.containsN(actionManager, '.o_search_panel_filter_value input:checked', 2); assert.containsN(actionManager, '.o_data_row', 4); - await testUtils.dom.click(actionManager.$('.o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.containsN(actionManager, '.o_search_panel_filter_value input:checked', 2); assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 4); @@ -2094,8 +2096,8 @@ QUnit.module('Views', { archs: this.archs, data: this.data, }); - await actionManager.doAction(1); + assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_kanban_view'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_search_panel'); assert.containsNone(actionManager, '.o_search_panel_filter_value input:checked'); @@ -2107,13 +2109,13 @@ QUnit.module('Views', { assert.containsN(actionManager, '.o_kanban_record:not(.o_kanban_ghost)', 1); // switch to pivot - await testUtils.dom.click(actionManager.$('.o_cp_switch_pivot')); + await cpHelpers.switchView(actionManager, 'pivot'); assert.containsOnce(actionManager, '.o_content .o_pivot'); assert.containsNone(actionManager, '.o_content .o_search_panel'); assert.strictEqual(actionManager.$('.o_pivot_cell_value').text(), '15'); // switch to list - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_list_view'); assert.containsOnce(actionManager, '.o_content.o_controller_with_searchpanel .o_search_panel'); assert.containsOnce(actionManager, '.o_search_panel_filter_value input:checked'); @@ -2192,10 +2194,10 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, }); - await actionManager.doAction(1); - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); - await testUtils.dom.click(actionManager.$('.o_cp_switch_kanban')); + + await cpHelpers.switchView(actionManager, 'list'); + await cpHelpers.switchView(actionManager, 'kanban'); assert.verifySteps([ '/web/action/load', @@ -2226,18 +2228,19 @@ QUnit.module('Views', { actionManager.$el.css('max-height', 300); await actionManager.doAction(1); + assert.containsOnce(actionManager, '.o_content .o_kanban_view'); assert.strictEqual(actionManager.$('.o_search_panel').scrollTop(), 0); // simulate a scroll in the search panel and switch into list actionManager.$('.o_search_panel').scrollTop(50); - await testUtils.dom.click(actionManager.$('.o_cp_switch_list')); + await cpHelpers.switchView(actionManager, 'list'); assert.containsOnce(actionManager, '.o_content .o_list_view'); assert.strictEqual(actionManager.$('.o_search_panel').scrollTop(), 50); // simulate another scroll and switch back to kanban actionManager.$('.o_search_panel').scrollTop(30); - await testUtils.dom.click(actionManager.$('.o_cp_switch_kanban')); + await cpHelpers.switchView(actionManager, 'kanban'); assert.containsOnce(actionManager, '.o_content .o_kanban_view'); assert.strictEqual(actionManager.$('.o_search_panel').scrollTop(), 30); diff --git a/addons/web/static/tests/views/search_view_tests.js b/addons/web/static/tests/views/search_view_tests.js deleted file mode 100644 index 5dbf8361628..00000000000 --- a/addons/web/static/tests/views/search_view_tests.js +++ /dev/null @@ -1,1928 +0,0 @@ -odoo.define('web.search_view_tests', function (require) { -"use strict"; - -var FormView = require('web.FormView'); -var GraphView = require('web.GraphView'); -var testUtils = require('web.test_utils'); - -var createActionManager = testUtils.createActionManager; -var createControlPanel = testUtils.createControlPanel; -var createView = testUtils.createView; -var patchDate = testUtils.mock.patchDate; -var session = require('web.session'); - -var controlPanelViewParameters = require('web.controlPanelViewParameters'); -const PERIOD_OPTIONS_IDS = controlPanelViewParameters.PERIOD_OPTIONS.map(o => o.optionId); -const OPTION_GENERATOR_IDS = controlPanelViewParameters.OPTION_GENERATORS.map(o => o.optionId); - -QUnit.module('Search View', { - beforeEach: function () { - this.data = { - partner: { - fields: { - date_field: {string: "Date", type: "date", store: true, sortable: true}, - birthday: {string: "Birthday", type: "date", store: true, sortable: true}, - foo: {string: "Foo", type: "char", store: true, sortable: true}, - bar: {string: "Bar", type: "many2one", relation: 'partner'}, - float_field: {string: "Float", type: "float", group_operator: 'sum'}, - }, - records: [ - {id: 1, display_name: "First record", foo: "yop", bar: 2, date_field: "2017-01-25", birthday: "1983-07-15", float_field: 1}, - {id: 2, display_name: "Second record", foo: "blip", bar: 1, date_field: "2017-01-24", birthday: "1982-06-04",float_field: 2}, - {id: 3, display_name: "Third record", foo: "gnap", bar: 1, date_field: "2017-01-13", birthday: "1985-09-13",float_field: 1.618}, - {id: 4, display_name: "Fourth record", foo: "plop", bar: 2, date_field: "2017-02-25", birthday: "1983-05-05",float_field: -1}, - {id: 5, display_name: "Fifth record", foo: "zoup", bar: 2, date_field: "2016-01-25", birthday: "1800-01-01",float_field: 13}, - ], - }, - pony: { - fields: { - name: {string: 'Name', type: 'char'}, - }, - records: [ - {id: 4, name: 'Twilight Sparkle'}, - {id: 6, name: 'Applejack'}, - {id: 9, name: 'Fluttershy'} - ], - }, - }; - - this.actions = [{ - id: 1, - name: 'Partners Action 1', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'list']], - }, { - id: 2, - name: 'Partners Action 2', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'list']], - search_view_id: [2, 'search'], - }, { - id: 3, - name: 'Partners Action 3', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'kanban']], - search_view_id: [2, 'search'], - }, { - id: 4, - name: 'Partners Action 4', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'graph']], - search_view_id: [3, 'search'], - }, { - id: 5, - name: 'Partners Action 5', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[2, 'list']], - search_view_id: [4, 'search'], - }, { - id: 6, - name: 'Partners Action 6', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[2, 'list']], - search_view_id: [5, 'search'], - }, { - id: 7, - name: 'Partners Action 7', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[2, 'list']], - search_view_id: [6, 'search'], - }, { - id: 8, - name: 'Partners Action 8', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[2, 'list']], - search_view_id: [7, 'search'], - }, { - id: 9, - name: 'Partners Action 9', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'pivot']], - search_view_id: [5, 'search'], - }, { - id: 10, - name: 'Partners Action 10', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'pivot']], - search_view_id: [8, 'search'], - }, { - id: 11, - name: 'Partners Action 11', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[2, 'list']], - search_view_id: [8, 'search'], - }, { - id: 12, - name: 'Partners Action 12', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[2, 'list']], - search_view_id: [9, 'search'], - } - ]; - - this.archs = { - // list views - 'partner,false,list': '<tree><field name="foo"/></tree>', - 'partner,2,list': '<tree><field name="foo"/></tree>', - - // kanban views - 'partner,false,kanban': '<kanban><templates><t t-name="kanban-box">' + - '<div class="oe_kanban_global_click"><field name="foo"/></div>' + - '</t></templates></kanban>', - - // graph views - 'partner,false,graph': '<graph>' + - '<field name="date_field" type="row" interval="day"/>' + - '<field name="float_field" type="measure"/>' + - '</graph>', - - // pivot views - 'partner,false,pivot': '<pivot>' + - '<field name="date_field" type="row" interval="day"/>' + - '<field name="float_field" type="measure"/>' + - '</pivot>', - - // search views - 'partner,false,search': '<search>'+ - '<filter string="candle" name="itsName" context="{\'group_by\': \'foo\'}"/>' + - '</search>', - 'partner,2,search': '<search>'+ - '<filter string="Date" name="coolName" context="{\'group_by\': \'date_field\'}"/>' + - '</search>', - 'partner,3,search': '<search>'+ - '<filter string="float" name="positive" domain="[(\'float_field\', \'>=\', 0)]"/>' + - '</search>', - 'partner,4,search': '<search>'+ - '<filter string="Date" name="coolName" context="{\'group_by\': \'date_field:day\'}"/>' + - '</search>', - 'partner,5,search': '<search>'+ - '<filter string="Date Field Filter" name="positive" date="date_field"/>' + - '<filter string="Date Field Groupby" name="coolName" context="{\'group_by\': \'date_field:day\'}"/>' + - '</search>', - 'partner,6,search': '<search>'+ - '<filter string="Date" name="coolName" context="{\'group_by\': \'date_field:day\'}"/>' + - '<separator/>' + - '<filter string="Bar" name="superName" context="{\'group_by\': \'bar\'}"/>' + - '</search>', - 'partner,7,search': '<search>'+ - '<filter string="1" name="coolName1" date="date_field"/>' + - '<separator/>' + - '<filter string="2" name="coolName2" date="birthday"/>' + - '<separator/>' + - '<filter string="3" name="coolName3" domain="[]"/>' + - '<separator/>' + - '<filter string="4" name="coolName4" domain="[]"/>' + - '<separator/>' + - '<filter string="5" name="coolName5" domain="[]"/>' + - '<separator/>' + - '<filter string="6" name="coolName6" domain="[]"/>' + - '<separator/>' + - '<filter string="7" name="coolName7" domain="[]"/>' + - '<separator/>' + - '<filter string="8" name="coolName8" domain="[]"/>' + - '<separator/>' + - '<filter string="9" name="coolName9" domain="[]"/>' + - '<separator/>' + - '<filter string="10" name="coolName10" domain="[]"/>' + - '<separator/>' + - '<filter string="11" name="coolName11" domain="[]"/>' + - '</search>', - 'partner,8,search': '<search>'+ - '<field name="foo"/>' + - '<field name="date_field"/>' + - '<field name="birthday"/>' + - '<field name="bar" context="{\'bar\': self}"/>' + - '<field name="float_field"/>' + - '<filter string="Date Field Filter" name="positive" date="date_field"/>' + - '<filter string="Date Field Groupby" name="coolName" context="{\'group_by\': \'date_field:day\'}"/>' + - '</search>', - 'partner,9,search': '<search>'+ - '<filter string="float" name="positive" domain="[(\'date_field\', \'>=\', (context_today() + relativedelta()).strftime(\'%Y-%m-%d\'))]"/>' + - '</search>', - 'partner,10,search': '<search>'+ - '<field string="Foo" name="foo"/>' + - '<filter string="Date Field Filter" name="positive" date="date_field"/>' + - '<filter string="Date Field Groupby" name="coolName" context="{\'group_by\': \'date_field:day\'}"/>' + - '</search>', - }; - - - // assuming that the current time is: 2017-03-22:01:00:00 - this.periodDomains = [ - // last 7 days (whole days) - ['&', ["date_field", ">=", "2017-03-15"],["date_field", "<", "2017-03-22"]], - // last 30 days - ['&', ["date_field", ">=", "2017-02-20"],["date_field", "<", "2017-03-22"]], - // last 365 days - ['&', ["date_field", ">=", "2016-03-22"],["date_field", "<", "2017-03-22"]], - // last 5 years - ['&', ["date_field", ">=", "2012-03-22"],["date_field", "<", "2017-03-22"]], - // today - ['&', ["date_field", ">=", "2017-03-22"],["date_field", "<", "2017-03-23"]], - // this week - ['&', ["date_field", ">=", "2017-03-20"],["date_field", "<", "2017-03-27"]], - // this month - ['&', ["date_field", ">=", "2017-03-01"],["date_field", "<", "2017-04-01"]], - // this quarter - ['&', ["date_field", ">=", "2017-01-01"],["date_field", "<", "2017-04-01"]], - // this year - ['&', ["date_field", ">=", "2017-01-01"],["date_field", "<", "2018-01-01"]], - // yesterday - ['&', ["date_field", ">=", "2017-03-21"],["date_field", "<", "2017-03-22"]], - // last week - ['&', ["date_field", ">=", "2017-03-13"],["date_field", "<", "2017-03-20"]], - // last month - ['&', ["date_field", ">=", "2017-02-01"],["date_field", "<", "2017-03-01"]], - // last quarter - ['&', ["date_field", ">=", "2016-10-01"],["date_field", "<", "2017-01-01"]], - // last year - ['&', ["date_field", ">=", "2016-01-01"],["date_field", "<", "2017-01-01"]], - ]; - - this.basicDomains = [ - ["&",["date_field",">=","2017-03-01"],["date_field","<=","2017-03-31"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"]], - ["&",["date_field",">=","2017-02-01"],["date_field","<=","2017-02-28"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-01-31"]], - ["|", - "&",["date_field",">=","2017-01-01"],["date_field","<=","2017-01-31"], - "&",["date_field",">=","2017-10-01"],["date_field","<=","2017-12-31"] - ], - ["&",["date_field",">=","2017-10-01"],["date_field","<=","2017-12-31"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-03-31"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"]], - ["&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"]], - ["|", - "&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"], - "&",["date_field",">=","2016-01-01"],["date_field","<=","2016-12-31"] - ], - ["|", - "|", - "&",["date_field",">=","2017-01-01"],["date_field","<=","2017-12-31"], - "&",["date_field",">=","2016-01-01"],["date_field","<=","2016-12-31"], - "&",["date_field",">=","2015-01-01"],["date_field","<=","2015-12-31"] - ], - ["|", - "|", - "&", ["date_field",">=","2017-03-01"],["date_field","<=","2017-03-31"], - "&",["date_field",">=","2016-03-01"],["date_field","<=","2016-03-31"], - "&",["date_field",">=","2015-03-01"],["date_field","<=","2015-03-31"] - ] - ]; - - // assuming that the current time is: 2017-03-22:01:00:00 - this.previousPeriodDomains = [ - // last 7 days (whole days) - 1 week - ['&', ["date_field", ">=", "2017-03-08"],["date_field", "<", "2017-03-15"]], - // last 30 days - 30 days - ['&', ["date_field", ">=", "2017-01-21"],["date_field", "<", "2017-02-20"]], - // last 365 days - ['&', ["date_field", ">=", "2015-03-23"],["date_field", "<", "2016-03-22"]], - // last 5 years - ['&', ["date_field", ">=", "2007-03-22"],["date_field", "<", "2012-03-22"]], - // today - 1 day - ['&', ["date_field", ">=", "2017-03-21"],["date_field", "<", "2017-03-22"]], - // this week - 1 week - ['&', ["date_field", ">=", "2017-03-13"],["date_field", "<", "2017-03-20"]], - // this month - 1 month - ['&', ["date_field", ">=", "2017-02-01"],["date_field", "<", "2017-03-01"]], - // this quarter - 3 months - ['&', ["date_field", ">=", "2016-10-01"],["date_field", "<", "2017-01-01"]], - // this year - 1 year - ['&', ["date_field", ">=", "2016-01-01"],["date_field", "<", "2017-01-01"]], - // yesterday - 1 day - ['&', ["date_field", ">=", "2017-03-20"],["date_field", "<", "2017-03-21"]], - // last week - 1 week - ['&', ["date_field", ">=", "2017-03-06"],["date_field", "<", "2017-03-13"]], - // last month - 1 month - ['&', ["date_field", ">=", "2017-01-01"],["date_field", "<", "2017-02-01"]], - // last quarter - 3 months - ['&', ["date_field", ">=", "2016-07-01"],["date_field", "<", "2016-10-01"]], - // last year - 1 year - ['&', ["date_field", ">=", "2015-01-01"],["date_field", "<", "2016-01-01"]], - ]; - }, -}, function () { - QUnit.test('basic rendering', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - await actionManager.doAction(1); - - assert.strictEqual($('.o_searchview input.o_searchview_input')[0], document.activeElement, - "searchview input should be focused"); - - actionManager.destroy(); - }); - QUnit.test('navigation with facets', async function (assert) { - assert.expect(4); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - await actionManager.doAction(1); - - // add a facet - await testUtils.dom.click(actionManager.$('.o_dropdown_toggler_btn:contains(Group By)')); - await testUtils.dom.click(actionManager.$('.o_menu_item a')); - assert.strictEqual(actionManager.$('.o_searchview .o_searchview_facet').length, 1, - "there should be one facet"); - assert.strictEqual(actionManager.$('.o_searchview input.o_searchview_input')[0], document.activeElement, - "searchview input should be focused"); - - // press left to focus the facet - actionManager.$('.o_searchview_input_container').trigger($.Event('keydown', { - which: $.ui.keyCode.LEFT, - keyCode: $.ui.keyCode.LEFT, - })); - assert.strictEqual(actionManager.$('.o_searchview .o_searchview_facet')[0], document.activeElement, - "the facet should be focused"); - - // press right to focus the facet - actionManager.$('.o_searchview_input_container').trigger($.Event('keydown', { - which: $.ui.keyCode.RIGHT, - keyCode: $.ui.keyCode.RIGHT, - })); - assert.strictEqual(actionManager.$('.o_searchview input.o_searchview_input')[0], document.activeElement, - "searchview input should be focused"); - - actionManager.destroy(); - }); - - QUnit.test('default groupbys can be ordered', async function (assert) { - assert.expect(7); - - const unpatchDate = patchDate(2019,6,31,13,43,0); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - this.archs['partner,5,search'] = - '<search>'+ - '<field name="bar"/>' + - '<filter string="Foo" name="foo" domain="[]" />' + - '<filter string="Foo 2" name="foo_2" domain="[]" />' + - '<filter string="Filter Date Field" name="date" date="date_field"/>' + - '<filter string="Groupby Date Field Day" name="gb_day" context="{\'group_by\': \'date_field:day\'}"/>' + - '<filter string="Groupby Foo" name="gb_foo" context="{\'group_by\': \'foo\'}"/>' + - '<filter string="Groupby Bar" name="gb_bar" context="{\'group_by\': \'bar\'}"/>' + - '</search>'; - this.actions[0].views = [[false, 'graph']], - this.actions[0].search_view_id = [5, 'search']; - this.actions[0].context = { - search_default_foo: true, - search_default_date: true, - search_default_bar: 3, - search_default_gb_foo: 1, - search_default_gb_day: 5, - search_default_gb_bar: true, - time_ranges: {field: 'date_field', range: 'this_week'}, - }; - await actionManager.doAction(1); - - const $facetValues = $('.o_searchview .o_searchview_facet .o_facet_values span:not(.o_facet_values_sep)'); - const expectedLabels = [ - "Third record", - "Foo", - "Filter Date Field: July 2019", - "Groupby Foo", - "Groupby Date Field Day: Day", - "Groupby Bar", - "Date: This Week" - ]; - - for (let i = 0; i < expectedLabels.length; i++) { - assert.strictEqual($facetValues.eq(i).text(), expectedLabels[i], - `first facet value should be ${expectedLabels[i]}`); - } - actionManager.destroy(); - unpatchDate(); - }); - - QUnit.module('GroupByMenu'); - - QUnit.test('click on groupby filter adds a facet', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(1); - await testUtils.dom.click($('.o_dropdown_toggler_btn:contains(Group By)')); - await testUtils.dom.click($('.o_menu_item a')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'candle', - 'should have a facet with candle name'); - - actionManager.destroy(); - }); - - QUnit.test('remove a "Group By" facet properly unchecks groupbys in groupby menu', async function (assert) { - assert.expect(2); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(1); - await testUtils.dom.click($('.o_dropdown_toggler_btn:contains(Group By)')); - await testUtils.dom.click($('.o_menu_item a')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'candle', - 'should have a facet with candle name'); - await testUtils.dom.click($('.o_facet_remove:first')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0, - 'there should be no facet'); - actionManager.destroy(); - }); - - QUnit.test('change option of a "Group By" does not remove groupy in facet "Group By"', async function (assert) { - assert.expect(3); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(2); - await testUtils.dom.click($('span.fa-bars')); - await testUtils.dom.click($('.o_submenu_switcher')); - // Don't forget there is a hidden li.divider element at first place among children - await testUtils.dom.click($('.o_item_option:nth-child(2)')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 1, - 'should have a facet'); - await testUtils.dom.click($('.o_item_option:nth-child(3)')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 3, - 'should have three facet spans (two options and a separator between them)'); - await testUtils.dom.click($('.o_item_option:nth-child(2)')); - await testUtils.dom.click($('.o_item_option:nth-child(3)')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0, - 'should have no facet'); - actionManager.destroy(); - }); - - QUnit.test('select and unselect quickly groupby does not crash', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(3); - await testUtils.dom.click($('span.fa-bars')); - await testUtils.dom.click($('.o_menu_item:first')); - await testUtils.dom.click($('.o_menu_item:first')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0, - 'should have a facet'); - actionManager.destroy(); - }); - - QUnit.test('groupby selected within graph subview are not deleted when modifying search view content', async function (assert) { - assert.expect(2); - - this.actions[3].flags = {isEmbedded: true}; - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - await actionManager.doAction(4); - await testUtils.dom.click($('.o_graph_controller .o_control_panel .o_cp_buttons button').eq(1)); - await testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item').eq(1)); - await testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item .o_item_option > .dropdown-item').eq(4)); - assert.doesNotHaveClass($('.o_graph_controller .o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected', - 'groupby should be unselected'); - await testUtils.dom.click($('.o_search_options button span.fa-filter')); - await testUtils.dom.click($('.o_filters_menu .o_menu_item a').first()); - await testUtils.dom.click($('.o_graph_controller .o_control_panel .o_cp_buttons button').eq(1)); - await testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item').eq(1)); - assert.doesNotHaveClass($('.o_graph_controller .o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected', - 'groupby should be still unselected'); - actionManager.destroy(); - }); - - QUnit.test('group by a date field using interval works', async function (assert) { - assert.expect(13); - - - var groupbys = [ - ["date_field:day"], - ["date_field:month"], - ["birthday:month"], - ["birthday:year"], - ]; - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - if (route === '/web/dataset/call_kw/partner/web_read_group') { - assert.deepEqual(args.kwargs.groupby, groupbys.shift()); - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(5); - // open menu 'Group By' - await testUtils.dom.click($('.o_search_options .fa-bars')); - // Open the groupby 'Date' - await testUtils.dom.click($('.o_group_by_menu .o_menu_item')); - // select option 'day' - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]')); - assert.strictEqual($('div.o_facet_values span').text().trim(),'Date: Day'); - assert.strictEqual($('.o_content tr.o_group_header').length, 5); - // select option 'month' - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]')); - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]')); - // data should be grouped by the field 'Date' using the interval 'month' - assert.strictEqual($('div.o_facet_values span').text().trim(),'Date: Month'); - assert.strictEqual($('.o_content tr.o_group_header').length, 3); - // deactivate option 'month' - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]')); - // no groupby is applied - assert.strictEqual($('div.o_facet_values span').length, 0); - // open 'Add custom Groupby' menu - await testUtils.dom.click($('.o_group_by_menu .o_add_custom_group')); - // click on 'Apply' button - await testUtils.dom.click($('.o_group_by_menu .o_generator_menu button')); - // data should be grouped by the field 'Birthday' using the interval 'month' - assert.strictEqual($('div.o_facet_values span').text().trim(),'Birthday: Month'); - assert.strictEqual($('.o_content tr.o_group_header').length, 5); - // close first submenu - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_submenu_switcher').eq(0)); - // open submenu with interval options - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_submenu_switcher').eq(1)); - // deselect option 'month' - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]')); - // select option 'year' - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option').eq(0)); - // data should be grouped by the field 'Birthday' using the interval 'year' - assert.strictEqual($('div.o_facet_values span').text().trim(),'Birthday: Year'); - assert.strictEqual($('.o_content tr.o_group_header').length, 4); - - actionManager.destroy(); - }); - - QUnit.test('group by a date field using interval works', async function (assert) { - assert.expect(8); - - var pivot = await createView({ - View: GraphView, - model: "partner", - groupBy:['bar'], - data: this.data, - arch: '<graph/>', - archs: { - 'partner,false,search': `<search> - <filter string="Bar" name="superName" context="{'group_by': 'bar'}"/> - <filter string="Date" name="coolName" context="{'group_by': 'date_field'}"/> - <filter string="Foo" name="superName" context="{'group_by': 'foo'}"/> - </search>` - }, - }); - - function getFacetTexts() { - return [...pivot.el.querySelectorAll('div.o_facet_values span')].map( - e => e.innerText - ).join(' '); - }; - - // open menu 'Group By' - await testUtils.dom.click(pivot.el.querySelector('.o_search_options .fa-bars')); - // select 'Bar' - await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[0]); - assert.strictEqual(getFacetTexts(), 'Bar'); - - // Open the groupby 'Date' - await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[1]); - // select option 'week' - await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="week"]')); - assert.strictEqual(getFacetTexts(), 'Bar > Date: Week'); - - // select option 'day' - await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]')); - assert.strictEqual(getFacetTexts(), 'Bar > Date: Week > Date: Day'); - - // select option 'year' - await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="year"]')); - assert.strictEqual(getFacetTexts(), 'Bar > Date: Year > Date: Week > Date: Day'); - - // select 'Foo' - await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[2]); - assert.strictEqual(getFacetTexts(), 'Bar > Date: Year > Date: Week > Date: Day > Foo'); - - // select option 'quarter' - await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="quarter"]')); - assert.strictEqual(getFacetTexts(), 'Bar > Date: Year > Date: Quarter > Date: Week > Date: Day > Foo'); - - // unselect 'Bar' - await testUtils.dom.click(pivot.el.querySelectorAll('.o_group_by_menu .o_menu_item')[0]); - assert.strictEqual(getFacetTexts(), 'Date: Year > Date: Quarter > Date: Week > Date: Day > Foo'); - - // unselect option 'week' - await testUtils.dom.click(pivot.el.querySelector('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="week"]')); - assert.strictEqual(getFacetTexts(), 'Date: Year > Date: Quarter > Date: Day > Foo'); - - pivot.destroy(); - }); - - QUnit.test('a separator in groupbys does not cause problems', async function (assert) { - assert.expect(6); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(7); - // open menu 'Group By' - await testUtils.dom.click($('span.fa-bars')); - // open options menu - await testUtils.dom.click($('.o_group_by_menu .o_menu_item a:first')); - // activate groupby with 'day' option - await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]')); - // activate the second groupby - await testUtils.dom.click($('.o_group_by_menu .o_menu_item > a').eq(1)); - assert.strictEqual($('.o_group_by_menu .o_menu_item').length, 2); - assert.strictEqual($('.o_group_by_menu .o_menu_item > .dropdown-item.selected').length, 2); - // deactivate second groupby - await testUtils.dom.click($('.o_group_by_menu .o_menu_item > a').eq(1)); - assert.hasClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(0), 'selected'); - assert.doesNotHaveClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected'); - // remove facet - await testUtils.dom.click($('.o_facet_remove')); - assert.doesNotHaveClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(0), 'selected'); - assert.doesNotHaveClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected'); - actionManager.destroy(); - }); - - QUnit.module('FilterMenu'); - - QUnit.test('Search date and datetime fields. Support of timezones', async function (assert) { - assert.expect(4); - - this.data.partner.fields.birth_datetime = {string: "Birth DateTime", type: "datetime", store: true, sortable: true}; - this.data.partner.records = this.data.partner.records.slice(0,-1); // exclude wrong date record - - async function stringToEvent ($element, string) { - for (var i = 0; i < string.length; i++) { - var keyAscii = string.charCodeAt(i); - $element.val($element.val()+string[i]); - await testUtils.nextTick(); - $element.trigger($.Event('keyup', {which: keyAscii, keyCode:keyAscii})); - await testUtils.nextTick(); - } - } - - var searchReadSequence = 0; - var actionManager = await createActionManager({ - actions: [{ - id: 11, - name: 'Partners Action 11', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[3, 'list']], - search_view_id: [9, 'search'], - }], - archs: { - 'partner,3,list': '<tree>' + - '<field name="foo"/>' + - '<field name="birthday" />' + - '<field name="birth_datetime" />' + - '</tree>', - - 'partner,9,search': '<search>'+ - '<field name="birthday"/>' + - '<field name="birth_datetime" />' + - '</search>', - }, - data: this.data, - session: { - getTZOffset: function() { - return 360; - } - }, - mockRPC: function (route, args) { - if (route === '/web/dataset/search_read') { - if (searchReadSequence === 1) { // The 0th time is at loading - assert.deepEqual(args.domain, [["birthday", "=", "1983-07-15"]], - 'A date should stay what the user has input, but transmitted in server\'s format'); - } else if (searchReadSequence === 3) { // the 2nd time is at closing the first facet - assert.deepEqual(args.domain, [["birth_datetime", "=", "1983-07-14 18:00:00"]], - 'A datetime should be transformed in UTC and transmitted in server\'s format'); - } - searchReadSequence+=1; - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(11); - - // Date case - var $autocomplete = $('.o_searchview_input'); - await stringToEvent($autocomplete, '07/15/1983'); - await testUtils.fields.triggerKey('up', $autocomplete, 'enter'); - - assert.equal($('.o_searchview_facet .o_facet_values').text().trim(), '07/15/1983', - 'The format of the date in the facet should be in locale'); - - // Close Facet - await testUtils.dom.click($('.o_searchview_facet .o_facet_remove')); - - // DateTime case - $autocomplete = $('.o_searchview_input'); - await stringToEvent($autocomplete, '07/15/1983 00:00:00'); - await testUtils.fields.triggerKey('down', $autocomplete, 'down'); - await testUtils.fields.triggerKey('up', $autocomplete, 'enter'); - - assert.equal($('.o_searchview_facet .o_facet_values').text().trim(), '07/15/1983 00:00:00', - 'The format of the datetime in the facet should be in locale'); - - actionManager.destroy(); - }); - - QUnit.test('add a custom filter works', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(1); - await testUtils.dom.click($('span.fa-filter')); - await testUtils.dom.click($('.o_add_custom_filter')); - await testUtils.dom.click($('.o_apply_filter')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'ID is \"0\"', - 'should have a facet with candle name'); - actionManager.destroy(); - }); - - QUnit.test('deactivate a new custom filter works', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(1); - await testUtils.dom.click($('span.fa-filter')); - await testUtils.dom.click($('.o_add_custom_filter')); - await testUtils.dom.click($('.o_apply_filter')); - await testUtils.dom.click($('.o_menu_item')); - assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0, - 'no facet should be in the search view'); - actionManager.destroy(); - }); - - QUnit.test('filter by a date field using period works', async function (assert) { - assert.expect(15); - - var self = this; - - this.archs['partner,4,search'] = '<search>'+ - '<filter string="AAA" name="some_filter" date="date_field"></filter>' + - '</search>'; - - var unpatchDate = patchDate(2017,2,22,1,0,0); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function(route, args) { - if (route === '/web/dataset/search_read' && args.domain.length) { - assert.deepEqual(args.domain, self.basicDomains.shift()); - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(5); - - // open menu 'Filter' - await testUtils.dom.click($('.o_search_options .fa-filter')); - // open menu options - await testUtils.dom.click($('.o_menu_item')); - - var generatorIds = $('.o_menu_item .o_item_option') - .map(function() {return $(this).data('option_id');}) - .toArray(); - - assert.deepEqual(generatorIds, OPTION_GENERATOR_IDS, - "10 basic period options should be available:"); - - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_month"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_month"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_month"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_month"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="antepenultimate_month"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="fourth_quarter"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="antepenultimate_month"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="fourth_quarter"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="first_quarter"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="first_quarter"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_year"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_year"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_year"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="antepenultimate_year"]')); - await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_month"]')); - actionManager.destroy(); - unpatchDate(); - }); - - QUnit.test('filter by a date field using period works even in January', async function (assert) { - assert.expect(3); - - this.archs['partner,4,search'] = '<search>'+ - '<filter string="AAA" name="some_filter" date="date_field" default_period="last_month"></filter>' + - '</search>'; - - var unpatchDate = patchDate(2017,0,7,3,0,0); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function(route, args) { - if (route === '/web/dataset/search_read' && args.domain.length) { - assert.deepEqual(args.domain, - ['&', ["date_field", ">=", "2016-12-01"], ["date_field", "<=", "2016-12-31"]] - ); - } - return this._super.apply(this, arguments); - }, - }); - - this.actions[4].context = {search_default_some_filter: true}; - - await actionManager.doAction(5); - - // open menu 'Filter' - await testUtils.dom.click($('.o_search_options .fa-filter')); - // open menu options - await testUtils.dom.click($('.o_menu_item')); - - assert.hasClass($('.o_item_option[data-option_id="last_month"] a'), 'selected'); - assert.hasClass($('.o_item_option[data-option_id="last_year"] a'), 'selected'); - - actionManager.destroy(); - unpatchDate(); - }); - - QUnit.test('`context` key in <filter> is used', async function (assert) { - assert.expect(3); - - this.archs['partner,4,search'] = '<search>'+ - '<filter string="AAA" name="some_filter" context="{\'coucou_1\': 1}"></filter>' + - '</search>'; - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - if (route === '/web/dataset/search_read') { - assert.step(JSON.stringify(args.context)); - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(5); - - // select filter - await testUtils.dom.click($('.o_search_options .fa-filter')); - await testUtils.dom.click($('.o_menu_item:contains(AAA)')); - - assert.verifySteps([ - "{\"bin_size\":true}", - "{\"coucou_1\":1,\"bin_size\":true}", - ]); - - actionManager.destroy(); - }); - - QUnit.test('Filter with JSON-parsable domain works', async function (assert) { - assert.expect(1); - - var domain = [['foo' ,'=', 'Gently Weeps']]; - var xml_domain = JSON.stringify(domain); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - if (route === '/web/dataset/search_read') { - assert.deepEqual(args.domain, domain, - 'A JSON parsable xml domain should be handled just like any other'); - } - return this._super.apply(this, arguments); - } - }); - - this.archs['partner,5,search'] = - '<search>'+ - '<filter string="Foo" name="gently_weeps" domain="' + _.escape(xml_domain) + '" />' + - '</search>'; - this.actions[0].search_view_id = [5, 'search']; - this.actions[0].context = {search_default_gently_weeps: true}; - - await actionManager.doAction(1); - - actionManager.destroy(); - }); - - QUnit.test('filter with date attribute set as search_default', async function (assert) { - assert.expect(1); - - const unpatchDate = patchDate(2019,6,31,13,43,0); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - this.archs['partner,5,search'] = - '<search>'+ - '<filter string="Date" name="date_field" date="date_field" />' + - '</search>'; - this.actions[0].search_view_id = [5, 'search']; - this.actions[0].context = {search_default_date_field: true}; - - await actionManager.doAction(1); - - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), - "Date: July 2019", - "There should be a filter facet with label 'Date: July 2019'"); - - actionManager.destroy(); - unpatchDate(); - }); - - QUnit.test('Custom Filter datetime with equal operator', async function (assert) { - assert.expect(5); - - this.data.partner.fields.date_time_field = {string: "DateTime", type: "datetime", store: true, searchable: true}; - - var searchReadCount = 0; - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - session: { - getTZOffset: function () { - return -240; - }, - }, - mockRPC: async function (route, args) { - if (route === '/web/dataset/search_read') { - if (searchReadCount === 1) { - assert.deepEqual(args.domain, - [['date_time_field', '=', '2017-02-22 15:00:00']], // In UTC - 'domain is correct' - ); - } - } - return this._super.apply(this, arguments); - }, - }); - // List view - await actionManager.doAction(2); - - await testUtils.dom.click($('button:contains(Filters)')); - await testUtils.dom.click($('.o_dropdown_menu .o_add_custom_filter')); - assert.strictEqual($('.o_dropdown_menu select.o_searchview_extended_prop_field').val(), 'date_time_field', - 'the date_time_field should be selected in the custom filter'); - - assert.strictEqual($('.o_dropdown_menu select.o_searchview_extended_prop_op').val(), 'between', - 'The between operator is selected'); - - await testUtils.fields.editSelect($('.o_dropdown_menu select.o_searchview_extended_prop_op'), '='); - - assert.strictEqual($('.o_dropdown_menu select.o_searchview_extended_prop_op').val(), '=', - 'The equal operator is selected'); - - await testUtils.fields.editAndTrigger($('.o_searchview_extended_prop_value input:first'), '02/22/2017 11:00:00', ['change']); // in TZ - - searchReadCount = 1; - await testUtils.dom.click($('.o_dropdown_menu .o_apply_filter')); - - assert.strictEqual($('.o_dropdown_menu .dropdown-item.selected').text().trim(), 'DateTime is equal to "02/22/2017 11:00:00"', - 'Label of Filter is correct'); - - actionManager.destroy(); - }); - - QUnit.test('Custom Filter datetime between operator', async function (assert) { - assert.expect(4); - - this.data.partner.fields.date_time_field = {string: "DateTime", type: "datetime", store: true, searchable: true}; - - var searchReadCount = 0; - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - session: { - getTZOffset: function () { - return -240; - }, - }, - mockRPC: async function (route, args) { - if (route === '/web/dataset/search_read') { - if (searchReadCount === 1) { - assert.deepEqual(args.domain, - [ - '&', ['date_time_field', '>=', '2017-02-22 15:00:00'], ['date_time_field', '<=', '2017-02-22 21:00:00'] // In UTC - ], - 'domain is correct' - ); - } - } - return this._super.apply(this, arguments); - }, - }); - // List view - await actionManager.doAction(2); - - await testUtils.dom.click($('button:contains(Filters)')); - await testUtils.dom.click($('.o_dropdown_menu .o_add_custom_filter')); - assert.strictEqual($('.o_dropdown_menu select.o_searchview_extended_prop_field').val(), 'date_time_field', - 'the date_time_field should be selected in the custom filter'); - - assert.strictEqual($('.o_dropdown_menu select.o_searchview_extended_prop_op').val(), 'between', - 'The between operator is selected'); - - await testUtils.fields.editAndTrigger($('.o_searchview_extended_prop_value input:first'), '02/22/2017 11:00:00', ['change']); // in TZ - await testUtils.fields.editAndTrigger($('.o_searchview_extended_prop_value input:last'), '02/22/2017 17:00:00', ['change']); // in TZ - - searchReadCount = 1; - await testUtils.dom.click($('.o_dropdown_menu .o_apply_filter')); - - assert.strictEqual($('.o_dropdown_menu .dropdown-item.selected').text().trim(), 'DateTime is between "02/22/2017 11:00:00 and 02/22/2017 17:00:00"', - 'Label of Filter is correct'); - - actionManager.destroy(); - }); - - QUnit.module('Favorites Menu'); - - QUnit.test('dynamic filters are saved dynamic', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - intercepts: { - create_filter: function (ev) { - assert.equal( - ev.data.filter.domain, - `[("date_field", ">=", (context_today() + relativedelta()).strftime("%Y-%m-%d"))]`); - }, - }, - }); - - await actionManager.doAction(12); - await testUtils.dom.click($('span.fa-filter')); - await testUtils.dom.click($('.o_filters_menu .o_menu_item a')); - await testUtils.dom.click($('span.fa-star')); - await testUtils.dom.click($('.o_favorites_menu .o_add_favorite')); - await testUtils.fields.editInput($('div.o_favorite_name input'), 'name for favorite'); - await testUtils.dom.click($('.o_favorites_menu .o_save_favorite button')); - actionManager.destroy(); - }); - - QUnit.test('save search filter in modal', async function (assert) { - assert.expect(5); - this.data.partner.records.push({ - id: 7, - display_name: "Partner 6", - }, { - id: 8, - display_name: "Partner 7", - }, { - id: 9, - display_name: "Partner 8", - }, { - id: 10, - display_name: "Partner 9", - }); - this.data.partner.fields.date_field.searchable = true; - var form = await createView({ - View: FormView, - model: 'partner', - data: this.data, - arch: '<form string="Partners">' + - '<sheet>' + - '<group>' + - '<field name="bar"/>' + - '</group>' + - '</sheet>' + - '</form>', - archs: { - 'partner,false,list': '<tree><field name="display_name"/></tree>', - 'partner,false,search': '<search><field name="date_field"/></search>', - }, - res_id: 1, - }); - - await testUtils.form.clickEdit(form); - - await testUtils.fields.many2one.clickOpenDropdown('bar'); - await testUtils.fields.many2one.clickItem('bar','Search'); - - assert.strictEqual($('tr.o_data_row').length, 9, "should display 9 records"); - - await testUtils.dom.click($('button:contains(Filters)')); - await testUtils.dom.click($('.o_add_custom_filter:visible')); - assert.strictEqual($('.o_filter_condition select.o_searchview_extended_prop_field').val(), 'date_field', - "date field should be selected"); - await testUtils.dom.click($('.o_apply_filter')); - - assert.strictEqual($('tr.o_data_row').length, 0, "should display 0 records"); - - // Save this search - await testUtils.mock.intercept(form, 'create_filter', function (event) { - assert.strictEqual(event.data.filter.name, "Awesome Test Customer Filter", "filter name should be correct"); - }); - await testUtils.dom.click($('button:contains(Favorites)')); - await testUtils.dom.click($('.o_add_favorite')); - var filterNameInput = $('.o_favorite_name .o_input[type="text"]:visible'); - assert.strictEqual(filterNameInput.length, 1, "should display an input field for the filter name"); - await testUtils.fields.editInput(filterNameInput, 'Awesome Test Customer Filter'); - await testUtils.dom.click($('.o_save_favorite button')); - - form.destroy(); - }); - - QUnit.test('save filters created via autocompletion works', async function (assert) { - assert.expect(2); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - intercepts: { - create_filter: function (ev) { - assert.ok(ev.data.filter.domain === `[["foo", "ilike", "a"]]`); - }, - }, - }); - - await actionManager.doAction(10); - - $('.o_searchview_input').trigger($.Event('keypress', { - which: 97, - })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keyup', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - await testUtils.nextTick(); - - await testUtils.nextTick(); - - assert.strictEqual($('.o_searchview_input_container .o_facet_values span').text().trim(), "a"); - - await testUtils.dom.click($('button .fa-star')); - await testUtils.dom.click($('.o_favorites_menu .o_add_favorite')); - await testUtils.fields.editInput($('div.o_favorite_name input'), 'name for favorite'); - await testUtils.dom.click($('.o_favorites_menu div.o_save_favorite button')); - - actionManager.destroy(); - }); - - QUnit.test('delete an active favorite remove it both in list of favorite and in search bar', async function (assert) { - assert.expect(2); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - intercepts: { - load_filters: function (event) { - return Promise.resolve([{ - context: "{}", - domain: "[]", - id: 7, - is_default: true, - name: "My favorite", - sort: "[]", - user_id: [2, "Mitchell Admin"], - }]).then(event.data.on_success); - }, - delete_filter: function (event) { - event.data.on_success(); - } - }, - }); - - await actionManager.doAction(6); - await testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options button.o_favorites_menu_button')); - assert.containsOnce(actionManager, '.o_control_panel .o_searchview_input_container .o_facet_values'); - await testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options .o_favorites_menu span.o_trash_button')); - await testUtils.modal.clickButton('Ok'); - assert.containsNone(actionManager, '.o_control_panel .o_searchview_input_container .o_facet_values'); - actionManager.destroy(); - }); - - QUnit.test('default favorite is not activated if key search_disable_custom_filters is set to true', async function (assert) { - assert.expect(1); - - var controlPanel = await createControlPanel({ - model: 'partner', - arch: '<controlpanel/>', - data: this.data, - intercepts: { - load_filters: function (event) { - return Promise.resolve([{ - context: "{}", - domain: "[]", - id: 7, - is_default: true, - name: "My favorite", - sort: "[]", - user_id: [2, "Mitchell Admin"], - }]).then(event.data.on_success); - }, - }, - context: { - search_disable_custom_filters: true, - }, - }); - - assert.containsNone(controlPanel, '.o_facet_values'); - controlPanel.destroy(); - }); - - QUnit.test('toggle favorite correctly clears filter, groupbys and field "options"', async function (assert) { - assert.expect(8); - - const unpatchDate = patchDate(2019,6,31,13,43,0); - - const actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - intercepts: { - load_filters: function (event) { - return Promise.resolve([{ - context: "{}", - domain: "[]", - id: 7, - is_default: false, - name: "My favorite", - sort: "[]", - user_id: [2, "Mitchell Admin"], - }]).then(event.data.on_success); - }, - }, - }); - - this.actions[11].search_view_id = [10, 'search']; - await actionManager.doAction(12); - - // activate Foo a - await testUtils.fields.triggerKey('press', $('.o_searchview_input'), 97); - await testUtils.fields.triggerKey('up', $('.o_searchview_input'), 'enter'); - - // activate Date Filter with This Month - await testUtils.dom.click($('button .fa-filter')); - await testUtils.dom.click($('.o_filters_menu .o_menu_item a')); - await testUtils.dom.click($('.o_item_option[data-option_id="this_month"]')); - - // activate Date Groupby with Year - await testUtils.dom.click($('button .fa-bars')); - await testUtils.dom.click($('.o_group_by_menu .o_menu_item a')); - await testUtils.dom.click($('.o_item_option[data-option_id="year"]')); - - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), - "a", - "There should be a filter Foo a"); - - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(1).text().trim(), - "Date Field Filter: July 2019", - "There should be a filter facet with label 'Date Field Filter: July 2019'"); - - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(2).text().trim(), - "Date Field Groupby: Year", - "There should be a groupby facet with label 'Date Field Groupby: Year'"); - - // activate the favorite - await testUtils.dom.click($('button .fa-star')); - await testUtils.dom.click($('.o_favorites_menu .o_menu_item a')); - - assert.containsOnce(actionManager, '.o_searchview_input_container .o_facet_values', - "There should be a unique facet in the search bar"); - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), - "My favorite", - "There should be a facet with label 'My favorite''"); - - await testUtils.dom.click($('button .fa-filter')); - await testUtils.dom.click($('.o_filters_menu .o_menu_item a')); - assert.doesNotHaveClass($('.o_item_option[data-option_id="this_month"]'), 'selected', - "The Date Filter option 'This Month' should be deactivated"); - - await testUtils.dom.click($('button .fa-bars')); - await testUtils.dom.click($('.o_group_by_menu .o_menu_item a')); - assert.doesNotHaveClass($('.o_item_option[data-option_id="year"]'), 'selected', - "The Date Groupby option 'Year' should be deactivated"); - - await testUtils.fields.triggerKey('press', $('.o_searchview_input'), 98); - await testUtils.fields.triggerKey('up', $('.o_searchview_input'), 'enter'); - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(1).text().trim(), - "b", - "There should be a filter Foo b"); - - actionManager.destroy(); - unpatchDate(); - }); - - QUnit.test('favorites have unique descriptions (the submenus of the favorite menu are correctly updated)', async function (assert) { - assert.expect(7); - - const UID = session.uid; - - const actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - intercepts: { - load_filters: function (event) { - return Promise.resolve([{ - context: "{}", - domain: "[]", - id: 7, - is_default: false, - name: "My favorite", - sort: "[]", - user_id: [2, "Mitchell Admin"], - }]).then(event.data.on_success); - }, - create_filter: function (event) { - assert.step('create_filter'); - assert.deepEqual(event.data.filter, { - "action_id": 1, - "context": {}, - "domain": "[]", - "is_default": false, - "model_id": "partner", - "name": "My favorite 2", - "sort": "[]", - "user_id": UID, - }); - return Promise.resolve(1).then(event.data.on_success); - } - }, - }); - testUtils.mock.intercept(actionManager, 'call_service', function (ev) { - if (ev.data.service === 'notification') { - // A notification alerting that another favorite with same name exists - // should be triggered - assert.step('notification'); - assert.deepEqual(ev.data.args[0], { - "className": undefined, - "message": "Filter with same name already exists.", - "sticky": undefined, - "title": "Error", - "type": "danger" - }); - } - }, true); - - await actionManager.doAction(1); - await testUtils.dom.click($('button .fa-star')); - await testUtils.dom.click($('.o_favorites_menu .o_add_favorite')); - await testUtils.fields.editInput($('div.o_favorite_name input'), 'My favorite'); - await testUtils.dom.click($('.o_favorites_menu div.o_save_favorite button')); - - await testUtils.fields.editInput($('div.o_favorite_name input'), 'My favorite 2'); - await testUtils.dom.click($('.o_favorites_menu div.o_save_favorite button')); - - await testUtils.dom.click($('.o_favorites_menu .o_add_favorite')); - await testUtils.fields.editInput($('div.o_favorite_name input'), 'My favorite 2'); - await testUtils.dom.click($('.o_favorites_menu div.o_save_favorite button')); - - assert.verifySteps([ - 'notification', - 'create_filter', - 'notification' - ]) - - actionManager.destroy(); - }); - - QUnit.module('Search Arch'); - - QUnit.test('arch order of groups of filters preserved', async function (assert) { - assert.expect(12); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(8); - await testUtils.dom.click($('span.fa-filter')); - assert.strictEqual($('.o_filters_menu .o_menu_item').length, 11); - for (var i = 0; i < 11; i++) { - assert.strictEqual($('.o_filters_menu .o_menu_item').eq(i).text().trim(), (i+1).toString()); - } - actionManager.destroy(); - }); - - QUnit.module('Autocompletion'); - - QUnit.test('select an autocomplete field', async function (assert) { - assert.expect(3); - - var searchRead = 0; - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - if (route === '/web/dataset/search_read') { - if (searchRead === 1) { - assert.deepEqual(args.domain, [["foo", "ilike", "a"]]); - } - searchRead++; - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(11); - - await testUtils.fields.triggerKey('press', $('.o_searchview_input'), 97); - assert.strictEqual(actionManager.$('.o_searchview_autocomplete li').length, 2, - "there should be 2 result for 'a' in search bar autocomplete"); - - await testUtils.fields.triggerKey('up', $('.o_searchview_input'), 'enter'); - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), - "a", "There should be a field facet with label 'a'"); - - actionManager.destroy(); - }); - - QUnit.test('select an autocomplete field with `context` key', async function (assert) { - assert.expect(9); - - var searchRead = 0; - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - if (route === '/web/dataset/search_read') { - if (searchRead === 1) { - assert.deepEqual(args.domain, [["bar", "=", 1]]); - assert.deepEqual(args.context.bar, [1]); - } else if (searchRead === 2) { - assert.deepEqual(args.domain, ["|", ["bar", "=", 1], ["bar", "=", 2]]); - assert.deepEqual(args.context.bar, [1, 2]); - } - searchRead++; - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(11); - await testUtils.nextTick(); - assert.strictEqual(searchRead, 1, "there should be 1 search_read"); - - // 'r' key to filter on bar "First Record" - $('.o_searchview_input').val('r'); - $('.o_searchview_input').trigger($.Event('keypress', { which: 82, keyCode: 82 })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.RIGHT, keyCode: $.ui.keyCode.RIGHT })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER })); - await testUtils.nextTick(); - - await testUtils.nextTick(); - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), "First record", - "the autocompletion facet should be correct"); - assert.strictEqual(searchRead, 2, "there should be 2 search_read"); - - // 'r' key to filter on bar "Second Record" - $('.o_searchview_input').val('r'); - $('.o_searchview_input').trigger($.Event('keypress', { which: 82, keyCode: 82 })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.RIGHT, keyCode: $.ui.keyCode.RIGHT })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - await testUtils.nextTick(); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - $('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER })); - await testUtils.nextTick(); - - assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), "First record or Second record", - "the autocompletion facet should be correct"); - assert.strictEqual(searchRead, 3, "there should be 3 search_read"); - - actionManager.destroy(); - }); - - QUnit.test('no search text triggers a reload', async function (assert) { - assert.expect(2); - var rpcs = 0; - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function () { - rpcs++; - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction(10); - rpcs = 0; - $('.o_searchview_input').trigger($.Event('keydown', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - await testUtils.nextTick(); - - $('.o_searchview_input').trigger($.Event('keyup', { - which: $.ui.keyCode.ENTER, - keyCode: $.ui.keyCode.ENTER, - })); - await testUtils.nextTick(); - - assert.containsNone(actionManager, '.o_searchview_facet_label'); - assert.strictEqual(rpcs, 2, "should have reloaded"); - - actionManager.destroy(); - }); - - QUnit.test('selecting (no result) triggers a re-render', async function (assert) { - assert.expect(3); - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - actionManager.doAction(10); - await testUtils.nextTick(); - - // 'a' key to filter nothing on bar - actionManager.$('.o_searchview_input').val('a'); - actionManager.$('.o_searchview_input').trigger($.Event('keypress', { which: 65, keyCode: 65 })); - await testUtils.nextTick(); - actionManager.$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - await testUtils.nextTick(); - actionManager.$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.RIGHT, keyCode: $.ui.keyCode.RIGHT })); - await testUtils.nextTick(); - actionManager.$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN })); - await testUtils.nextTick(); - - assert.strictEqual(actionManager.$('.o_searchview_autocomplete .o-selection-focus').text(), "(no result)", - "there should be no result for 'a' in bar"); - - actionManager.$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER })); - await testUtils.nextTick(); - - assert.containsNone(actionManager, '.o_searchview_facet_label'); - assert.strictEqual(actionManager.$('.o_searchview_input').val(), "", - "the search input should be re-rendered"); - - actionManager.destroy(); - }); - - QUnit.test('update suggested filters in autocomplete menu with Japanese IME', async function (assert) { - assert.expect(4); - - this.actions.push({ - id: 13, - name: 'Partners Action 11', - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'list']], - search_view_id: [13, 'search'], - }); - this.archs['partner,13,search'] = ` - <search> - <field name="foo"/> - <field name="bar"/> - </search>`; - - const actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - actionManager.doAction(13); - await testUtils.nextTick(); - - // Simulate typing "Test" on search view. - const TEST = "TEST"; - $('.o_searchview_input').val(TEST); - for (const char of TEST) { - $('.o_searchview_input').trigger($.Event('keypress', { - which: char.charCodeAt(0), - keyCode: char.charCodeAt(0), - })); - } - $('.o_searchview_input').trigger($.Event('keyup')); - await testUtils.nextTick(); - assert.containsOnce( - $, - '.o_searchview_autocomplete', - "should display autocomplete dropdown menu on typing something in search view" - ); - assert.strictEqual( - $('.o_searchview_autocomplete li:first').text(), - "Search Foo for: TEST", - `1st filter suggestion should be based on typed word "TEST"` - ); - - // Simulate soft-selection of another suggestion from IME. - const テスト = "テスト"; - $('.o_searchview_input').val(テスト); - for (const char of テスト) { - $('.o_searchview_input').trigger($.Event('keypress', { - which: char.charCodeAt(0), - keyCode: char.charCodeAt(0), - })); - } - $('.o_searchview_input').trigger($.Event('keyup')); - await testUtils.nextTick(); - assert.strictEqual( - $('.o_searchview_autocomplete li:first').text(), - "Search Foo for: テスト", - `1st filter suggestion should be updated with soft-selection typed word "テスト"` - ); - - // Simulate selection on suggestion item "Test" from IME. - $('.o_searchview_input').val("TEST"); - const nativeInputEvent = new window.InputEvent('input', { inputType: 'insertCompositionText' }); - const jqueryInputEvent = $.Event('input', { bubbles: true }); - jqueryInputEvent.originalEvent = nativeInputEvent; - $('.o_searchview_input').trigger(jqueryInputEvent); - await testUtils.nextTick(); - assert.strictEqual( - $('.o_searchview_autocomplete li:first').text(), - "Search Foo for: TEST", - `1st filter suggestion should finally be updated with click selection on word "TEST" from IME` - ); - - actionManager.destroy(); - }); - - QUnit.module('TimeRangeMenu'); - - QUnit.test('time range menu stays hidden', async function (assert) { - assert.expect(4); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - }); - - await actionManager.doAction(1); - - // check that there is no time range menu - assert.containsNone(actionManager, '.o_control_panel .o_search_options .o_time_range_menu'); - // check if search view has no facets - assert.strictEqual($('.o_facet_values').length, 0); - - // activate groupby - await testUtils.dom.click($('button .fa-bars')); - await testUtils.dom.click($('.o_menu_item a').eq(0)); - // check that there is a facet - assert.strictEqual($('div.o_facet_values').length, 1); - // check that there is still no time range menu - assert.containsNone(actionManager, '.o_control_panel .o_search_options .o_time_range_menu'); - actionManager.destroy(); - }); - - QUnit.test('time range menu in comparison mode', async function (assert) { - assert.expect(46); - - var self = this; - var nbrReadGroup = 0; - - var periodOptionText, periodOptionValue; - var unpatchDate = patchDate(2017, 2, 22, 1, 0, 0); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - if (route === '/web/dataset/call_kw/partner/read_group') { - nbrReadGroup++; - var timeRangeMenuData = args.kwargs.context.timeRangeMenuData; - if (timeRangeMenuData) { - // nbrReadGroup % 2 === 0 is true when the read group is for data, false - // for comparison data - if (nbrReadGroup % 2 === 0) { - assert.deepEqual(timeRangeMenuData.timeRange, - self.periodDomains.shift(), - "time range domain for " + periodOptionText); - } else { - assert.deepEqual(timeRangeMenuData.comparisonTimeRange, - self.previousPeriodDomains.shift(), - "comparaison time range domain for " + periodOptionText); - } - } - } - return this._super.apply(this, arguments); - }, - }); - // time range menu should be available in graph view - await actionManager.doAction(4); - - var $timeRangeMenu = $('.o_time_range_menu'); - assert.strictEqual($timeRangeMenu.not('.o_hidden').length, 1, - "Time range menu should be visible"); - assert.strictEqual($('.o_facet_values').length, 0, - "Search view has no facet"); - - var $periodOptions = $timeRangeMenu.find('.o_time_range_selector option'); - var periodOptions = $periodOptions.map(function () { - return $(this).val(); - }).toArray(); - assert.deepEqual(periodOptions, PERIOD_OPTIONS_IDS, - "13 period options should be available:"); - - for (var option of $periodOptions) { - periodOptionText = $(option).text().trim(); - periodOptionValue = $(option).val(); - // opens time range menu dropdown - await testUtils.dom.click($('.o_time_range_menu_button')); - var $timeRangeMenu = $('.o_time_range_menu'); - // comparison is not checked by default - if (!$timeRangeMenu.find('.o_comparison_checkbox').is(':checked')) { - await testUtils.dom.click($timeRangeMenu.find('.o_comparison_checkbox')); - assert.strictEqual($('.o_comparison_time_range_selector:visible').length, 1, - "Comparison has to be checked (only at the first time)"); - } - // select one period option to test it - $timeRangeMenu.find('.o_time_range_selector').val(periodOptionValue); - // apply - await testUtils.dom.click($timeRangeMenu.find('.o_apply_range')); - assert.strictEqual($('.o_facet_values').text().trim(), - "Date: " + periodOptionText + " / Previous Period", - "Facet should be updated with this period: " + periodOptionValue); - } - unpatchDate(); - actionManager.destroy(); - }); - - QUnit.test('a default time range only in context is taken into account', async function (assert) { - assert.expect(1); - - var actionManager = await createActionManager({ - actions: this.actions, - archs: this.archs, - data: this.data, - mockRPC: function (route, args) { - // there are only one read_group call (for the groupby lists []) - // the read group for the list ["date_field:day"] is not done since no data is available for today) - if (route === '/web/dataset/call_kw/partner/read_group') { - var timeRangeMenuData = args.kwargs.context.timeRangeMenuData; - assert.ok(timeRangeMenuData.timeRange.length > 0, "time range should be non empty"); - } - return this._super.apply(this, arguments); - }, - }); - - await actionManager.doAction({ - res_model: 'partner', - type: 'ir.actions.act_window', - views: [[false, 'pivot']], - context: {time_ranges: {range: 'today', field: 'date_field'}} - }); - actionManager.destroy(); - }); - - QUnit.test('Customizing filter does not close the filter dropdown', async function (assert) { - assert.expect(5); - var self = this; - - _.each(this.data.partner.records.slice(), function (rec) { - var copy = _.defaults({}, rec, {id: rec.id + 10 }); - self.data.partner.records.push(copy); - }); - - this.data.partner.fields.date_field.searchable = true; - var form = await createView({ - View: FormView, - model: 'partner', - data: this.data, - arch: '<form string="Partners">' + - '<field name="bar"/>' + - '</form>', - viewOptions: { - mode: 'edit', - }, - archs: { - 'partner,false,list': '<tree><field name="display_name"/></tree>', - 'partner,false,search': '<search><field name="date_field"/></search>', - }, - res_id: 1, - intercepts: { - create_filter: function (ev) { - var data = ev.data; - assert.strictEqual(data.filter.name, 'Fire on the bayou'); - assert.strictEqual(data.filter.is_default, true); - }, - }, - }); - - await testUtils.fields.many2one.clickOpenDropdown('bar'); - await testUtils.fields.many2one.clickItem('bar', 'Search More'); - - assert.containsOnce(document.body, '.modal'); - - await testUtils.dom.click($('.modal .o_filters_menu_button')); - - var $filterDropdown = $('.modal .o_filters_menu'); - await testUtils.dom.click($filterDropdown.find('.o_add_custom_filter')); - - assert.containsN($filterDropdown, '.o_input', 4); - - // We really are interested in the click event - // We do it twice on each input to make sure - // the parent dropdown doesn't react to any of it - _.each($filterDropdown.find('input'), async function (input) { - var $input = $(input); - $input.click(); - $input.click(); - await testUtils.nextTick(); - }); - assert.isVisible($filterDropdown); - - // Favorites Menu - var $modal = $('.modal'); - await testUtils.dom.click($modal.find('.o_favorites_menu_button')); - await testUtils.dom.click($modal.find('.o_add_favorite')); - $modal.find('.o_search_options .dropdown-menu').one('click', function (ev) { - // This handler is on the webClient - // But since the test suite doesn't have one - // We manually set it here - ev.stopPropagation(); - }); - await testUtils.fields.editInput($modal.find('div.o_favorite_name input'), 'Fire on the bayou'); - await testUtils.dom.click($modal.find('.o_add_favorite ~ div label:contains(Use by default)')); - await testUtils.dom.click($modal.find('.o_save_favorite button')); - - form.destroy(); - }); -}); -}); diff --git a/addons/web/static/tests/views/view_dialogs_tests.js b/addons/web/static/tests/views/view_dialogs_tests.js index 4e205c420a1..e86d0f53297 100644 --- a/addons/web/static/tests/views/view_dialogs_tests.js +++ b/addons/web/static/tests/views/view_dialogs_tests.js @@ -7,8 +7,16 @@ var testUtils = require('web.test_utils'); var Widget = require('web.Widget'); var FormView = require('web.FormView'); +const cpHelpers = testUtils.controlPanel; var createView = testUtils.createView; +async function createParent(params) { + var widget = new Widget(); + params.server = await testUtils.mock.addMockEnvironment(widget, params); + owl.Component.env = testUtils.mock.getMockedOwlEnv(params); + return widget; +} + QUnit.module('Views', { beforeEach: function () { this.data = { @@ -56,17 +64,10 @@ QUnit.module('Views', { QUnit.module('view_dialogs'); - function createParent(params) { - var widget = new Widget(); - - testUtils.mock.addMockEnvironment(widget, params); - return widget; - } - QUnit.test('formviewdialog buttons in footer are positioned properly', async function (assert) { assert.expect(2); - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,form': @@ -97,7 +98,7 @@ QUnit.module('Views', { this.data.partner.fields.poney_ids = {string: "Poneys", type: "one2many", relation: 'partner'}; this.data.partner.records[0].poney_ids = []; - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,form': @@ -129,7 +130,7 @@ QUnit.module('Views', { assert.expect(3); var search = 0; - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,list': @@ -196,9 +197,8 @@ QUnit.module('Views', { dialog = result; }); await testUtils.nextTick(); - - await testUtils.dom.click(dialog.$('.o_searchview_facet:contains(groupby_bar) .o_facet_remove')); - await testUtils.dom.click(dialog.$('.o_searchview_facet .o_facet_remove')); + await cpHelpers.removeFacet('.modal', "Bar"); + await cpHelpers.removeFacet('.modal'); parent.destroy(); }); @@ -206,7 +206,7 @@ QUnit.module('Views', { QUnit.test('SelectCreateDialog correctly evaluates domains', async function (assert) { assert.expect(1); - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,list': @@ -245,7 +245,7 @@ QUnit.module('Views', { QUnit.test('SelectCreateDialog list view in readonly', async function (assert) { assert.expect(1); - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,list': @@ -437,7 +437,7 @@ QUnit.module('Views', { }, }); - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,list': @@ -450,14 +450,19 @@ QUnit.module('Views', { '</search>', }, - intercepts: { - create_filter: function (event) { - var filter = event.data.filter; - assert.deepEqual(filter.domain, `[("bar", "=", True)]`, - "should save the correct domain"); - assert.deepEqual(filter.context, {shouldBeInFilterContext: true}, - "should save the correct context"); - }, + env: { + dataManager: { + create_filter: function (filter) { + assert.strictEqual(filter.domain, `[("bar", "=", True)]`, + "should save the correct domain"); + const expectedContext = { + group_by: [], // default groupby is an empty list + shouldBeInFilterContext: true, + }; + assert.deepEqual(filter.context, expectedContext, + "should save the correct context"); + }, + } }, }); @@ -470,19 +475,20 @@ QUnit.module('Views', { }); await testUtils.nextTick(); + assert.containsN(dialog, '.o_data_row', 3, "should contain 3 records"); // filter on bar - await testUtils.dom.click(dialog.$('.o_dropdown_toggler_btn:contains(Filters)')); - await testUtils.dom.click(dialog.$('.o_filters_menu a:contains(Bar)')); + await cpHelpers.toggleFilterMenu('.modal'); + await cpHelpers.toggleMenuItem('.modal', "Bar"); assert.containsN(dialog, '.o_data_row', 2, "should contain 2 records"); // save filter - await testUtils.dom.click(dialog.$('.o_dropdown_toggler_btn:contains(Favorites)')); - await testUtils.dom.click(dialog.$('.o_add_favorite')); - await testUtils.fields.editInput(dialog.$('.o_favorite_name input[type=text]'), 'some name'); // name the filter - await testUtils.dom.click(dialog.$('.o_save_favorite button')); + await cpHelpers.toggleFavoriteMenu('.modal'); + await cpHelpers.toggleSaveFavorite('.modal'); + await cpHelpers.editFavoriteName('.modal', "some name"); + await cpHelpers.saveFavorite('.modal'); testUtils.mock.unpatch(ListController); parent.destroy(); @@ -555,7 +561,7 @@ QUnit.module('Views', { this.data.partner.records[0].poney_ids = []; var reject = true; - var parent = createParent({ + var parent = await createParent({ data: this.data, archs: { 'partner,false,form': diff --git a/addons/web/static/tests/widgets/data_export_tests.js b/addons/web/static/tests/widgets/data_export_tests.js index c9c51219571..2d3488f5891 100644 --- a/addons/web/static/tests/widgets/data_export_tests.js +++ b/addons/web/static/tests/widgets/data_export_tests.js @@ -1,12 +1,13 @@ odoo.define('web.data_export_tests', function (require) { "use strict"; -var framework = require('web.framework'); -var ListView = require('web.ListView'); -var testUtils = require('web.test_utils'); -var data = require('web.data'); +const framework = require('web.framework'); +const ListView = require('web.ListView'); +const testUtils = require('web.test_utils'); +const data = require('web.data'); -var createView = testUtils.createView; +const cpHelpers = testUtils.controlPanel; +const createView = testUtils.createView; QUnit.module('widgets', { beforeEach: function () { @@ -63,7 +64,7 @@ QUnit.module('widgets', { data: this.data, arch: '<tree><field name="foo"/></tree>', viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, mockRPC: function (route) { if (route === '/web/export/formats') { @@ -104,9 +105,11 @@ QUnit.module('widgets', { }, }); + await testUtils.dom.click(list.$('thead th.o_list_record_selector input')); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Export)')); + + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, 'Export'); assert.strictEqual($('.modal').length, 1, "a modal dialog should be open"); assert.strictEqual($('div.o_tree_column:contains(Activities)').length, 1, @@ -144,7 +147,7 @@ QUnit.module('widgets', { data: this.data, arch: '<tree><field name="foo"/></tree>', viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, mockRPC: function (route) { if (route === '/web/export/formats') { @@ -179,10 +182,12 @@ QUnit.module('widgets', { }, }); + // Open the export modal await testUtils.dom.click(list.$('thead th.o_list_record_selector input')); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Export)')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, 'Export'); + assert.strictEqual($('.modal').length, 1, "a modal dialog should be open"); @@ -214,7 +219,7 @@ QUnit.module('widgets', { data: this.data, arch: '<tree><field name="foo"/></tree>', viewOptions: { - hasSidebar: true, + hasActionMenus: true, }, mockRPC: function (route) { if (route === '/web/export/formats') { @@ -248,10 +253,12 @@ QUnit.module('widgets', { return this._super.apply(this, arguments); }, }); + + // Open the export modal - await testUtils.dom.click(list.$('thead .o_list_record_selector input')); - await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)')); - await testUtils.dom.click(list.sidebar.$('a:contains(Export)')); + await testUtils.dom.click(list.$('thead th.o_list_record_selector input')); + await cpHelpers.toggleActionMenu(list); + await cpHelpers.toggleMenuItem(list, 'Export'); assert.strictEqual($('.modal .o_export_tree_item:visible').length, 2, "There should be only two items visible"); await testUtils.dom.click($('.modal .o_export_search_input')); @@ -333,7 +340,6 @@ QUnit.module('widgets', { View: ListView, model: 'partner', data: this.data, - debug: true, arch: ` <tree> <field name="foo"/> diff --git a/addons/web/static/tests/widgets/dropdown_menu_tests.js b/addons/web/static/tests/widgets/dropdown_menu_tests.js deleted file mode 100644 index ff53b3d77e8..00000000000 --- a/addons/web/static/tests/widgets/dropdown_menu_tests.js +++ /dev/null @@ -1,203 +0,0 @@ -odoo.define('web.dropdown_menu_tests', function (require) { -"use strict"; - -var DropdownMenu = require('web.DropdownMenu'); -var testUtils = require('web.test_utils'); - -function createDropdownMenu(items, params) { - params = params || {}; - var target = params.debug ? document.body : $('#qunit-fixture'); - var menu = new DropdownMenu(null, items); - testUtils.mock.addMockEnvironment(menu, params); - return menu.appendTo(target).then(function() { - return menu; - }); -} - -QUnit.module('Web', { - beforeEach: function () { - this.items = [ - { - isActive: false, - description: 'Some Item', - id: 1, - groupId: 1, - groupNumber: 1, - }, - { - isActive: true, - description: 'Some other Item', - id: 2, - groupId: 2, - groupNumber: 2, - }, - ]; - }, -}, function () { - QUnit.module('DropdownMenu'); - - QUnit.test('simple rendering', async function (assert) { - assert.expect(4); - - var dropdownMenu = await createDropdownMenu(this.items); - assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4, - 'should have 4 elements counting the dividers'); - assert.strictEqual(dropdownMenu.$('.o_menu_item').first().text().trim(), 'Some Item', - 'first element should have "Some Item" description'); - assert.ok(!dropdownMenu.$('.o_menu_item > .dropdown-item').eq(0).hasClass('selected'), - 'first element should not be selected'); - assert.ok(dropdownMenu.$('.o_menu_item > .dropdown-item').eq(1).hasClass('selected'), - 'second element should be selected'); - - dropdownMenu.destroy(); - }); - - QUnit.test('click on an item without options should toggle it', async function (assert) { - assert.expect(7); - - var self = this; - var dropdownMenu = await createDropdownMenu(this.items, { - intercepts: { - menu_item_clicked: function (ev) { - assert.strictEqual(ev.data.id, 1); - self.items[0].isActive = !self.items[0].isActive; - dropdownMenu.update(self.items); - }, - }, - }); - await testUtils.dom.click(dropdownMenu.$('button:first')); - assert.doesNotHaveClass(dropdownMenu.$('.o_menu_item:first > .dropdown-item').first(), 'selected'); - await testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first()); - assert.hasClass(dropdownMenu.$('.o_menu_item:first > .dropdown-item'), 'selected'); - assert.ok(dropdownMenu.$('.o_menu_item:first').is(':visible'), - 'item should still be visible'); - await testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first()); - assert.doesNotHaveClass(dropdownMenu.$('.o_menu_item:first > .dropdown-item').first(), 'selected'); - assert.ok(dropdownMenu.$('.o_menu_item:first').is(':visible'), - 'item should still be visible'); - dropdownMenu.destroy(); - }); - - QUnit.test('click on an item should not change url', async function (assert) { - assert.expect(0); - - var dropdownMenu = await createDropdownMenu(this.items); - await testUtils.dom.click(dropdownMenu.$('.o_dropdown_toggler_btn')); - dropdownMenu.$el.click(function () { - // we do not want a click to get out and change the url, for example - throw new Error('No click should get out of the dropdown menu'); - }); - await testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first()); - - dropdownMenu.destroy(); - }); - - QUnit.test('options rendering', async function (assert) { - assert.expect(3); - - this.items[0].hasOptions = true; - this.items[0].options = [ - {optionId: 1, description: "First Option", groupId: 1}, - {optionId: 2, description: "Second Option", groupId: 1} - ]; - this.items[0].currentOptionIds = new Set(); - var dropdownMenu = await createDropdownMenu(this.items); - testUtils.dom.click(dropdownMenu.$('button:first')); - assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4); - // open options menu - await testUtils.dom.click(dropdownMenu.$('span.fa-caret-right')); - assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 7); - // close options menu - await testUtils.dom.click(dropdownMenu.$('span.fa-caret-down')); - assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4); - - dropdownMenu.destroy(); - }); - - QUnit.test('close menu closes also submenus', async function (assert) { - assert.expect(2); - - this.items[0].hasOptions = true; - this.items[0].options = [ - {optionId: 1, description: "First Option"}, - {optionId: 2, description: "Second Option"} - ]; - this.items[0].currentOptionIds = new Set(); - var dropdownMenu = await createDropdownMenu(this.items); - // open dropdown menu - testUtils.dom.click(dropdownMenu.$('button:first')); - // open options menu - await testUtils.dom.click(dropdownMenu.$('span.fa-caret-right')); - assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 7); - await testUtils.dom.click(dropdownMenu.$('button:first')); - await testUtils.dom.click(dropdownMenu.$('button:first')); - assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4); - - dropdownMenu.destroy(); - }); - - QUnit.test('click on an option should trigger the event "item_option_clicked" with appropriate data', async function (assert) { - assert.expect(18); - - var self = this; - var eventNumber = 0; - this.items[0].hasOptions = true; - this.items[0].options = [ - {optionId: 1, description: "First Option"}, - {optionId: 2, description: "Second Option"} - ]; - this.items[0].currentOptionIds = new Set(); - var dropdownMenu = await createDropdownMenu(this.items, { - intercepts: { - item_option_clicked: function (ev) { - eventNumber++; - assert.strictEqual(ev.data.id, 1); - if (eventNumber === 1) { - assert.strictEqual(ev.data.optionId, 1); - self.items[0].isActive = true; - self.items[0].currentOptionIds.add(1); - } - if (eventNumber === 2) { - assert.strictEqual(ev.data.optionId, 2); - self.items[0].currentOptionIds = new Set([1,2]); - } - if (eventNumber === 3) { - assert.strictEqual(ev.data.optionId, 1); - self.items[0].currentOptionIds = new Set([2]); - } - if (eventNumber === 4) { - assert.strictEqual(ev.data.optionId, 2); - self.items[0].isActive = false; - self.items[0].currentOptionIds.clear(); - } - dropdownMenu.update(self.items); - }, - }, - }); - await testUtils.nextTick(); - // open dropdown menu - await testUtils.dom.click(dropdownMenu.$('button:first')); - assert.containsN(dropdownMenu, '.dropdown-divider, .o_menu_item', 4); - await testUtils.dom.clickFirst(dropdownMenu.$('.o_menu_item')); - // click on first option - await testUtils.dom.click(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0)); - assert.hasClass(dropdownMenu.$('.o_menu_item > .dropdown-item').first(), 'selected'); - assert.hasClass(dropdownMenu.$('.o_item_option> .dropdown-item').eq(0),'selected'); - assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(1), 'selected'); - // click on second option - await testUtils.dom.click($('.o_item_option > .dropdown-item').eq(1)); - assert.hasClass(dropdownMenu.$('.o_menu_item > .dropdown-item').first(), 'selected'); - assert.hasClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0), 'selected'); - assert.hasClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(1), 'selected'); - // click again on first option - await testUtils.dom.click(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0)); - // click again on second option - await testUtils.dom.click($('.o_item_option > .dropdown-item').eq(1)); - assert.doesNotHaveClass(dropdownMenu.$('.o_menu_item > .dropdown-item').first(), 'selected'); - assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0), 'selected'); - assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(1), 'selected'); - - dropdownMenu.destroy(); - }); -}); -}); diff --git a/addons/website_sale/static/tests/tours/website_sale_shop_cart_recovery.js b/addons/website_sale/static/tests/tours/website_sale_shop_cart_recovery.js index 079029ee4e3..aeae75fc0b8 100644 --- a/addons/website_sale/static/tests/tours/website_sale_shop_cart_recovery.js +++ b/addons/website_sale/static/tests/tours/website_sale_shop_cart_recovery.js @@ -46,7 +46,7 @@ tour.register('shop_cart_recovery', { }, { content: "click action", - trigger: '.btn:containsExact("Action")', + trigger: '.o_dropdown_toggler_btn:contains("Action")', }, { content: "click Send a Cart Recovery Email", |
