[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>
This commit is contained in:
Julien Mougenot
2020-03-13 14:08:33 +00:00
co-authored by Mathieu Duckerts-Antoine
parent bb8eb766a8
commit 804507ef49
35 changed files with 1076 additions and 3691 deletions
@@ -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',
+40 -44
View File
@@ -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();
});
+110 -147
View File
@@ -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');
"use strict";
var createView = testUtils.createView;
const FormView = require('web.FormView');
const testUtils = require('web.test_utils');
/*
* @override
* Avoid breaking other tests because of the new route
* that the module introduces
*/
var _addGoogleDocItemsOriginal = GoogleDriveSideBar.prototype._addGoogleDocItems;
const cpHelpers = testUtils.controlPanel;
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},
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: [],
}
};
},
});
await cpHelpers.toggleActionMenu(form);
afterEach: function() {
GoogleDriveSideBar.prototype._addGoogleDocItems = _addGoogleDocItemsMocked;
}
assert.containsOnce(form, '.oe_share_gdoc_item',
"The button to the google action should be present");
}, function () {
QUnit.module('Google Drive Sidebar');
await cpHelpers.toggleMenuItem(form, "Cyberdyne Systems");
QUnit.test('rendering of the google drive attachments in Sidebar', async function (assert) {
assert.expect(3);
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');
QUnit.test('click on the google drive attachments after switching records', async function (assert) {
assert.expect(4);
assert.strictEqual($googleAction.length, 1,
'The button to the google action should be present');
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");
// click on gdrive sidebar item
await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
await testUtils.dom.click($googleAction);
await cpHelpers.pagerNext(form);
form.destroy();
});
currentID = 2;
await cpHelpers.toggleActionMenu(form);
await cpHelpers.toggleMenuItem(form, "Cyberdyne Systems");
QUnit.test('click on the google drive attachments after switching records', async function (assert) {
assert.expect(3);
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();
});
});
});
@@ -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,
});
@@ -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',
]);
+2 -3
View File
@@ -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();
});
+58 -49
View File
@@ -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");
// needed to handle events triggered by the controlPanelModel
discuss.on_attach_callback();
await testUtils.nextTick();
// 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");
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 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();
// 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");
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");
// 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);
discuss.destroy();
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 testUtils.fields.editInput(discuss.$('.o_favorite_name input'), 'War');
await testUtils.dom.click(discuss.$('.o_save_favorite button'));
await cpHelpers.toggleFavoriteMenu(discuss);
await cpHelpers.toggleSaveFavorite(discuss);
await cpHelpers.editFavoriteName(discuss, "War");
await cpHelpers.saveFavorite(discuss);
discuss.on_detach_callback();
discuss.destroy();
});
@@ -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,
@@ -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,
});
@@ -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,
@@ -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,
});
@@ -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"]);
@@ -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'));
});
});
});
@@ -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);
QUnit.module('CustomFileInput');
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.test("Upload a file: default props", 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, {
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 input = customFileInput.el.querySelector('input');
const parent = new Parent();
await parent.mount(testUtils.prepareTarget());
const fileInput = parent.el;
const input = fileInput.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");
// 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");
await testUtils.dom.triggerEvent(input, 'change');
// Change props
Object.assign(parent.state, {
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: {
async httpRequest(route, params) {
assert.deepEqual(params, {
id: 5,
model: 'res.model',
csrf_token: odoo.csrf_token,
ufile: [],
});
assert.step(route);
return '[]';
},
},
},
props: {
accepted_file_extensions: '.png',
action: '/web/binary/upload_attachment',
id: 5,
model: 'res.model',
multi_upload: true,
});
await testUtils.nextTick();
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.verifySteps(['/web/binary/upload', '/web/binary/upload_attachment']);
parent.destroy();
},
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.verifySteps(['/web/binary/upload_attachment']);
customFileInput.destroy();
});
});
});
@@ -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'};
@@ -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");
@@ -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
@@ -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();
});
@@ -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();
});
@@ -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");
+105 -94
View File
@@ -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');
assert.strictEqual(form.pager.$('.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');
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'));
+70 -80
View File
@@ -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 () {
+16 -17
View File
@@ -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();
}
+142 -143
View File
@@ -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');
+97 -101
View File
@@ -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(),
@@ -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", {
@@ -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();
});
});
});
@@ -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();
});
});
});
@@ -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);
File diff suppressed because it is too large Load Diff
@@ -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':
@@ -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"/>
@@ -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();
});
});
});
@@ -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",
@@ -77,6 +77,11 @@ odoo.define('web.test.x2many', function (require) {
}, { // add message a
content: "Select First Tab",
trigger: 'a[role=tab]:first',
// We check the "Save" button is in the DOM to ensure that the form renderer
// is fully loaded and is on the right pane (right now the renderer dispatches
// a click on its last active pane header. We can remove this assert once the
// form renderer behaves properly).
extra_trigger: 'button.o_form_button_save',
}, {
content: "create new message a",
trigger: '.o_form_sheet .tab-pane:eq(0) .o_field_x2many_list_row_add a'