diff --git a/addons/web/static/tests/components/action_menus_tests.js b/addons/web/static/tests/components/action_menus_tests.js
index f4229b30493..e17ae95ba78 100644
--- a/addons/web/static/tests/components/action_menus_tests.js
+++ b/addons/web/static/tests/components/action_menus_tests.js
@@ -105,7 +105,6 @@ odoo.define('web.action_menus_tests', function (require) {
active_id: 23,
active_ids: [23],
active_model: 'hobbit',
- select_all: false, // default props
};
assert.deepEqual(args.context, expectedContext);
assert.step('load-action');
@@ -178,7 +177,6 @@ odoo.define('web.action_menus_tests', function (require) {
active_id: 23,
active_ids: [23],
active_model: 'hobbit',
- select_all: false, // default props
};
assert.deepEqual(args.context, expectedContext);
assert.step('load-action');
diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js
index a59a925306f..d59cafacd28 100644
--- a/addons/web/static/tests/helpers/mock_server.js
+++ b/addons/web/static/tests/helpers/mock_server.js
@@ -1093,6 +1093,20 @@ var MockServer = Class.extend({
}
return true;
},
+ /**
+ * Simulate a 'search' operation
+ *
+ * @private
+ * @param {string} model
+ * @param {Array} args
+ * @param {Object} kwargs
+ * @param {integer} [kwargs.limit]
+ * @returns {integer[]}
+ */
+ _mockSearch: function (model, args, kwargs) {
+ const limit = kwargs.limit || Number.MAX_VALUE;
+ return this._getRecords(model, args[0]).map(r => r.id).slice(0, limit);
+ },
/**
* Simulate a 'search_count' operation
*
@@ -1340,6 +1354,9 @@ var MockServer = Class.extend({
case 'read_progress_bar':
return Promise.resolve(this._mockReadProgressBar(args.model, args.kwargs));
+ case 'search':
+ return Promise.resolve(this._mockSearch(args.model, args.args, args.kwargs));
+
case 'search_count':
return Promise.resolve(this._mockSearchCount(args.model, args.args));
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index 852c74d922b..cf0736f86f1 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -1251,8 +1251,76 @@ QUnit.module('Views', {
list.destroy();
});
+ QUnit.test('selection box is properly displayed (single page)', async function (assert) {
+ assert.expect(11);
+
+ var list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '',
+ });
+
+ assert.containsN(list, '.o_data_row', 4);
+ assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
+
+ // select a record
+ await testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input'));
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
+ assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
+ assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '1 selected');
+
+ // select all records of first page
+ await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
+ assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
+ assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '4 selected');
+
+ // unselect a record
+ await testUtils.dom.click(list.$('.o_data_row:nth(1) .o_list_record_selector input'));
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
+ assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
+ assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '3 selected');
+
+ list.destroy();
+ });
+
+ QUnit.test('selection box is properly displayed (multi pages)', async function (assert) {
+ assert.expect(10);
+
+ var list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '',
+ });
+
+ assert.containsN(list, '.o_data_row', 3);
+ assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
+
+ // select a record
+ await testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input'));
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
+ assert.containsNone(list.$('.o_list_selection_box'), '.o_list_select_domain');
+ assert.strictEqual(list.$('.o_list_selection_box').text().trim(), '1 selected');
+
+ // select all records of first page
+ await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
+ assert.containsOnce(list.$('.o_list_selection_box'), '.o_list_select_domain');
+ assert.strictEqual(list.$('.o_list_selection_box').text().replace(/\s+/g, ' ').trim(),
+ '3 selected Select all 4');
+
+ // select all domain
+ await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
+ assert.strictEqual(list.$('.o_list_selection_box').text().trim(), 'All 4 selected');
+
+ list.destroy();
+ });
+
QUnit.test('selection is reset on reload', async function (assert) {
- assert.expect(5);
+ assert.expect(8);
var list = await createView({
View: ListView,
@@ -1264,6 +1332,7 @@ QUnit.module('Views', {
'',
});
+ assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '32',
"total should be 32 (no record selected)");
@@ -1271,6 +1340,7 @@ QUnit.module('Views', {
var $firstRowSelector = list.$('tbody .o_list_record_selector input').first();
testUtils.dom.click($firstRowSelector);
assert.ok($firstRowSelector.is(':checked'), "first row should be selected");
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '10',
"total should be 10 (first record selected)");
@@ -1279,6 +1349,7 @@ QUnit.module('Views', {
$firstRowSelector = list.$('tbody .o_list_record_selector input').first();
assert.notOk($firstRowSelector.is(':checked'),
"first row should no longer be selected");
+ assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '32',
"total should be 32 (no more record selected)");
@@ -1286,7 +1357,7 @@ QUnit.module('Views', {
});
QUnit.test('selection is kept on render without reload', async function (assert) {
- assert.expect(6);
+ assert.expect(10);
var list = await createView({
View: ListView,
@@ -1301,17 +1372,20 @@ QUnit.module('Views', {
});
assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus');
+ assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
// 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.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus');
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
// 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.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus');
+ assert.containsOnce(list.$('.o_cp_buttons'), '.o_list_selection_box');
// close and open blip grouping and verify blip are unchecked
await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
@@ -1319,6 +1393,7 @@ QUnit.module('Views', {
assert.containsNone(list, '.o_data_row input:checked',
"opening and closing a grouping uncheck its elements");
assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus');
+ assert.containsNone(list.$('.o_cp_buttons'), '.o_list_selection_box');
list.destroy();
});
@@ -2865,7 +2940,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list without import button', async function (assert) {
+ QUnit.test('list with group_by_no_leaf flag in context', async function (assert) {
assert.expect(1);
var list = await createView({
@@ -2878,7 +2953,7 @@ QUnit.module('Views', {
}
});
- assert.ok(!list.$buttons, "should not have any buttons");
+ assert.containsNone(list, '.o_list_buttons', "should not have any buttons");
list.destroy();
});
@@ -4260,7 +4335,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('execute ActionMenus actions with correct params', async function (assert) {
+ QUnit.test('execute ActionMenus actions with correct params (single page)', async function (assert) {
assert.expect(12);
const list = await createView({
@@ -4320,9 +4395,78 @@ QUnit.module('Views', {
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":[]}}',
- '{"action_id":44,"context":{"active_id":2,"active_ids":[2,3,4],"active_model":"foo","select_all":false,"active_domain":[]}}',
- '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2],"active_model":"foo","select_all":false,"active_domain":[["bar","=",true]]}}',
+ '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3,4],"active_model":"foo","active_domain":[]}}',
+ '{"action_id":44,"context":{"active_id":2,"active_ids":[2,3,4],"active_model":"foo","active_domain":[]}}',
+ '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2],"active_model":"foo","active_domain":[["bar","=",true]]}}',
+ ]);
+
+ list.destroy();
+ });
+
+ QUnit.test('execute ActionMenus actions with correct params (multi pages)', async function (assert) {
+ assert.expect(13);
+
+ const list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '',
+ toolbar: {
+ action: [{
+ id: 44,
+ name: 'Custom Action',
+ type: 'ir.actions.server',
+ }],
+ print: [],
+ },
+ mockRPC: function (route, args) {
+ if (route === '/web/action/load') {
+ assert.step(JSON.stringify(args));
+ return Promise.resolve({});
+ }
+ return this._super(...arguments);
+ },
+ viewOptions: {
+ hasActionMenus: true,
+ },
+ });
+
+ assert.containsNone(list.el, 'div.o_control_panel .o_cp_action_menus');
+ assert.containsN(list, '.o_data_row', 2);
+
+ // select all records
+ await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
+ assert.containsN(list, '.o_list_record_selector input:checked', 3);
+ assert.containsOnce(list, '.o_list_selection_box .o_list_select_domain');
+ assert.containsOnce(list.el, 'div.o_control_panel .o_cp_action_menus');
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, "Custom Action");
+
+ // select all domain
+ await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
+ assert.containsN(list, '.o_list_record_selector input:checked', 3);
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, "Custom Action");
+
+ // add a domain
+ await list.reload({ domain: [['bar', '=', true]] });
+ assert.containsNone(list, '.o_list_selection_box .o_list_select_domain');
+
+ // select all domain
+ await testUtils.dom.click(list.$('thead .o_list_record_selector input'));
+ await testUtils.dom.click(list.$('.o_list_selection_box .o_list_select_domain'));
+ assert.containsN(list, '.o_list_record_selector input:checked', 3);
+ assert.containsNone(list, '.o_list_selection_box .o_list_select_domain');
+
+ await cpHelpers.toggleActionMenu(list);
+ await cpHelpers.toggleMenuItem(list, "Custom Action");
+
+ assert.verifySteps([
+ '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2],"active_model":"foo","active_domain":[]}}',
+ '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3,4],"active_model":"foo","active_domain":[]}}',
+ '{"action_id":44,"context":{"active_id":1,"active_ids":[1,2,3],"active_model":"foo","active_domain":[["bar","=",true]]}}',
]);
list.destroy();