summaryrefslogtreecommitdiff
path: root/addons/web/static/tests
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-01-09 19:59:27 +0100
committerChristophe Simonis <chs@odoo.com>2019-01-09 19:59:27 +0100
commitd7c5bc02cc2b27442f0d4c8aca70266762be2a32 (patch)
tree3a675d15b539a4474be38704405b318bebecdce7 /addons/web/static/tests
parent37b518f1749aff3d6ffb2246c32f2aa1e67d9067 (diff)
parent8aa8548d8ab68feb13f3bde51c557db84877e809 (diff)
[MERGE] forward port branch saas-12.1 up to 8aa8548d8ab
Diffstat (limited to 'addons/web/static/tests')
-rw-r--r--addons/web/static/tests/chrome/action_manager_tests.js193
-rw-r--r--addons/web/static/tests/core/py_utils_tests.js7
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js166
-rw-r--r--addons/web/static/tests/helpers/test_utils_create.js1
-rw-r--r--addons/web/static/tests/helpers/test_utils_dom.js17
-rw-r--r--addons/web/static/tests/tools/debug_manager_tests.js4
-rw-r--r--addons/web/static/tests/views/calendar_tests.js92
-rw-r--r--addons/web/static/tests/views/control_panel_tests.js62
-rw-r--r--addons/web/static/tests/views/form_tests.js72
-rw-r--r--addons/web/static/tests/views/graph_tests.js33
-rw-r--r--addons/web/static/tests/views/kanban_mobile_tests.js6
-rw-r--r--addons/web/static/tests/views/kanban_tests.js63
-rw-r--r--addons/web/static/tests/views/pivot_tests.js161
-rw-r--r--addons/web/static/tests/views/search_filters_menu_tests.js140
-rw-r--r--addons/web/static/tests/views/search_view_tests.js34
15 files changed, 898 insertions, 153 deletions
diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js
index e1b14b4d363..990c166a419 100644
--- a/addons/web/static/tests/chrome/action_manager_tests.js
+++ b/addons/web/static/tests/chrome/action_manager_tests.js
@@ -735,6 +735,37 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
+ QUnit.test('properly load default record', function (assert) {
+ assert.expect(5);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method || route);
+ return this._super.apply(this, arguments);
+ },
+ });
+ actionManager.loadState({
+ action: 3,
+ id: "", // might happen with bbq and id=& in URL
+ model: 'partner',
+ view_type: 'form',
+ });
+
+ assert.containsOnce(actionManager, '.o_form_view',
+ "should have rendered a form view");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ 'default_get',
+ ]);
+
+ actionManager.destroy();
+ });
+
QUnit.test('load requested view for act window actions', function (assert) {
assert.expect(6);
@@ -2095,6 +2126,39 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
+ QUnit.test('sidebar is present in list view', function (assert) {
+ assert.expect(5);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ var res = this._super.apply(this, arguments);
+ if (args.method === 'load_views') {
+ assert.strictEqual(args.kwargs.options.toolbar, true,
+ "should ask for toolbar information");
+ return res.then(function (fieldsViews) {
+ fieldsViews.list.toolbar = {
+ print: [{name: "Print that record"}],
+ };
+ return fieldsViews;
+ });
+ }
+ return res;
+ },
+ });
+ 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")'));
+ 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")'));
+
+ actionManager.destroy();
+ });
+
QUnit.test('can switch between views', function (assert) {
assert.expect(18);
@@ -2155,6 +2219,62 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
+ QUnit.test('orderedBy in context is not propagated when executing another action', function (assert) {
+ assert.expect(6);
+
+ this.data.partner.fields.foo.sortable = true,
+
+ this.archs['partner,false,form'] = '<header>' +
+ '<button name="8" string="Execute action" type="action"/>' +
+ '</header>';
+
+ var searchReadCount = 1;
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (route === '/web/dataset/search_read') {
+ if (searchReadCount === 1) {
+ assert.strictEqual(args.model, 'partner');
+ assert.notOk(args.sort);
+ }
+ if (searchReadCount === 2) {
+ assert.strictEqual(args.model, 'partner');
+ assert.strictEqual(args.sort, "foo ASC");
+ }
+ if (searchReadCount === 3) {
+ assert.strictEqual(args.model, 'pony');
+ assert.notOk(args.sort);
+ }
+ searchReadCount += 1;
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+ actionManager.doAction(3);
+
+ // Simulate the activation of a filter
+ var searchData = {
+ domains: [[["foo", "=", "yop"]]],
+ contexts: [{
+ orderedBy: [],
+ }],
+ };
+ actionManager.trigger_up('search', searchData);
+
+ // Sort records
+ actionManager.$('.o_list_view th.o_column_sortable').click();
+
+ // get to the form view of the model, on the first record
+ actionManager.$('.o_data_cell:first').click();
+
+ // Change model by clicking on the button within the form
+ actionManager.$('.o_form_view button').click();
+
+ actionManager.destroy();
+ });
+
QUnit.test('breadcrumbs are updated when switching between views', function (assert) {
assert.expect(10);
@@ -3314,6 +3434,79 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
+ QUnit.test('fullscreen on action change: back to a "current" action', function (assert) {
+ assert.expect(3);
+
+ this.actions[0].target = 'fullscreen';
+ this.archs['partner,false,form'] = '<form>' +
+ '<button name="1" type="action" class="oe_stat_button" />' +
+ '</form>';
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ intercepts: {
+ toggle_fullscreen: function (ev) {
+ var fullscreen = ev.data.fullscreen;
+
+ switch (toggleFullscreenCalls) {
+ case 0:
+ assert.strictEqual(fullscreen, false);
+ break;
+ case 1:
+ assert.strictEqual(fullscreen, true);
+ break;
+ case 2:
+ assert.strictEqual(fullscreen, false);
+ break;
+ }
+ },
+ },
+
+ });
+
+ var toggleFullscreenCalls = 0;
+ actionManager.doAction(6);
+
+ toggleFullscreenCalls = 1;
+ actionManager.$('button[name=1]').click();
+
+ toggleFullscreenCalls = 2;
+ $('.breadcrumb li a:first').click();
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('fullscreen on action change: all "fullscreen" actions', function (assert) {
+ assert.expect(3);
+
+ this.actions[5].target = 'fullscreen';
+ this.archs['partner,false,form'] = '<form>' +
+ '<button name="1" type="action" class="oe_stat_button" />' +
+ '</form>';
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ intercepts: {
+ toggle_fullscreen: function (ev) {
+ var fullscreen = ev.data.fullscreen;
+ assert.strictEqual(fullscreen, true);
+ },
+ },
+ });
+
+ actionManager.doAction(6);
+
+ actionManager.$('button[name=1]').click();
+
+ $('.breadcrumb li a:first').click();
+
+ actionManager.destroy();
+ });
+
QUnit.module('"ir.actions.act_window_close" actions');
QUnit.test('close the currently opened dialog', function (assert) {
diff --git a/addons/web/static/tests/core/py_utils_tests.js b/addons/web/static/tests/core/py_utils_tests.js
index d59fd30f957..be5760fc6c7 100644
--- a/addons/web/static/tests/core/py_utils_tests.js
+++ b/addons/web/static/tests/core/py_utils_tests.js
@@ -1254,6 +1254,13 @@ QUnit.module('core', function () {
assert.checkAST(expr);
});
+ QUnit.test("parse escaped quoted strings", function (assert) {
+ assert.expect(2);
+
+ assert.checkAST(`'\"'`, "a string containing \"");
+ assert.checkAST(`'\'`, "a string containing \'");
+ });
+
QUnit.module('pyutils (_normalizeDomain)');
QUnit.assert.checkNormalization = function (domain, normalizedDomain) {
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index 6c3493828ad..15999ca952e 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -228,6 +228,90 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('widget many2many_checkboxes in a subview', function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<sheet>' +
+ '<notebook>' +
+ '<page string="Turtles">' +
+ '<field name="turtles" mode="tree">' +
+ '<tree>' +
+ '<field name="id"/>' +
+ '</tree>' +
+ '</field>' +
+ '</page>' +
+ '</notebook>' +
+ '</sheet>' +
+ '</form>',
+ archs: {
+ 'turtle,false,form': '<form>' +
+ '<field name="partner_ids" widget="many2many_checkboxes"/>' +
+ '</form>',
+ },
+ res_id: 1,
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ form.$('.o_data_cell').click();
+ // edit the partner_ids field by (un)checking boxes on the widget
+ var $firstCheckbox = $('.modal .custom-control-input').first();
+ $firstCheckbox.click();
+ assert.ok($firstCheckbox.prop('checked'), "the checkbox should be ticked");
+ var $secondCheckbox = $('.modal .custom-control-input').eq(1);
+ $secondCheckbox.click();
+ assert.notOk($secondCheckbox.prop('checked'), "the checkbox should be unticked");
+ form.destroy();
+ });
+
+ QUnit.test('delete a record while adding another one in a multipage', function (assert) {
+ // in a many2one with at least 2 pages, add a new line. Delete the line above it.
+ // (the onchange makes it so that the virtualID is inserted in the middle of the currentResIDs.)
+ // it should load the next line to display it on the page.
+ assert.expect(2);
+
+ this.data.partner.records[0].turtles = [2, 3];
+ this.data.partner.onchanges.turtles = function (obj) {
+ obj.turtles = [[5]].concat(obj.turtles);
+ };
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="turtles">' +
+ '<tree editable="bottom" limit="1" decoration-muted="turtle_bar == False">' +
+ '<field name="turtle_foo"/>' +
+ '<field name="turtle_bar"/>' +
+ '</tree>' +
+ '</field>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ form.$buttons.find('.o_form_button_edit').click();
+ // add a line (virtual record)
+ form.$('.o_field_x2many_list_row_add a').click();
+ form.$('.o_input').val('pi').trigger('input');
+ // delete the line above it
+ form.$('.o_list_record_remove').first().click();
+ // the next line should be displayed below the newly added one
+ assert.strictEqual(form.$('.o_data_row').length, 2, "should have 2 records");
+ assert.strictEqual(form.$('.o_data_row .o_data_cell:first-child').text(), 'pikawa',
+ "should display the correct records on page 1");
+
+ form.destroy();
+ });
+
QUnit.test('one2many, onchange, edition and multipage...', function (assert) {
assert.expect(7);
@@ -252,7 +336,7 @@ QUnit.module('relational_fields', {
'</form>',
res_id: 1,
mockRPC: function (route, args) {
- assert.step(args.method + ' ' + args.model)
+ assert.step(args.method + ' ' + args.model);
return this._super(route, args);
},
viewOptions: {
@@ -362,6 +446,39 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('many2many read, field context is properly sent', function (assert) {
+ assert.expect(4);
+
+ this.data.partner.fields.timmy.context = {hello: 'world'};
+ this.data.partner.records[0].timmy = [12];
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="timmy" widget="many2many_tags"/>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (args.method === 'read' && args.model === 'partner_type') {
+ assert.step(args.kwargs.context.hello);
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.verifySteps(['world']);
+
+ form.$buttons.find('.o_form_button_edit').click();
+ var $m2mInput = form.$('.o_field_many2manytags input');
+ $m2mInput.click();
+ $m2mInput.autocomplete('widget').find('li:first()').click();
+ assert.verifySteps(['world', 'world']);
+
+ form.destroy();
+ });
+
QUnit.module('FieldStatus');
QUnit.test('static statusbar widget on many2one field', function (assert) {
@@ -1323,6 +1440,53 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('widget many2many_tags in one2many with display_name', function (assert) {
+ assert.expect(4);
+ this.data.turtle.records[0].partner_ids = [2];
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<sheet>' +
+ '<field name="turtles">' +
+ '<tree>' +
+ '<field name="partner_ids" widget="many2many_tags"/>' + // will use display_name
+ '</tree>' +
+ '<form>' +
+ '<sheet>' +
+ '<field name="partner_ids"/>' +
+ '</sheet>' +
+ '</form>' +
+ '</field>' +
+ '</sheet>' +
+ '</form>',
+ archs: {
+ 'partner,false,list': '<tree><field name="foo"/></tree>',
+ },
+ res_id: 1,
+ });
+
+ assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o_list_view .o_field_many2manytags[name="partner_ids"]').text().replace(/\s/g, ''),
+ "secondrecordaaa", "the tags should be correctly rendered");
+
+ // open the x2m form view
+ form.$('.o_field_one2many[name="turtles"] .o_list_view td.o_data_cell:first').click();
+ assert.strictEqual($('.modal .o_form_view .o_field_many2many[name="partner_ids"] .o_list_view .o_data_cell').text(),
+ "blipMy little Foo Value", "the list view should be correctly rendered with foo");
+
+ $('.modal button.o_form_button_cancel').click();
+ assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o_list_view .o_field_many2manytags[name="partner_ids"]').text().replace(/\s/g, ''),
+ "secondrecordaaa", "the tags should still be correctly rendered");
+
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o_list_view .o_field_many2manytags[name="partner_ids"]').text().replace(/\s/g, ''),
+ "secondrecordaaa", "the tags should still be correctly rendered");
+
+ form.destroy();
+ });
+
QUnit.test('widget many2many_tags: tags title attribute', function (assert) {
assert.expect(1);
this.data.turtle.records[0].partner_ids = [2];
diff --git a/addons/web/static/tests/helpers/test_utils_create.js b/addons/web/static/tests/helpers/test_utils_create.js
index 0adb13d466f..5a64512260e 100644
--- a/addons/web/static/tests/helpers/test_utils_create.js
+++ b/addons/web/static/tests/helpers/test_utils_create.js
@@ -135,6 +135,7 @@ function createAsyncView(params) {
currentId: 'res_id' in params ? params.res_id : undefined,
domain: params.domain || [],
context: params.context || {},
+ hasSidebar: false,
});
// patch the View to handle the groupBy given in params, as we can't give it
// in init (unlike the domain and context which can be set in the action)
diff --git a/addons/web/static/tests/helpers/test_utils_dom.js b/addons/web/static/tests/helpers/test_utils_dom.js
index b89f5a8eb5f..dcf9eab6e15 100644
--- a/addons/web/static/tests/helpers/test_utils_dom.js
+++ b/addons/web/static/tests/helpers/test_utils_dom.js
@@ -17,6 +17,10 @@ odoo.define('web.test_utils_dom', function () {
* events, but it is enough to help test drag and drop operations with jqueryUI
* sortable.
*
+ * @todo: remove the withTrailingClick option when the jquery update branch is
+ * merged. This is not the default as of now, because handlers are triggered
+ * synchronously, which is not the same as the 'reality'.
+ *
* @param {jqueryElement} $el
* @param {jqueryElement} $to
* @param {Object} [options]
@@ -27,9 +31,13 @@ odoo.define('web.test_utils_dom', function () {
* @param {boolean} [options.continueMove=false] whether to trigger the
* mousedown action (will only work after another call of this function with
* without this option)
+ * @param {boolean} [options.withTrailingClick=false] if true, this utility
+ * function will also trigger a click on the target after the mouseup event
+ * (this is actually what happens when a drag and drop operation is done)
*/
function dragAndDrop($el, $to, options) {
- var position = (options && options.position) || 'center';
+ options = options || {};
+ var position = options.position || 'center';
var elementCenter = $el.offset();
var toOffset = $to.offset();
@@ -58,7 +66,7 @@ function dragAndDrop($el, $to, options) {
toOffset.top += bound.top;
}
$el.trigger($.Event("mouseenter"));
- if (!(options && options.continueMove)) {
+ if (!(options.continueMove)) {
elementCenter.left += $el.outerWidth() / 2;
elementCenter.top += $el.outerHeight() / 2;
@@ -75,12 +83,15 @@ function dragAndDrop($el, $to, options) {
pageY: toOffset.top
}));
- if (!(options && options.disableDrop)) {
+ if (!options.disableDrop) {
$el.trigger($.Event("mouseup", {
which: 1,
pageX: toOffset.left,
pageY: toOffset.top
}));
+ if (options.withTrailingClick) {
+ $el.click();
+ }
} else {
// It's impossible to drag another element when one is already
// being dragged. So it's necessary to finish the drop when the test is
diff --git a/addons/web/static/tests/tools/debug_manager_tests.js b/addons/web/static/tests/tools/debug_manager_tests.js
index fde90105bfb..fb454aae0d1 100644
--- a/addons/web/static/tests/tools/debug_manager_tests.js
+++ b/addons/web/static/tests/tools/debug_manager_tests.js
@@ -46,6 +46,10 @@ QUnit.module('DebugManager', {}, function () {
intercepts: {
do_action: function (event) {
assert.deepEqual(event.data.action, {
+ context: {
+ default_res_model: "test.model",
+ default_res_id: 5,
+ },
domain: [["res_model", "=", "test.model"],["res_id", "=", 5]],
name: "Manage Attachments",
res_model: "ir.attachment",
diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js
index 3f4c6376d5b..264a00cc52a 100644
--- a/addons/web/static/tests/views/calendar_tests.js
+++ b/addons/web/static/tests/views/calendar_tests.js
@@ -557,6 +557,98 @@ QUnit.module('Views', {
$view.remove();
});
+ QUnit.test('default week start (US)', function (assert) {
+ // if not given any option, default week start is on Sunday
+ assert.expect(1);
+ var done = assert.async();
+
+ createAsyncView({
+ View: CalendarView,
+ model: 'event',
+ data: this.data,
+ arch:
+ '<calendar class="o_calendar_test" '+
+ 'date_start="start" '+
+ 'date_stop="stop" '+
+ 'mode="week">'+
+ '</calendar>',
+ archs: archs,
+
+ viewOptions: {
+ initialDate: initialDate,
+ },
+ }).then(function (calendar) {
+ assert.strictEqual(calendar.$('.fc-day-header').first().text(), "Sun 12/11",
+ "The first day of the week should be Sunday");
+ calendar.destroy();
+ done();
+ });
+ });
+
+ QUnit.test('European week start', function (assert) {
+ // the week start depends on the locale
+ assert.expect(1);
+ var done = assert.async();
+
+ createAsyncView({
+ View: CalendarView,
+ model: 'event',
+ data: this.data,
+ arch:
+ '<calendar class="o_calendar_test" '+
+ 'date_start="start" '+
+ 'date_stop="stop" '+
+ 'mode="week">'+
+ '</calendar>',
+ archs: archs,
+
+ viewOptions: {
+ initialDate: initialDate,
+ },
+ translateParameters: {
+ week_start: 1,
+ },
+ }).then(function (calendar) {
+ assert.strictEqual(calendar.$('.fc-day-header').first().text(), "Mon 12/12",
+ "The first day of the week should be Monday");
+ calendar.destroy();
+ done();
+ });
+ });
+
+ QUnit.test('week numbering', function (assert) {
+ // week number depends on the week start, which depends on the locale
+ // the calendar library uses numbers [0 .. 6], while Odoo uses [1 .. 7]
+ // so if the modulo is not done, the week number is incorrect
+ assert.expect(1);
+ var done = assert.async();
+
+ createAsyncView({
+ View: CalendarView,
+ model: 'event',
+ data: this.data,
+ arch:
+ '<calendar class="o_calendar_test" '+
+ 'date_start="start" '+
+ 'date_stop="stop" '+
+ 'mode="week">'+
+ '</calendar>',
+ archs: archs,
+
+ viewOptions: {
+ initialDate: initialDate,
+ },
+ translateParameters: {
+ week_start: 7,
+ },
+ }).then(function (calendar) {
+ assert.strictEqual(calendar.$('.fc-week-number').text(), "W51",
+ "We should be on the 51st week");
+ calendar.destroy();
+ done();
+ });
+ });
+
QUnit.test('create event with timezone in week mode with formViewDialog European locale', function (assert) {
assert.expect(8);
diff --git a/addons/web/static/tests/views/control_panel_tests.js b/addons/web/static/tests/views/control_panel_tests.js
index 08cc1391719..ee191e4d3a9 100644
--- a/addons/web/static/tests/views/control_panel_tests.js
+++ b/addons/web/static/tests/views/control_panel_tests.js
@@ -120,6 +120,7 @@ QUnit.module('Views', {
assert.deepEqual(
controlPanelFactory.loadParams.groups,
[[{
+ context: {},
description: "Hello",
groupNumber: 2,
domain: "[]",
@@ -198,6 +199,7 @@ QUnit.module('Views', {
controlPanelFactory.loadParams.groups,
[[
{
+ "context": {},
"description": "Hello One",
"domain": "[]",
"groupNumber": 2,
@@ -205,6 +207,7 @@ QUnit.module('Views', {
"type": "filter"
},
{
+ "context": {},
"description": "Hello Two",
"domain": "[('bar', '=', 3)]",
"groupNumber": 2,
@@ -233,6 +236,7 @@ QUnit.module('Views', {
[
[
{
+ context: {},
description: "Hello One",
domain: "[]",
groupNumber: 2,
@@ -242,6 +246,7 @@ QUnit.module('Views', {
],
[
{
+ context: {},
description: "Hello Two",
domain: "[('bar', '=', 3)]",
groupNumber: 4,
@@ -267,6 +272,7 @@ QUnit.module('Views', {
[
[
{
+ context: {},
description: "Hello",
domain: "[]",
groupNumber: 2,
@@ -353,5 +359,61 @@ QUnit.module('Views', {
controlPanel.destroy();
});
+
+ QUnit.module('Control Panel behaviour');
+
+ QUnit.test('remove a facet with backspace', async function (assert) {
+ assert.expect(2);
+
+ var controlPanel = await createControlPanel({
+ model: 'partner',
+ arch: "<search><filter name=\"filterA\" string=\"A\" domain=\"[]\"/></search>",
+ data: this.data,
+ searchMenuTypes: ['filter'],
+ });
+ testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
+ testUtils.dom.click($('.o_menu_item a'));
+ assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'A',
+ 'should have a facet with A');
+
+ // delete a facet
+ controlPanel.$('input.o_searchview_input').trigger($.Event('keydown', {
+ which: $.ui.keyCode.BACKSPACE,
+ keyCode: $.ui.keyCode.BACKSPACE,
+ }));
+ assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0,
+ 'there should be no facet');
+
+ // delete nothing (should not crash)
+ controlPanel.$('input.o_searchview_input').trigger($.Event('keydown', {
+ which: $.ui.keyCode.BACKSPACE,
+ keyCode: $.ui.keyCode.BACKSPACE,
+ }));
+
+ controlPanel.destroy();
+ });
+
+ QUnit.module('Control Panel Rendering');
+
+ QUnit.test('invisible filters are not rendered', async function (assert) {
+ assert.expect(2);
+ var controlPanel = await createControlPanel({
+ model: 'partner',
+ arch: "<search>" +
+ "<filter name=\"filterA\" string=\"A\" domain=\"[]\"/>" +
+ "<filter name=\"filterB\" string=\"B\" invisible=\"1\" domain=\"[]\"/>" +
+ "</search>",
+ data: this.data,
+ searchMenuTypes: ['filter'],
+ context: {
+ search_disable_custom_filters: true,
+ },
+ });
+ testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
+ assert.containsOnce(controlPanel, '.o_menu_item a:contains("A")');
+ assert.containsNone(controlPanel, '.o_menu_item a:contains("B")');
+
+ controlPanel.destroy();
+ });
});
});
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index a120a6a7547..e1cb3277dba 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -17,6 +17,7 @@ var Widget = require('web.Widget');
var _t = core._t;
var createView = testUtils.createView;
var createAsyncView = testUtils.createAsyncView;
+var createActionManager = testUtils.createActionManager;
QUnit.module('Views', {
beforeEach: function () {
@@ -299,7 +300,78 @@ QUnit.module('Views', {
form.destroy();
});
+ QUnit.test('Form and subview with _view_ref contexts', function (assert) {
+ assert.expect(2);
+
+ this.data.product.fields.partner_type_ids = {string: "one2many field", type: "one2many", relation: "partner_type"},
+ this.data.product.records = [{id: 1, name: 'Tromblon', partner_type_ids: [12,14]}];
+ this.data.partner.records[0].product_id = 1;
+
+ var actionManager = createActionManager({
+ data: this.data,
+ archs: {
+ 'product,false,form': '<form>'+
+ '<field name="name"/>'+
+ '<field name="partner_type_ids" context="{\'tree_view_ref\': \'some_other_tree_view\'}"/>' +
+ '</form>',
+ 'partner_type,false,list': '<tree>'+
+ '<field name="color"/>'+
+ '</tree>',
+ 'product,false,search': '<search></search>',
+ },
+ mockRPC: function (route, args) {
+ if (args.method === 'load_views') {
+ var context = args.kwargs.context;
+ if (args.model === 'product') {
+ assert.deepEqual(context, {tree_view_ref: 'some_tree_view'},
+ 'The correct _view_ref should have been sent to the server, first time');
+ }
+ if (args.model === 'partner_type') {
+ assert.deepEqual(context, {tree_view_ref: 'some_other_tree_view'},
+ 'The correct _view_ref should have been sent to the server for the subview');
+ }
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="name"/>' +
+ '<field name="product_id" context="{\'tree_view_ref\': \'some_tree_view\'}"/>' +
+ '</form>',
+ res_id: 1,
+
+ mockRPC: function(route, args) {
+ if (args.method === 'get_formview_action') {
+ return $.when({
+ res_id: 1,
+ type: 'ir.actions.act_window',
+ target: 'current',
+ res_model: args.model,
+ context: args.kwargs.context,
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'views': [[false, 'form']],
+ });
+ }
+ return this._super(route, args);
+ },
+
+ interceptsPropagate: {
+ do_action: function (ev) {
+ actionManager.doAction(ev.data.action);
+ },
+ },
+ });
+ form.$('.o_field_widget[name="product_id"]').click();
+ form.destroy();
+ actionManager.destroy();
+ });
QUnit.test('invisible fields are properly hidden', function (assert) {
assert.expect(4);
diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js
index 73f2179dc8f..d651afc030c 100644
--- a/addons/web/static/tests/views/graph_tests.js
+++ b/addons/web/static/tests/views/graph_tests.js
@@ -785,13 +785,40 @@ QUnit.module('Views', {
'</graph>',
});
- assert.strictEqual(graph.$("svg.nvd3-svg:contains('Undefined')").length, 0);
- assert.strictEqual(graph.$("svg.nvd3-svg:contains('March')").length, 1);
+ assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0);
+ assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=bar]'));
- assert.strictEqual(graph.$("svg.nvd3-svg:contains('Undefined')").length, 1);
+ assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 1);
+ assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
+
+ graph.destroy();
+ });
+
+ QUnit.test('Undefined should appear in bar, pie graph but not in line graph with multiple groupbys', function (assert) {
+ assert.expect(6);
+
+ var graph = createView({
+ View: GraphView,
+ model: "foo",
+ groupBy:['date', 'color_id'],
+ data: this.data,
+ arch: '<graph string="Partners" type="line">' +
+ '<field name="bar"/>' +
+ '</graph>',
+ });
+
+ assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0);
assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
+ graph.$buttons.find('.o_graph_button[data-mode=bar]').click();
+ assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 1);
+ assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
+
+ // Undefined should not appear after switching back to line chart
+ graph.$buttons.find('.o_graph_button[data-mode=line]').click();
+ assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0);
+ assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
graph.destroy();
});
});
diff --git a/addons/web/static/tests/views/kanban_mobile_tests.js b/addons/web/static/tests/views/kanban_mobile_tests.js
index 98e65d1ea9c..a9eec223143 100644
--- a/addons/web/static/tests/views/kanban_mobile_tests.js
+++ b/addons/web/static/tests/views/kanban_mobile_tests.js
@@ -56,7 +56,7 @@ QUnit.module('Views', {
QUnit.module('KanbanView Mobile');
QUnit.test('mobile grouped rendering', function (assert) {
- assert.expect(9);
+ assert.expect(11);
var kanban = createView({
View: KanbanView,
@@ -75,6 +75,8 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_group', 2, "should have 2 columns" );
assert.hasClass(kanban.$('.o_kanban_mobile_tab:first'),'o_current',
"first tab is the active tab with class 'o_current'");
+ assert.hasClass(kanban.$('.o_kanban_group:first'),'o_current',
+ "first column is the active column with class 'o_current'");
assert.containsN(kanban, '.o_kanban_group:first > div.o_kanban_record', 2,
"there are 2 records in active tab");
assert.strictEqual(kanban.$('.o_kanban_group:nth(1) > div.o_kanban_record').length, 0,
@@ -89,6 +91,8 @@ QUnit.module('Views', {
kanban.$('.o_kanban_mobile_tab:nth(1)').trigger('click');
assert.hasClass(kanban.$('.o_kanban_mobile_tab:nth(1)'),'o_current',
"second tab is now active with class 'o_current'");
+ assert.hasClass(kanban.$('.o_kanban_group:nth(1)'),'o_current',
+ "second column is now active with class 'o_current'");
assert.strictEqual(kanban.$('.o_kanban_group:nth(1) > div.o_kanban_record').length, 2,
"the 2 records of the second group have now been loaded");
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index c398e9df09f..6702a9bee37 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -465,7 +465,7 @@ QUnit.module('Views', {
});
QUnit.test('quick create record with quick_create_view', function (assert) {
- assert.expect(17);
+ assert.expect(19);
var kanban = createView({
View: KanbanView,
@@ -497,6 +497,7 @@ QUnit.module('Views', {
},
});
+ assert.containsOnce(kanban, '.o_cp_controller', 'should have one control panel');
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"first column should contain one record");
@@ -508,6 +509,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.strictEqual($quickCreate.find('input').length, 2,
"should have two inputs");
assert.strictEqual($quickCreate.find('.o_field_widget').length, 3,
@@ -2376,9 +2378,60 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('wait x2manys batch fetches to re-render', function (assert) {
+ assert.expect(4);
+ var done = assert.async();
+
+ var def;
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test">' +
+ '<field name="product_id"/>' +
+ '<templates><t t-name="kanban-box">' +
+ '<div>' +
+ '<field name="category_ids" widget="many2many_tags"/>' +
+ '</div>' +
+ '</t></templates>' +
+ '</kanban>',
+ groupBy: ['product_id'],
+ mockRPC: function (route, args) {
+ var result = this._super(route, args);
+ if (args.method === 'read') {
+ return $.when(def).then(function() {
+ return result;
+ });
+ }
+ return result;
+ },
+ });
+
+ def = $.Deferred();
+ assert.containsN(kanban, '.o_tag', 2);
+ kanban.update({groupBy: ['state']});
+
+ def.resolve().then(function () {
+ assert.containsN(kanban, '.o_tag', 2,
+ 'Should display 2 tags after update');
+ assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_tag').text(),
+ 'gold', 'First category should be \'gold\'');
+ assert.strictEqual(kanban.$('.o_kanban_group:eq(2) .o_tag').text(),
+ 'silver', 'Second category should be \'silver\'');
+ kanban.destroy();
+ done();
+ });
+ });
+
QUnit.test('can drag and drop a record from one column to the next', function (assert) {
assert.expect(9);
+ // @todo: remove this resequenceDef whenever the jquery upgrade branch
+ // is merged. This is currently necessary to simulate the reality: we
+ // need the click handlers to be executed after the end of the drag and
+ // drop operation, not before.
+ var resequenceDef = $.Deferred();
+
var envIDs = [1, 3, 2, 4]; // the ids that should be in the environment during this test
this.data.partner.fields.sequence = {type: 'number', string: "Sequence"};
var kanban = createView({
@@ -2388,7 +2441,7 @@ QUnit.module('Views', {
arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
'<field name="product_id"/>' +
'<templates><t t-name="kanban-box">' +
- '<div><field name="foo"/>' +
+ '<div class="oe_kanban_global_click"><field name="foo"/>' +
'<t t-if="widget.editable"><span class="thisiseditable">edit</span></t>' +
'</div>' +
'</t></templates>' +
@@ -2397,7 +2450,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
assert.ok(true, "should call resequence");
- return $.when(true);
+ return resequenceDef.then(_.constant(true));
}
return this._super(route, args);
},
@@ -2410,13 +2463,15 @@ QUnit.module('Views', {
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
envIDs = [3, 2, 4, 1]; // first record of first column moved to the bottom of second column
- testUtils.dom.dragAndDrop($record, $group);
+ testUtils.dom.dragAndDrop($record, $group, {withTrailingClick: true});
+ resequenceDef.resolve();
assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 3);
assert.containsN(kanban, '.thisiseditable', 4);
assert.deepEqual(kanban.exportState().resIds, envIDs);
+ resequenceDef.resolve();
kanban.destroy();
});
diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js
index 46c28529bed..930fadbbb7b 100644
--- a/addons/web/static/tests/views/pivot_tests.js
+++ b/addons/web/static/tests/views/pivot_tests.js
@@ -149,6 +149,23 @@ QUnit.module('Views', {
pivot.destroy();
});
+ QUnit.test('pivot rendering with string attribute on non stored field', function (assert) {
+ assert.expect(1);
+
+ this.data.partner.fields.fubar = {string: "Fubar", type: "integer", store:false};
+
+ var pivot = createView({
+ View: PivotView,
+ model: "partner",
+ data: this.data,
+ arch: '<pivot string="Partners">' +
+ '<field name="fubar" string="fubar" type="measure"/>' +
+ '</pivot>',
+ });
+ assert.containsOnce(pivot, '.o_pivot', 'Non stored fields can have a string attribute');
+ pivot.destroy();
+ });
+
QUnit.test('pivot rendering with invisible attribute on field', function (assert) {
assert.expect(2);
// when invisible, a field should neither be an active measure,
@@ -1415,7 +1432,7 @@ QUnit.module('Views', {
actionManager.destroy();
});
- QUnit.test('export data in excel with comparison', function (assert) {
+ QUnit.test('export data in excel with comparison', function (assert) {
assert.expect(10);
this.data.partner.records[0].date = '2016-12-15';
@@ -1570,5 +1587,147 @@ QUnit.module('Views', {
unpatchDate();
actionManager.destroy();
});
+
+ QUnit.module('Sort in comparison mode', {
+ beforeEach: function () {
+ this.data.partner.records[0].date = '2016-12-15';
+ this.data.partner.records[1].date = '2016-12-17';
+ this.data.partner.records[2].date = '2016-11-22';
+ this.data.partner.records[3].date = '2016-11-03';
+
+ this.data.partner.fields.company_type = {string: "Company Type", type: "selection", selection: [["company", "Company"], ["individual", "individual"]], searchable: true, store: true, sortable: true};
+
+ this.data.partner.records[0].company_type = 'company';
+ this.data.partner.records[1].company_type = 'individual';
+ this.data.partner.records[2].company_type = 'company';
+ this.data.partner.records[3].company_type = 'individual';
+
+
+ this.unpatchDate = patchDate(2016, 11, 20, 1, 0, 0);
+
+ this.actualResult = function () {
+ var actualResult = $('.o_pivot .o_pivot_cell_value div').map(function() {
+ return $( this ).text();
+ }).get().join();
+ return actualResult;
+ };
+
+ // create an action manager to test the interactions with the search view
+ this.actionManager = createActionManager({
+ data: this.data,
+ archs: {
+ 'partner,false,pivot': '<pivot>' +
+ '<field name="date" interval="day" type="row"/>' +
+ '<field name="company_type" type="col"/>' +
+ '<field name="foo" type="measure"/>' +
+ '</pivot>',
+ 'partner,false,search': '<search></search>',
+ },
+ debug: 1,
+ });
+
+ this.actionManager.doAction({
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[false, 'pivot']],
+ flags: {
+ pivot: {
+ additionalMeasures: ['product_id'],
+ }
+ }
+ });
+
+ // open time range menu
+ testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
+ // select 'Today' as range
+ testUtils.fields.editInput($('.o_control_panel .o_time_range_selector'), 'this_month');
+ // check checkbox 'Compare To'
+ testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
+ // Click on 'Apply' button
+ testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
+ // We are in comparison mode
+ },
+ afterEach: function () {
+ this.unpatchDate();
+ this.actionManager.destroy();
+ },
+ }, function () {
+ QUnit.test('when clicking on measure, sort by "This Month" (period of interest)', function (assert) {
+ assert.expect(1);
+
+ // click on 'Foo' in column Total/Company
+ testUtils.dom.click($('.o_pivot_measure_row').eq(0));
+ var results = [
+ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
+ "12", "0", "100%", "12", "0" , "100%",
+ "1", "0", "100%", "1" , "0", "100%",
+ "0", "17", "-100%", "0", "17", "-100%",
+ "0", "2", "-100%", "0" , "2" , "-100%"
+ ];
+ assert.strictEqual(this.actualResult(), results.join());
+ });
+
+ QUnit.test(
+ 'click on a period of interest header sort according to the appropriate column ' +
+ 'first in ascending order then in descending order',
+ function (assert) {
+ assert.expect(2);
+
+ // click on 'This Month' in column Total/Individual/Foo
+ testUtils.dom.click($('.o_pivot_measure_row').eq(6));
+ var results = [
+ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
+ "1", "0", "100%", "1" , "0", "100%",
+ "12", "0", "100%", "12", "0" , "100%",
+ "0", "17", "-100%", "0", "17", "-100%",
+ "0", "2", "-100%", "0" , "2" , "-100%"
+ ];
+ var actualResult = $('.o_pivot .o_pivot_cell_value div').text();
+ assert.strictEqual(actualResult, results.join(''));
+
+ // click once again on 'This Month' in column Total/Individual/Foo
+ testUtils.dom.click($('.o_pivot_measure_row').eq(6));
+ results = [
+ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
+ "12", "0", "100%", "12", "0" , "100%",
+ "0", "17", "-100%", "0", "17", "-100%",
+ "0", "2", "-100%", "0" , "2" , "-100%",
+ "1", "0", "100%", "1" , "0", "100%"
+ ];
+ assert.strictEqual(this.actualResult(), results.join());
+ });
+
+ QUnit.test('click on a period of comparison header sort according to appropriate column',
+ function (assert) {
+ assert.expect(1);
+
+ // click on 'Previous Period' in column Total/Individual/Foo
+ testUtils.dom.click($('.o_pivot_measure_row').eq(7));
+ var results = [
+ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
+ "0", "2", "-100%", "0" , "2" , "-100%",
+ "12", "0", "100%", "12", "0" , "100%",
+ "1", "0", "100%", "1" , "0", "100%",
+ "0", "17", "-100%", "0", "17", "-100%"
+ ];
+ assert.strictEqual(this.actualResult(), results.join());
+ });
+
+ QUnit.test('click on a variation header sort according to appropriate column',
+ function (assert) {
+ assert.expect(1);
+
+ // click on 'Variation' in column Total/Individual/Foo
+ testUtils.dom.click($('.o_pivot_measure_row').eq(11));
+ var results = [
+ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
+ "12", "0", "100%", "12", "0" , "100%",
+ "1", "0", "100%", "1" , "0", "100%",
+ "0", "17", "-100%", "0", "17", "-100%",
+ "0", "2", "-100%", "0" , "2" , "-100%"
+ ];
+ assert.strictEqual(this.actualResult(), results.join());
+ });
+ });
});
});
diff --git a/addons/web/static/tests/views/search_filters_menu_tests.js b/addons/web/static/tests/views/search_filters_menu_tests.js
deleted file mode 100644
index e9246520f1d..00000000000
--- a/addons/web/static/tests/views/search_filters_menu_tests.js
+++ /dev/null
@@ -1,140 +0,0 @@
-odoo.define('web.search_filters_menu_tests', function (require) {
-"use strict";
-
-var FilterMenu = require('web.FilterMenu');
-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);
- menu.appendTo(target);
- 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', function (assert) {
- assert.expect(4);
-
- var filterMenu = createFilterMenu([], this.fields);
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- assert.containsOnce(filterMenu, '.dropdown-divider');
- assert.ok(!filterMenu.$('.dropdown-divider').is(':visible'));
- assert.containsN(filterMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 3,
- 'should have 3 elements: a hidden divider, a add custom filter item, a apply button + add condition button');
- assert.containsOnce(filterMenu, '.o_add_custom_filter.o_closed_menu');
- filterMenu.destroy();
- });
-
- QUnit.test('simple rendering with a filter', function (assert) {
- assert.expect(2);
-
- var filterMenu = createFilterMenu(this.filters, this.fields);
- assert.containsN(filterMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 5,
- 'should have 4 elements: a hidden, separator, a filter, a separator, a add custom filter item, a apply button + add condition button');
- assert.containsOnce(filterMenu, '.o_add_custom_filter.o_closed_menu');
- filterMenu.destroy();
- });
-
- QUnit.test('click on add custom filter opens the submenu', function (assert) {
- assert.expect(3);
-
- var filterMenu = createFilterMenu([], this.fields);
- // open menu dropdown
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- // open add custom filter submenu
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- assert.hasClass(filterMenu.$('.o_add_custom_filter'), 'o_open_menu');
- assert.ok(filterMenu.$('.o_add_filter_menu').is(':visible'));
- assert.containsN(filterMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4,
- 'should have 3 elements: a hidden divider, a add custom filter item, a proposition, a apply button + add condition button');
-
- filterMenu.destroy();
- });
-
- QUnit.test('removing last prop disable the apply button', function (assert) {
- assert.expect(2);
-
- var filterMenu = createFilterMenu([], this.fields);
- // open menu dropdown and custom filter submenu
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
-
- // remove the current unique proposition
- testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop'));
-
- assert.ok(filterMenu.$('.o_apply_filter').attr('disabled'));
-
- assert.containsN(filterMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 3,
- 'should have 3 elements: a hidden separator, a add custom filter item, a apply button + add condition button');
-
- filterMenu.destroy();
- });
-
- QUnit.test('readding a proposition reenable apply button', function (assert) {
- assert.expect(1);
-
- var filterMenu = createFilterMenu([], this.fields);
- // open menu dropdown and custom filter submenu, remove existing prop
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop'));
- // read a proposition
- testUtils.dom.click(filterMenu.$('.o_add_condition'));
- assert.ok(!filterMenu.$('.o_apply_filter').attr('disabled'));
-
- filterMenu.destroy();
- });
-
- QUnit.test('adding a simple filter works', function (assert) {
- assert.expect(6);
-
- delete this.fields.date_field;
- var filterMenu = createFilterMenu([], this.fields, {
- debug: true,
- 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
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- // click on apply to activate filter
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
- assert.hasClass(filterMenu.$('.o_add_custom_filter'), 'o_closed_menu');
- assert.containsNone(filterMenu, '.o_filter_condition');
- assert.containsOnce(filterMenu, '.dropdown-divider:visible',
- 'there should be a separator between filters and add custom filter menu');
- filterMenu.destroy();
- });
-});
-});
diff --git a/addons/web/static/tests/views/search_view_tests.js b/addons/web/static/tests/views/search_view_tests.js
index fa3fe817c2a..f4b0163ce07 100644
--- a/addons/web/static/tests/views/search_view_tests.js
+++ b/addons/web/static/tests/views/search_view_tests.js
@@ -2,6 +2,7 @@ odoo.define('web.search_view_tests', function (require) {
"use strict";
var FormView = require('web.FormView');
+var ListView = require('web.ListView');
var testUtils = require('web.test_utils');
var createActionManager = testUtils.createActionManager;
@@ -694,6 +695,39 @@ QUnit.module('Search View', {
window.Date = RealDate;
});
+ QUnit.test('`context` key in <filter> is used', function (assert) {
+ assert.expect(3);
+
+ this.archs['partner,4,search'] = '<search>'+
+ '<filter string="AAA" name="some_filter" context="{\'coucou_1\': 1}"></filter>' +
+ '</search>';
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (route === '/web/dataset/search_read') {
+ assert.step(JSON.stringify(args.context));
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ actionManager.doAction(5);
+
+ // select filter
+ testUtils.dom.click($('.o_search_options .fa-filter'));
+ testUtils.dom.click($('.o_menu_item:contains(AAA)'));
+
+ assert.verifySteps([
+ "{}",
+ "{\"coucou_1\":1}",
+ ]);
+
+ actionManager.destroy();
+ });
+
QUnit.module('Favorites Menu');
QUnit.test('dynamic filters are saved dynamic', function (assert) {