summaryrefslogtreecommitdiff
path: root/addons/web/static/tests
diff options
context:
space:
mode:
authorAaron Bohy <aab@odoo.com>2017-11-17 13:14:02 +0100
committerAaron Bohy <aab@odoo.com>2018-01-16 20:49:19 +0100
commit32b8cec5361174c92c45a4975d4e02f1fb448aa2 (patch)
tree110bd6986c2da1ed5047002b7ea40c91ea9fa5ed /addons/web/static/tests
parent9bee25a9df65f657fef0f2f32a7ad823fdc7d4e1 (diff)
[REF] web,*: ActionManager/ViewManager refactoring
This rev. is the first part (out of 3) of the refactoring of the ActionManager and ViewManager layer of the webclient. The main changes are: - there is no ViewManager anymore, its work is now handled by the ActionManager itself, but isolated in a specific file ; this eases a lot of things, as the breadcrumbs handling for example. - the ActionManager code is converted to the new coding principles and guidelines ; mainly, children widgets communicate with it by triggering events up, and not by function calls anymore. - the ActionManager layer is now testable, and a lot of tests have already been written. - the code in other addons has been adapted consequently. What's coming next: - introduce the 'AbstractAction' Widget, and make client actions and view controllers inherit from it ; this widget will implement a common API that could be used uniformly by the ActionManager (e.g. restore(), canBeLeft(), renderButtons(), getTitle()...). - move the ControlPanel handling from the ActionManager to the AbstractAction.
Diffstat (limited to 'addons/web/static/tests')
-rw-r--r--addons/web/static/tests/chrome/action_manager_mobile_tests.js85
-rw-r--r--addons/web/static/tests/chrome/action_manager_tests.js1667
-rw-r--r--addons/web/static/tests/helpers/mock_server.js21
-rw-r--r--addons/web/static/tests/helpers/test_utils.js89
-rw-r--r--addons/web/static/tests/views/form_tests.js41
-rw-r--r--addons/web/static/tests/views/kanban_tests.js14
-rw-r--r--addons/web/static/tests/views/list_tests.js31
-rw-r--r--addons/web/static/tests/views/view_dialogs_tests.js2
-rw-r--r--addons/web/static/tests/widgets/data_export_tests.js4
9 files changed, 1889 insertions, 65 deletions
diff --git a/addons/web/static/tests/chrome/action_manager_mobile_tests.js b/addons/web/static/tests/chrome/action_manager_mobile_tests.js
new file mode 100644
index 00000000000..c23d7be19f8
--- /dev/null
+++ b/addons/web/static/tests/chrome/action_manager_mobile_tests.js
@@ -0,0 +1,85 @@
+odoo.define('web.action_manager_mobile_tests', function (require) {
+"use strict";
+
+var testUtils = require('web.test_utils');
+
+var createActionManager = testUtils.createActionManager;
+
+QUnit.module('ActionManager', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ foo: {string: "Foo", type: "char"},
+ },
+ records: [
+ {id: 1, display_name: "First record", foo: "yop"},
+ ],
+ },
+ };
+
+ this.actions = [{
+ id: 1,
+ name: 'Partners Action 1',
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[false, 'list'], [false, 'kanban'], [false, 'form']],
+ }, {
+ id: 2,
+ name: 'Partners Action 2',
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[false, 'list'], [false, 'form']],
+ }];
+
+ this.archs = {
+ // kanban views
+ 'partner,false,kanban': '<kanban><templates><t t-name="kanban-box">' +
+ '<div class="oe_kanban_global_click"><field name="foo"/></div>' +
+ '</t></templates></kanban>',
+
+ // list views
+ 'partner,false,list': '<tree><field name="foo"/></tree>',
+
+ // form views
+ 'partner,false,form': '<form>' +
+ '<group>' +
+ '<field name="display_name"/>' +
+ '</group>' +
+ '</form>',
+
+ // search views
+ 'partner,false,search': '<search><field name="foo" string="Foo"/></search>',
+ };
+ },
+}, function () {
+ QUnit.test('uses a mobile-friendly view by default (if possible)', function (assert) {
+ assert.expect(4);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+
+ // should default on a mobile-friendly view (kanban) for action 1
+ actionManager.doAction(1);
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should not have rendered the list view");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have rendered the kanban view");
+
+ // there is no mobile-friendly view for action 2, should use the first one (list)
+ actionManager.doAction(2);
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should have rendered the list view");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "there should be no kanban view in the DOM");
+
+ actionManager.destroy();
+ });
+});
+
+});
diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js
new file mode 100644
index 00000000000..848d7eb1570
--- /dev/null
+++ b/addons/web/static/tests/chrome/action_manager_tests.js
@@ -0,0 +1,1667 @@
+odoo.define('web.action_manager_tests', function (require) {
+"use strict";
+
+var ControlPanelMixin = require('web.ControlPanelMixin');
+var core = require('web.core');
+var testUtils = require('web.test_utils');
+var Widget = require('web.Widget');
+
+var createActionManager = testUtils.createActionManager;
+
+QUnit.module('ActionManager', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ foo: {string: "Foo", type: "char"},
+ },
+ records: [
+ {id: 1, display_name: "First record", foo: "yop"},
+ {id: 2, display_name: "Second record", foo: "blip"},
+ {id: 3, display_name: "Third record", foo: "gnap"},
+ {id: 4, display_name: "Fourth record", foo: "plop"},
+ {id: 5, display_name: "Fifth record", foo: "zoup"},
+ ],
+ },
+ };
+
+ this.actions = [{
+ id: 1,
+ name: 'Partners Action 1',
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[1, 'kanban']],
+ }, {
+ id: 2,
+ type: 'ir.actions.server',
+ }, {
+ id: 3,
+ name: 'Partners',
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[false, 'list'], [1, 'kanban'], [false, 'form']],
+ }, {
+ id: 4,
+ name: 'Partners Action 4',
+ res_model: 'partner',
+ type: 'ir.actions.act_window',
+ views: [[1, 'kanban'], [2, 'list'], [false, 'form']],
+ }, {
+ id: 5,
+ name: 'Create a Partner',
+ res_model: 'partner',
+ target: 'new',
+ type: 'ir.actions.act_window',
+ view_mode: 'form',
+ views: [[false, 'form']],
+ }, {
+ id: 6,
+ name: 'Partner',
+ res_id: 2,
+ res_model: 'partner',
+ target: 'inline',
+ type: 'ir.actions.act_window',
+ view_mode: 'form',
+ views: [[false, 'form']],
+ }];
+ this.archs = {
+ // kanban views
+ 'partner,1,kanban': '<kanban><templates><t t-name="kanban-box">' +
+ '<div><field name="foo"/></div>' +
+ '</t></templates></kanban>',
+
+ // list views
+ 'partner,false,list': '<tree><field name="foo"/></tree>',
+ 'partner,2,list': '<tree limit="3"><field name="foo"/></tree>',
+
+ // form views
+ 'partner,false,form': '<form>' +
+ '<header>' +
+ '<button name="object" string="Call method" type="object"/>' +
+ '<button name="4" string="Execute action" type="action"/>' +
+ '</header>' +
+ '<group>' +
+ '<field name="display_name"/>' +
+ '<field name="foo"/>' +
+ '</group>' +
+ '</form>',
+
+ // search views
+ 'partner,false,search': '<search><field name="foo" string="Foo"/></search>',
+ };
+ },
+}, function () {
+ QUnit.module('Misc');
+
+ QUnit.test('no widget memory leaks when executing actions in dialog', function (assert) {
+ assert.expect(1);
+
+ var delta = 0;
+ testUtils.patch(Widget, {
+ init: function () {
+ delta++;
+ this._super.apply(this, arguments);
+ },
+ destroy: function () {
+ if (!this.isDestroyed()) {
+ delta--;
+ }
+ this._super.apply(this, arguments);
+ },
+ });
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ var n = delta;
+
+ actionManager.doAction(5);
+ actionManager.doAction({type: 'ir.actions.act_window_close'});
+
+ assert.strictEqual(delta, n,
+ "should have properly destroyed all widgets");
+
+ actionManager.destroy();
+ testUtils.unpatch(Widget);
+ });
+
+ QUnit.test('no memory leaks when executing an action while switching view', function (assert) {
+ assert.expect(1);
+
+ var def;
+ var delta = 0;
+ testUtils.patch(Widget, {
+ init: function () {
+ delta += 1;
+ this._super.apply(this, arguments);
+ },
+ destroy: function () {
+ delta -= 1;
+ this._super.apply(this, arguments);
+ },
+ });
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ var result = this._super.apply(this, arguments);
+ if (args.method === 'read') {
+ return $.when(def).then(_.constant(result));
+ }
+ return result;
+ },
+ });
+
+ actionManager.doAction(4);
+ var n = delta;
+
+ actionManager.doAction(3, {clear_breadcrumbs: true});
+
+ // switch to the form view (this request is blocked)
+ def = $.Deferred();
+ actionManager.$('.o_list_view .o_data_row:first').click();
+
+ // execute another action meanwhile (don't block this request)
+ actionManager.doAction(4, {clear_breadcrumbs: true});
+
+ // unblock the switch to the form view in action 3
+ def.resolve();
+
+ assert.strictEqual(n, delta,
+ "all widgets of action 3 should have been destroyed");
+
+ actionManager.destroy();
+ testUtils.unpatch(Widget);
+ });
+
+ QUnit.test('action with "no_breadcrumbs" set to true', function (assert) {
+ assert.expect(2);
+
+ _.findWhere(this.actions, {id: 4}).context = {no_breadcrumbs: true};
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(3);
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+
+ // push another action flagged with 'no_breadcrumbs=true'
+ actionManager.doAction(4);
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 0,
+ "the breadcrumbs should be empty");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('on_reverse_breadcrumb handler is correctly called', function (assert) {
+ assert.expect(3);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+
+ // execute action 3 and open a record in form view
+ actionManager.doAction(3);
+ actionManager.$('.o_list_view .o_data_row:first').click();
+
+ // execute action 4 without 'on_reverse_breadcrumb' handler, then go back
+ actionManager.doAction(4);
+ $('.o_control_panel .breadcrumb a:first').click();
+ assert.verifySteps([]);
+
+ // execute action 4 with an 'on_reverse_breadcrumb' handler, then go back
+ actionManager.doAction(4, {
+ on_reverse_breadcrumb: function () {
+ assert.step('on_reverse_breadcrumb');
+ }
+ });
+ $('.o_control_panel .breadcrumb a:first').click();
+ assert.verifySteps(['on_reverse_breadcrumb']);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('handles "history_back" event', function (assert) {
+ assert.expect(2);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+
+ actionManager.doAction(4);
+ actionManager.doAction(3);
+ actionManager.trigger_up('history_back');
+
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners Action 4',
+ "breadcrumbs should display the display_name of the action");
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Load State');
+
+ QUnit.test('should not crash on invalid state', function (assert) {
+ assert.expect(2);
+
+ 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({
+ res_model: 'partner', // the valid key for the model is 'model', not 'res_model'
+ });
+
+ assert.strictEqual(actionManager.$el.text(), '', "should display nothing");
+ assert.verifySteps([]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('properly load client actions', function (assert) {
+ assert.expect(2);
+
+ var ClientAction = Widget.extend({
+ className: 'o_client_action_test',
+ start: function () {
+ this.$el.text('Hello World');
+ },
+ });
+ core.action_registry.add('HelloWorldTest', ClientAction);
+
+ 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: 'HelloWorldTest',
+ });
+
+ assert.strictEqual(actionManager.$('.o_client_action_test').text(),
+ 'Hello World', "should have correctly rendered the client action");
+
+ assert.verifySteps([]);
+
+ actionManager.destroy();
+ delete core.action_registry.map.HelloWorldTest;
+ });
+
+ QUnit.test('properly load act window actions', function (assert) {
+ assert.expect(6);
+
+ 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: 1,
+ });
+
+ assert.strictEqual($('.o_control_panel').length, 1,
+ "should have rendered a control panel");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have rendered a kanban view");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('properly load records', 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({
+ id: 2,
+ model: 'partner',
+ });
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should have rendered a form view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Second record',
+ "should have opened the second record");
+
+ assert.verifySteps([
+ 'load_views',
+ 'read',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('load requested view for act window actions', function (assert) {
+ assert.expect(6);
+
+ 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,
+ view_type: 'kanban',
+ });
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should not have rendered a list view");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have rendered a kanban view");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('lazy load multi record view if mono record one is requested', function (assert) {
+ assert.expect(11);
+
+ 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: 2,
+ view_type: 'form',
+ });
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should not have rendered a list view");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should have rendered a form view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Second record',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ // go back to Lst
+ $('.o_control_panel .breadcrumb a').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should now display the list view");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "should not display the form view anymore");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ 'read', // read the opened record
+ '/web/dataset/search_read', // search read when coming back to List
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('change the viewType of the current action', function (assert) {
+ assert.expect(13);
+
+ 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.doAction(3);
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should have rendered a list view");
+
+ // switch to kanban view
+ actionManager.loadState({
+ action: 3,
+ view_type: 'kanban',
+ });
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should not display the list view anymore");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have switched to the kanban view");
+
+ // switch to form view, open record 4
+ actionManager.loadState({
+ action: 3,
+ id: 4,
+ view_type: 'form',
+ });
+
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "should not display the kanban view anymore");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should have switched to the form view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Fourth record',
+ "should have opened the requested record");
+
+ // verify steps to ensure that the whole action hasn't been re-executed
+ // (if it would have been, /web/action/load and load_views would appear
+ // several times)
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list view
+ '/web/dataset/search_read', // kanban view
+ 'read', // form view
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('change the id of the current action', function (assert) {
+ assert.expect(11);
+
+ 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);
+ },
+ });
+
+ // execute action 3 and open the first record in a form view
+ actionManager.doAction(3);
+ actionManager.$('.o_list_view .o_data_row:first').click();
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should have rendered a form view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'First record',
+ "should have opened the first record");
+
+ // switch to record 4
+ actionManager.loadState({
+ action: 3,
+ id: 4,
+ view_type: 'form',
+ });
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should still display the form view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Fourth record',
+ "should have switched to the requested record");
+
+ // verify steps to ensure that the whole action hasn't been re-executed
+ // (if it would have been, /web/action/load and load_views would appear
+ // twice)
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list view
+ 'read', // form view, record 1
+ 'read', // form view, record 4
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('should not push a loaded state', function (assert) {
+ assert.expect(1);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ intercepts: {
+ push_state: function () {
+ assert.step('push_state');
+ },
+ },
+ });
+ actionManager.loadState({action: 1});
+
+ assert.verifySteps([]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Concurrency management');
+
+ QUnit.test('execute a new action while loading a lazy-loaded controller', function (assert) {
+ assert.expect(15);
+
+ var def;
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ var result = this._super.apply(this, arguments);
+ assert.step(args.method || route);
+ if (route === '/web/dataset/search_read' && args.model === 'partner') {
+ return $.when(def).then(_.constant(result));
+ }
+ return result;
+ },
+ });
+ actionManager.loadState({
+ action: 4,
+ id: 2,
+ view_type: 'form',
+ });
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should display the form view of action 4");
+
+ // click to go back to Kanban (this request is blocked)
+ def = $.Deferred();
+ $('.o_control_panel .breadcrumb a').click();
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should still display the form view of action 4");
+
+ // execute another action meanwhile (don't block this request)
+ actionManager.doAction(8, {clear_breadcrumbs: true});
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display action 8");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "should no longer display the form view");
+
+ assert.verifySteps([
+ '/web/action/load', // load state action 4
+ 'load_views', // load state action 4
+ 'read', // read the opened record (action 4)
+ '/web/dataset/search_read', // blocked search read when coming back to Kanban (action 4)
+ '/web/action/load', // action 8
+ 'load_views', // action 8
+ '/web/dataset/search_read', // search read action 8
+ ]);
+
+ // unblock the switch to Kanban in action 4
+ def.resolve();
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should still display action 8");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "should not display the kanban view of action 4");
+
+ assert.verifySteps([
+ '/web/action/load', // load state action 4
+ 'load_views', // load state action 4
+ 'read', // read the opened record (action 4)
+ '/web/dataset/search_read', // blocked search read when coming back to Kanban (action 4)
+ '/web/action/load', // action 8
+ 'load_views', // action 8
+ '/web/dataset/search_read', // search read action 8
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('execute a new action while handling a call_button', function (assert) {
+ assert.expect(16);
+
+ var self = this;
+ var def = $.Deferred();
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method || route);
+ if (route === '/web/dataset/call_button') {
+ return def.then(_.constant(self.actions[0]));
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ // execute action 3 and open a record in form view
+ actionManager.doAction(3);
+ actionManager.$('.o_list_view .o_data_row:first').click();
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should display the form view of action 3");
+
+ // click on 'Call method' button (this request is blocked)
+ actionManager.$('.o_form_view button:contains(Call method)').click();
+
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should still display the form view of action 3");
+
+ // execute another action
+ actionManager.doAction(8, {clear_breadcrumbs: true});
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display the list view of action 8");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "should no longer display the form view");
+
+ assert.verifySteps([
+ '/web/action/load', // action 3
+ 'load_views', // action 3
+ '/web/dataset/search_read', // list for action 3
+ 'read', // form for action 3
+ 'object', // click on 'Call method' button (this request is blocked)
+ '/web/action/load', // action 8
+ 'load_views', // action 8
+ '/web/dataset/search_read', // list for action 8
+ ]);
+
+ // unblock the call_button request
+ def.resolve();
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should still display the list view of action 8");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "should not display action 1");
+
+ assert.verifySteps([
+ '/web/action/load', // action 3
+ 'load_views', // action 3
+ '/web/dataset/search_read', // list for action 3
+ 'read', // form for action 3
+ 'object', // click on 'Call method' button (this request is blocked)
+ '/web/action/load', // action 8
+ 'load_views', // action 8
+ '/web/dataset/search_read', // list for action 8
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('execute a new action while switching to another controller', function (assert) {
+ assert.expect(15);
+
+ var def;
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ var result = this._super.apply(this, arguments);
+ assert.step(args.method || route);
+ if (args.method === 'read') {
+ return $.when(def).then(_.constant(result));
+ }
+ return result;
+ },
+ });
+
+ actionManager.doAction(3);
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display the list view of action 3");
+
+ // switch to the form view (this request is blocked)
+ def = $.Deferred();
+ actionManager.$('.o_list_view .o_data_row:first').click();
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should still display the list view of action 3");
+
+ // execute another action meanwhile (don't block this request)
+ actionManager.doAction(4, {clear_breadcrumbs: true});
+
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should display the kanban view of action 8");
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should no longer display the list view");
+
+ assert.verifySteps([
+ '/web/action/load', // action 3
+ 'load_views', // action 3
+ '/web/dataset/search_read', // search read of list view of action 3
+ 'read', // read the opened record of action 3 (this request is blocked)
+ '/web/action/load', // action 4
+ 'load_views', // action 4
+ '/web/dataset/search_read', // search read action 4
+ ]);
+
+ // unblock the switch to the form view in action 3
+ def.resolve();
+
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should still display the kanban view of action 8");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "should not display the form view of action 3");
+
+ assert.verifySteps([
+ '/web/action/load', // action 3
+ 'load_views', // action 3
+ '/web/dataset/search_read', // search read of list view of action 3
+ 'read', // read the opened record of action 3 (this request is blocked)
+ '/web/action/load', // action 4
+ 'load_views', // action 4
+ '/web/dataset/search_read', // search read action 4
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Client Actions');
+
+ QUnit.test('can execute client actions from tag name', function (assert) {
+ assert.expect(3);
+
+ var ClientAction = Widget.extend({
+ className: 'o_client_action_test',
+ start: function () {
+ this.$el.text('Hello World');
+ },
+ });
+ core.action_registry.add('HelloWorldTest', ClientAction);
+
+ var actionManager = createActionManager({
+ mockRPC: function (route, args) {
+ assert.step(args.method || route);
+ return this._super.apply(this, arguments);
+ }
+ });
+ actionManager.doAction('HelloWorldTest');
+
+ assert.strictEqual($('.o_control_panel:visible').length, 0, // AAB: global selector until the ControlPanel is moved from ActionManager to the Views
+ "shouldn't have rendered a control panel");
+ assert.strictEqual(actionManager.$('.o_client_action_test').text(),
+ 'Hello World', "should have correctly rendered the client action");
+ assert.verifySteps([]);
+
+ actionManager.destroy();
+ delete core.action_registry.map.HelloWorldTest;
+ });
+
+ QUnit.test('client action with control panel', function (assert) {
+ assert.expect(4);
+
+ var ClientAction = Widget.extend(ControlPanelMixin, {
+ className: 'o_client_action_test',
+ start: function () {
+ this.$el.text('Hello World');
+ this.set('title', 'Hello'); // AAB: drop this and replace by getTitle()
+ },
+ });
+ core.action_registry.add('HelloWorldTest', ClientAction);
+
+ var actionManager = createActionManager();
+ actionManager.doAction('HelloWorldTest');
+
+ assert.strictEqual($('.o_control_panel:visible').length, 1,
+ "should have rendered a control panel");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Hello',
+ "breadcrumbs should still display the title of the controller");
+ assert.strictEqual(actionManager.$('.o_client_action_test').text(),
+ 'Hello World', "should have correctly rendered the client action");
+
+ actionManager.destroy();
+ delete core.action_registry.map.HelloWorldTest;
+ });
+
+ QUnit.test('state is pushed for client actions', function (assert) {
+ assert.expect(2);
+
+ var ClientAction = Widget.extend(ControlPanelMixin, {
+ className: 'o_client_action_test',
+ start: function () {
+ this.$el.text('Hello World');
+ },
+ });
+ var actionManager = createActionManager({
+ intercepts: {
+ push_state: function () {
+ assert.step('push state');
+ },
+ },
+ });
+ core.action_registry.add('HelloWorldTest', ClientAction);
+
+ actionManager.doAction('HelloWorldTest');
+
+ assert.verifySteps(['push state']);
+
+ actionManager.destroy();
+ delete core.action_registry.map.HelloWorldTest;
+ });
+
+ QUnit.module('Server actions');
+
+ QUnit.test('can execute server actions from db ID', function (assert) {
+ assert.expect(9);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method || route);
+ if (route === '/web/action/run') {
+ assert.strictEqual(args.action_id, 2,
+ "should call the correct server action");
+ return $.when(1); // execute action 1
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+ actionManager.doAction(2);
+
+ assert.strictEqual($('.o_control_panel:visible').length, 1,
+ "should have rendered a control panel");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have rendered a kanban view");
+ assert.verifySteps([
+ '/web/action/load',
+ '/web/action/run',
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Window Actions');
+
+ QUnit.test('can execute act_window actions from db ID', function (assert) {
+ assert.expect(6);
+
+ 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.doAction(1);
+
+ assert.strictEqual($('.o_control_panel').length, 1,
+ "should have rendered a control panel");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have rendered a kanban view");
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('can switch between views', function (assert) {
+ assert.expect(18);
+
+ 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.doAction(3);
+
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display the list view");
+
+ // switch to kanban view
+ $('.o_control_panel .o_cp_switch_kanban').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should no longer display the list view");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should display the kanban view");
+
+ // switch back to list view
+ $('.o_control_panel .o_cp_switch_list').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display the list view");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "should no longer display the kanban view");
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should no longer display the list view");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should display the form view");
+ assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop',
+ "should have opened the correct record");
+
+ // go back to list view using the breadcrumbs
+ $('.o_control_panel .breadcrumb a').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display the list view");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "should no longer display the form view");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list
+ '/web/dataset/search_read', // kanban
+ '/web/dataset/search_read', // list
+ 'read', // form
+ '/web/dataset/search_read', // list
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('breadcrumbs are updated when switching between views', function (assert) {
+ assert.expect(10);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(3);
+
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners',
+ "breadcrumbs should display the display_name of the action");
+
+ // switch to kanban view
+ $('.o_control_panel .o_cp_switch_kanban').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should still be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners',
+ "breadcrumbs should still display the display_name of the action");
+
+ // switch back to list view
+ $('.o_control_panel .o_cp_switch_list').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should still be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners',
+ "breadcrumbs should still display the display_name of the action");
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'First record',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ // go back to list view using the breadcrumbs
+ $('.o_control_panel .breadcrumb a').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners',
+ "breadcrumbs should display the display_name of the action");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('switch buttons are updated when switching between views', function (assert) {
+ assert.expect(13);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(3);
+
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
+ "should have two switch buttons (list and kanban)");
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1,
+ "should have only one active button");
+ assert.ok($('.o_control_panel .o_cp_switch_buttons button:first').hasClass('o_cp_switch_list'),
+ "list switch button should be the first one");
+ assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'),
+ "list should be the active view");
+
+ // switch to kanban view
+ $('.o_control_panel .o_cp_switch_kanban').click();
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
+ "should still have two switch buttons (list and kanban)");
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1,
+ "should still have only one active button");
+ assert.ok($('.o_control_panel .o_cp_switch_buttons button:first').hasClass('o_cp_switch_list'),
+ "list switch button should still be the first one");
+ assert.ok($('.o_control_panel .o_cp_switch_kanban').hasClass('active'),
+ "kanban should now be the active view");
+
+ // switch back to list view
+ $('.o_control_panel .o_cp_switch_list').click();
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
+ "should still have two switch buttons (list and kanban)");
+ assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'),
+ "list should now be the active view");
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 0,
+ "should not have any switch buttons");
+
+ // go back to list view using the breadcrumbs
+ $('.o_control_panel .breadcrumb a').click();
+ assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
+ "should have two switch buttons (list and kanban)");
+ assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'),
+ "list should be the active view");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('pager is updated when switching between views', function (assert) {
+ assert.expect(10);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(4);
+
+ 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',
+ "limit should be correct for kanban");
+
+ // switch to list view
+ $('.o_control_panel .o_cp_switch_list').click();
+ assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-3',
+ "value should be correct for list");
+ assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5',
+ "limit should be correct for list");
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1',
+ "value should be correct for form");
+ assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '3',
+ "limit should be correct for form");
+
+ // go back to list view using the breadcrumbs
+ $('.o_control_panel .breadcrumb a').click();
+ assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-3',
+ "value should be correct for list");
+ assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5',
+ "limit should be correct for list");
+
+ // switch back to kanban view
+ $('.o_control_panel .o_cp_switch_kanban').click();
+ 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',
+ "limit should be correct for kanban");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('there is no flickering when switching between views', function (assert) {
+ assert.expect(20);
+
+ var def;
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function () {
+ var result = this._super.apply(this, arguments);
+ return $.when(def).then(_.constant(result));
+ },
+ });
+ actionManager.doAction(3);
+
+ // switch to kanban view
+ def = $.Deferred();
+ $('.o_control_panel .o_cp_switch_kanban').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should still display the list view");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "shouldn't display the kanban view yet");
+ def.resolve();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "shouldn't display the list view anymore");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should now display the kanban view");
+
+ // switch back to list view
+ def = $.Deferred();
+ $('.o_control_panel .o_cp_switch_list').click();
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should still display the kanban view");
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "shouldn't display the list view yet");
+ def.resolve();
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
+ "shouldn't display the kanban view anymore");
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should now display the list view");
+
+ // open a record in form view
+ def = $.Deferred();
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should still display the list view");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "shouldn't display the form view yet");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should still be one controller in the breadcrumbs");
+ def.resolve();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "should no longer display the list view");
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should display the form view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+
+ // go back to list view using the breadcrumbs
+ def = $.Deferred();
+ $('.o_control_panel .breadcrumb a').click();
+ assert.strictEqual(actionManager.$('.o_form_view').length, 1,
+ "should still display the form view");
+ assert.strictEqual(actionManager.$('.o_list_view').length, 0,
+ "shouldn't display the list view yet");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should still be two controllers in the breadcrumbs");
+ def.resolve();
+ assert.strictEqual(actionManager.$('.o_form_view').length, 0,
+ "should no longer display the form view");
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should display the list view");
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('breadcrumbs are updated when display_name changes', function (assert) {
+ assert.expect(4);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(3);
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'First record',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ // switch to edit mode and change the display_name
+ $('.o_control_panel .o_form_button_edit').click();
+ actionManager.$('.o_field_widget[name=display_name]').val('New name').trigger('input');
+ $('.o_control_panel .o_form_button_save').click();
+
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should still be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'New name',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('reload previous controller when discarding a new record', function (assert) {
+ assert.expect(8);
+
+ 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.doAction(3);
+
+ // create a new record
+ $('.o_control_panel .o_list_button_add').click();
+ assert.strictEqual(actionManager.$('.o_form_view.o_form_editable').length, 1,
+ "should have opened the form view in edit mode");
+
+ // discard
+ $('.o_control_panel .o_form_button_cancel').click();
+ assert.strictEqual(actionManager.$('.o_list_view').length, 1,
+ "should have switched back to the list view");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list
+ 'default_get', // form
+ '/web/dataset/search_read', // list
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('requests for execute_action of type object are handled', function (assert) {
+ assert.expect(10);
+
+ var self = this;
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method || route);
+ if (route === '/web/dataset/call_button') {
+ assert.deepEqual(args, {
+ args: [[1], {some_key: 2}],
+ method: 'object',
+ model: 'partner',
+ }, "should call route with correct arguments");
+ var record = _.findWhere(self.data.partner.records, {id: args.args[0][0]});
+ record.foo = 'value changed';
+ return $.when(false);
+ }
+ return this._super.apply(this, arguments);
+ },
+ session: {user_context: {
+ some_key: 2,
+ }},
+ });
+ actionManager.doAction(3);
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop',
+ "check initial value of 'yop' field");
+
+ // click on 'Call method' button (should call an Object method)
+ actionManager.$('.o_form_view button:contains(Call method)').click();
+ assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'value changed',
+ "'yop' has been changed by the server, and should be updated in the UI");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list for action 3
+ 'read', // form for action 3
+ 'object', // click on 'Call method' button
+ 'read', // re-read form view
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('requests for execute_action of type action are handled', function (assert) {
+ assert.expect(11);
+
+ 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.doAction(3);
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+
+ // click on 'Execute action' button (should execute an action)
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two parts in the breadcrumbs");
+ actionManager.$('.o_form_view button:contains(Execute action)').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 3,
+ "the returned action should have been stacked over the previous one");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "the returned action should have been executed");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list for action 3
+ 'read', // form for action 3
+ '/web/action/load', // click on 'Execute action' button
+ 'load_views',
+ '/web/dataset/search_read', // kanban for action 4
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('can open different records from a multi record view', function (assert) {
+ assert.expect(11);
+
+ 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.doAction(3);
+
+ // open the first record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'First record',
+ "breadcrumbs should contain the display_name of the opened record");
+ assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop',
+ "should have opened the correct record");
+
+ // go back to list view using the breadcrumbs
+ $('.o_control_panel .breadcrumb a').click();
+
+ // open the second record in form view
+ actionManager.$('.o_list_view .o_data_row:nth(1)').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Second record',
+ "breadcrumbs should contain the display_name of the opened record");
+ assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'blip',
+ "should have opened the correct record");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read', // list
+ 'read', // form
+ '/web/dataset/search_read', // list
+ 'read', // form
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('limit set in action is passed to each created controller', function (assert) {
+ assert.expect(2);
+
+ _.findWhere(this.actions, {id: 3}).limit = 2;
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(3);
+
+ assert.strictEqual(actionManager.$('.o_data_row').length, 2,
+ "should only display 2 record");
+
+ // switch to kanban view
+ $('.o_control_panel .o_cp_switch_kanban').click();
+
+ assert.strictEqual(actionManager.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2,
+ "should only display 2 record");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('go back to a previous action using the breadcrumbs', function (assert) {
+ assert.expect(10);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(3);
+
+ // open a record in form view
+ actionManager.$('.o_list_view .o_data_row:first').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'First record',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ // push another action on top of the first one, and come back to the form view
+ actionManager.doAction(4);
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 3,
+ "there should be three controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Partners Action 4',
+ "breadcrumbs should contain the name of the current action");
+ // go back using the breadcrumbs
+ $('.o_control_panel .breadcrumb a:nth(1)').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'First record',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ // push again the other action on top of the first one, and come back to the list view
+ actionManager.doAction(4);
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 3,
+ "there should be three controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Partners Action 4',
+ "breadcrumbs should contain the name of the current action");
+ // go back using the breadcrumbs
+ $('.o_control_panel .breadcrumb a:first').click();
+ assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
+ "there should be one controller in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb li:last').text(), 'Partners',
+ "breadcrumbs should contain the name of the current action");
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Actions in target="new"');
+
+ QUnit.test('can execute act_window actions in target="new"', function (assert) {
+ assert.expect(7);
+
+ 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.doAction(5);
+
+ assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
+ "should have rendered a form view in a modal");
+ assert.ok($('.o_technical_modal .modal-body').hasClass('o_act_window'),
+ "modal-body element should have classname 'o_act_window'");
+ assert.ok($('.o_technical_modal .o_form_view').hasClass('o_form_editable'),
+ "form view should be in edit mode");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ 'default_get',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('footer buttons are moved to the dialog footer', function (assert) {
+ assert.expect(3);
+
+ this.archs['partner,false,form'] = '<form>' +
+ '<field name="display_name"/>' +
+ '<footer>' +
+ '<button string="Create" type="object" class="infooter"/>' +
+ '</footer>' +
+ '</form>';
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ actionManager.doAction(5);
+
+ assert.strictEqual($('.o_technical_modal .modal-body button.infooter').length, 0,
+ "the button should not be in the body");
+ assert.strictEqual($('.o_technical_modal .modal-footer button.infooter').length, 1,
+ "the button should be in the footer");
+ assert.strictEqual($('.o_technical_modal .modal-footer button').length, 1,
+ "the modal footer should only contain one button");
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Actions in target="inline"');
+
+ QUnit.test('form views for actions in target="inline" open in edit mode', 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.doAction(6);
+
+ assert.strictEqual(actionManager.$('.o_form_view.o_form_editable').length, 1,
+ "should have rendered a form view in edit mode");
+
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ 'read',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('Actions in target="fullscreen"');
+
+ QUnit.test('correctly execute act_window actions in target="fullscreen"', function (assert) {
+ assert.expect(7);
+
+ this.actions[0].target = 'fullscreen';
+ 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);
+ },
+ intercepts: {
+ toggle_fullscreen: function () {
+ assert.step('toggle_fullscreen');
+ },
+ },
+ });
+ actionManager.doAction(1);
+
+ assert.strictEqual($('.o_control_panel').length, 1,
+ "should have rendered a control panel");
+ assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
+ "should have rendered a kanban view");
+ assert.verifySteps([
+ '/web/action/load',
+ 'load_views',
+ '/web/dataset/search_read',
+ 'toggle_fullscreen',
+ ]);
+
+ actionManager.destroy();
+ });
+
+ QUnit.module('"ir.actions.act_window_close" actions');
+
+ QUnit.test('close the currently opened dialog', function (assert) {
+ assert.expect(2);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+
+ // execute an action in target="new"
+ actionManager.doAction(5);
+ assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
+ "should have rendered a form view in a modal");
+
+ // execute an 'ir.actions.act_window_close' action
+ actionManager.doAction({
+ type: 'ir.actions.act_window_close',
+ });
+ assert.strictEqual($('.o_technical_modal').length, 0,
+ "should have closed the modal");
+
+ actionManager.destroy();
+ });
+
+ QUnit.test('execute "on_close" only if there is no dialog to close', function (assert) {
+ assert.expect(3);
+
+ var actionManager = createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+
+ // execute an action in target="new"
+ actionManager.doAction(5);
+
+ var options = {
+ on_close: assert.step.bind(assert, 'on_close'),
+ };
+ // execute an 'ir.actions.act_window_close' action
+ // should not call 'on_close' as there is a dialog to close
+ actionManager.doAction({type: 'ir.actions.act_window_close'}, options);
+
+ assert.verifySteps([]);
+
+ // execute again an 'ir.actions.act_window_close' action
+ // should call 'on_close' as there is no dialog to close
+ actionManager.doAction({type: 'ir.actions.act_window_close'}, options);
+
+ assert.verifySteps(['on_close']);
+
+ actionManager.destroy();
+ });
+});
+
+});
diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js
index 4bc58dd097d..dbe1a2c49e0 100644
--- a/addons/web/static/tests/helpers/mock_server.js
+++ b/addons/web/static/tests/helpers/mock_server.js
@@ -12,6 +12,7 @@ var MockServer = Class.extend({
* @constructor
* @param {Object} data
* @param {Object} options
+ * @param {Object[]} [options.actions=[]]
* @param {Object} [options.archs={}] dict of archs with keys being strings like
* 'model,id,viewType'
* @param {boolean} [options.debug=false] logs RPCs if set to true
@@ -47,6 +48,7 @@ var MockServer = Class.extend({
this.currentDate = options.currentDate || moment().format("YYYY-MM-DD");
+ this.actions = options.actions || [];
this.archs = options.archs || {};
},
@@ -432,6 +434,23 @@ var MockServer = Class.extend({
return modelFields;
},
/**
+ * Simulate a call to the '/web/action/load' route
+ *
+ * @private
+ * @param {Object} kwargs
+ * @param {integer} kwargs.action_id
+ * @returns {Object}
+ */
+ _mockLoadAction: function (kwargs) {
+ var action = _.findWhere(this.actions, {id: parseInt(kwargs.action_id)});
+ if (!action) {
+ // when the action doesn't exist, the real server doesn't crash, it
+ // simply returns false
+ console.warn("No action found for ID " + event.data.actionID);
+ }
+ return action || false;
+ },
+ /**
* Simulate a 'load_views' operation
*
* @param {string} model
@@ -943,7 +962,7 @@ var MockServer = Class.extend({
_performRpc: function (route, args) {
switch (route) {
case '/web/action/load':
- return $.when(this._mockLoadAction(args));
+ return $.when(this._mockLoadAction(args.kwargs));
case '/web/dataset/search_read':
return $.when(this._mockSearchReadController(args));
diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js
index e049ba968b2..afeb579eb02 100644
--- a/addons/web/static/tests/helpers/test_utils.js
+++ b/addons/web/static/tests/helpers/test_utils.js
@@ -10,9 +10,11 @@ odoo.define('web.test_utils', function (require) {
* instance of a view, appended in the dom, ready to be tested.
*/
+var ActionManager = require('web.ActionManager');
var ajax = require('web.ajax');
var basic_fields = require('web.basic_fields');
var config = require('web.config');
+var ControlPanel = require('web.ControlPanel');
var core = require('web.core');
var dom = require('web.dom');
var session = require('web.session');
@@ -59,6 +61,58 @@ function observe(widget) {
}
/**
+ * create and return an instance of ActionManager with all rpcs going through a
+ * mock method using the data, actions and archs objects as sources.
+ *
+ * @param {Object} [params]
+ * @param {Object} [params.actions] the actions given to the mock server
+ * @param {Object} [params.archs] this archs given to the mock server
+ * @param {Object} [params.data] the business data given to the mock server
+ * @param {boolean} [params.debug]
+ * @param {function} [params.mockRPC]
+ * @returns {ActionManager}
+ */
+var createActionManager = function (params) {
+ params = params || {};
+ var $target = $('#qunit-fixture');
+ if (params.debug) {
+ $target = $('body');
+ }
+
+ var widget = new Widget();
+ // when 'document' addon is installed, the sidebar does a 'search_read' on
+ // model 'ir_attachment' each time a record is open, so we monkey-patch
+ // 'mockRPC' to mute those RPCs, so that the tests can be written uniformly,
+ // whether or not 'document' is installed
+ var mockRPC = params.mockRPC;
+ _.extend(params, {
+ mockRPC: function (route, args) {
+ if (args.model === 'ir.attachment') {
+ return $.when([]);
+ }
+ if (mockRPC) {
+ return mockRPC.apply(this, arguments);
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+ addMockEnvironment(widget, _.defaults(params, {debounce: false}));
+ widget.appendTo($target);
+ widget.$el.addClass('o_web_client');
+
+ var userContext = params.context && params.context.user_context || {};
+ var actionManager = new ActionManager(widget, userContext);
+ var originalDestroy = ActionManager.prototype.destroy;
+ actionManager.destroy = function () {
+ actionManager.destroy = originalDestroy;
+ widget.destroy();
+ };
+ actionManager.appendTo(widget.$el);
+
+ return actionManager;
+};
+
+/**
* create a view synchronously. This method uses the createAsyncView method.
* Most views are synchronous, so the deferred can be resolved immediately and
* this method will work.
@@ -87,8 +141,7 @@ function createView(params) {
*
* It returns the instance of the view, properly created, with all rpcs going
* through a mock method using the data object as source, and already loaded/
- * started (with a do_search). The buttons/pager should also be created, if
- * appropriate.
+ * started.
*
* Most views can be tested synchronously (@see createView), but some view have
* external dependencies (like lazy loaded libraries). In that case, it is
@@ -145,9 +198,9 @@ function createAsyncView(params) {
// reproduce the DOM environment of views
var $web_client = $('<div>').addClass('o_web_client').prependTo($target);
- var $control_panel = $('<div>').addClass('o_control_panel').appendTo($web_client);
+ var controlPanel = new ControlPanel(widget);
+ controlPanel.appendTo($web_client);
var $content = $('<div>').addClass('o_content').appendTo($web_client);
- var $view_manager = $('<div>').addClass('o_view_manager_content').appendTo($content);
return view.getController(widget).then(function (view) {
// override the view's 'destroy' so that it calls 'destroy' on the widget
@@ -159,29 +212,21 @@ function createAsyncView(params) {
widget.destroy();
$('#qunit-fixture').off('DOMNodeInserted.removeSRC');
};
+
+ // link the view to the control panel
+ view.set_cp_bus(controlPanel.get_bus());
+
// render the view in a fragment as they must be able to render correctly
// without being in the DOM
var fragment = document.createDocumentFragment();
return view.appendTo(fragment).then(function () {
- dom.append($view_manager, fragment, {
+ dom.append($content, fragment, {
callbacks: [{widget: view}],
in_DOM: true,
});
view.$el.on('click', 'a', function (ev) {
ev.preventDefault();
});
- }).then(function () {
- var $buttons = $('<div>');
- view.renderButtons($buttons);
- $buttons.contents().appendTo($control_panel);
-
- var $sidebar = $('<div>');
- view.renderSidebar($sidebar);
- $sidebar.contents().appendTo($control_panel);
-
- var $pager = $('<div>');
- view.renderPager($pager);
- $pager.contents().appendTo($control_panel);
return view;
});
@@ -250,6 +295,7 @@ function addMockEnvironment(widget, params) {
console.log('%c[debug] debug mode activated', 'color: blue; font-weight: bold;', url);
}
var mockServer = new Server(params.data, {
+ actions: params.actions,
archs: params.archs,
currentDate: params.currentDate,
debug: params.debug,
@@ -336,6 +382,14 @@ function addMockEnvironment(widget, params) {
}
});
+ intercept(widget, 'load_action', function (event) {
+ mockServer.performRpc('/web/action/load', {
+ kwargs: {action_id: event.data.actionID},
+ }).then(function (action) {
+ event.data.on_success(action);
+ });
+ });
+
intercept(widget, "load_views", function (event) {
mockServer.performRpc('/web/dataset/call_kw/' + event.data.modelName, {
args: [],
@@ -617,6 +671,7 @@ return $.when(
}, 0);
return {
addMockEnvironment: addMockEnvironment,
+ createActionManager: createActionManager,
createAsyncView: createAsyncView,
createModel: createModel,
createParent: createParent,
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index 9f2a9b68698..06cc046df83 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -1451,7 +1451,7 @@ QUnit.module('Views', {
'<field name="foo"/>' +
'</sheet>' +
'</form>',
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'search_read' && args.model === 'ir.attachment') {
@@ -1597,7 +1597,7 @@ QUnit.module('Views', {
'<field name="foo"/>' +
'</form>',
res_id: 1,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
mockRPC: function (route, args) {
if (args.method === 'search_read' && args.model === 'ir.attachment') {
return $.when([]);
@@ -1628,7 +1628,7 @@ QUnit.module('Views', {
'<field name="foo"/>' +
'</form>',
res_id: 1,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
mockRPC: function (route, args) {
if (args.method === 'search_read' && args.model === 'ir.attachment') {
return $.when([]);
@@ -1659,7 +1659,7 @@ QUnit.module('Views', {
'</footer>' +
'</form>',
res_id: 1,
- viewOptions: {footer_to_buttons: true},
+ viewOptions: {footerToButtons: true},
});
assert.ok(form.$buttons.find('button.infooter').length, "footer button should be in footer");
@@ -2050,7 +2050,7 @@ QUnit.module('Views', {
data: this.data,
arch: '<form string="Partners"><field name="date"></field></form>',
intercepts: {
- switch_to_previous_view: function (event) {
+ history_back: function () {
form.update({}, {reload: false});
}
},
@@ -2086,9 +2086,9 @@ QUnit.module('Views', {
return this._super.apply(this, arguments);
},
intercepts: {
- switch_to_previous_view: function (event) {
+ history_back: function () {
assert.ok(true, "should have sent correct event");
- // simulate the response from the view manager, in the case
+ // simulate the response from the action manager, in the case
// where we have only one active view (the form). If there
// was another view, we would have switched to that view
// instead
@@ -2126,7 +2126,7 @@ QUnit.module('Views', {
data: this.data,
arch: '<form string="Partners"><field name="foo"></field></form>',
intercepts: {
- switch_to_previous_view: function () {
+ history_back: function () {
assert.ok(true, "should have sent correct event");
}
}
@@ -2155,9 +2155,9 @@ QUnit.module('Views', {
data: this.data,
arch: '<form string="Partners"><field name="foo"></field></form>',
intercepts: {
- switch_to_previous_view: function (event) {
+ history_back: function () {
assert.ok(true, "should have sent correct event");
- // simulate the response from the view manager, in the case
+ // simulate the response from the action manager, in the case
// where we have only one active view (the form). If there
// was another view, we would have switched to that view
// instead
@@ -2197,7 +2197,7 @@ QUnit.module('Views', {
data: this.data,
arch: '<form string="Partners"><field name="foo"></field></form>',
res_id: 1,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
mockRPC: function (route, args) {
if (args.method === 'search_read' && args.model === 'ir.attachment') {
return $.when([]);
@@ -2542,7 +2542,7 @@ QUnit.module('Views', {
viewOptions: {
ids: [1, 2, 4],
index: 0,
- sidebar: true,
+ hasSidebar: true,
},
res_id: 1,
mockRPC: function (route, args) {
@@ -2586,7 +2586,7 @@ QUnit.module('Views', {
viewOptions: {
ids: [1],
index: 0,
- sidebar: true,
+ hasSidebar: true,
},
res_id: 1,
mockRPC: function (route, args) {
@@ -2602,15 +2602,14 @@ QUnit.module('Views', {
form.sidebar.$('button.o_dropdown_toggler_btn').click();
form.sidebar.$('a:contains(Delete)').click();
- testUtils.intercept(form, 'do_action', function (event) {
- assert.strictEqual(event.data.action, 'history_back',
- "should trigger an history back action");
+ testUtils.intercept(form, 'history_back', function () {
+ assert.step('history_back');
});
assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
$('.modal .modal-footer button.btn-primary').click();
assert.strictEqual($('.modal').length, 0, 'no confirm modal should be displayed');
- assert.verifySteps(['read', 'unlink']);
+ assert.verifySteps(['read', 'unlink', 'history_back']);
form.destroy();
});
@@ -4287,7 +4286,7 @@ QUnit.module('Views', {
'</form>',
res_id: 1,
viewOptions: {
- footer_to_buttons: true,
+ footerToButtons: true,
mode: 'edit',
},
});
@@ -4326,7 +4325,7 @@ QUnit.module('Views', {
'</form>',
res_id: 1,
viewOptions: {
- footer_to_buttons: true,
+ footerToButtons: true,
},
});
@@ -4684,7 +4683,7 @@ QUnit.module('Views', {
print: [],
},
viewOptions: {
- sidebar: true,
+ hasSidebar: true,
},
mockRPC: function (route, args) {
if (route === '/web/action/load') {
@@ -5943,7 +5942,7 @@ QUnit.module('Views', {
'<field name="display_name"/>' +
'</form>',
res_id: 1,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
mockRPC: function (route, args) {
if (args.method === 'search_read' && args.model === 'ir.attachment') {
// rpcs done by the sidebar
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index eed80410e7f..5b34ed413c5 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -164,7 +164,7 @@ QUnit.module('Views', {
groupBy: ['bar'],
intercepts: {
env_updated: function (event) {
- assert.deepEqual(event.data.ids, envIDs,
+ assert.deepEqual(event.data.env.ids, envIDs,
"should notify the environment with the correct ids");
},
},
@@ -384,7 +384,7 @@ QUnit.module('Views', {
groupBy: ['bar'],
intercepts: {
env_updated: function (event) {
- assert.strictEqual(event.data.ids.length, nbRecords,
+ assert.strictEqual(event.data.env.ids.length, nbRecords,
"should update the env with the records ids");
},
}
@@ -666,7 +666,7 @@ QUnit.module('Views', {
},
intercepts: {
switch_view: function (event) {
- assert.deepEqual(event.data, {
+ assert.deepEqual(_.pick(event.data, 'mode', 'model', 'res_id', 'view_type'), {
mode: 'readonly',
model: 'partner',
res_id: 1,
@@ -733,7 +733,7 @@ QUnit.module('Views', {
},
intercepts: {
env_updated: function (event) {
- assert.deepEqual(event.data.ids, envIDs,
+ assert.deepEqual(event.data.env.ids, envIDs,
"should notify the environment with the correct ids");
},
},
@@ -977,7 +977,7 @@ QUnit.module('Views', {
groupBy: ['product_id'],
intercepts: {
env_updated: function (event) {
- assert.deepEqual(envIDs, event.data.ids,
+ assert.deepEqual(event.data.env.ids, envIDs,
"should notify the environment with the correct ids");
},
},
@@ -1659,7 +1659,7 @@ QUnit.module('Views', {
},
intercepts: {
env_updated: function (event) {
- assert.deepEqual(event.data.ids, envIDs,
+ assert.deepEqual(event.data.env.ids, envIDs,
"should notify the environment with the correct ids");
},
},
@@ -1823,7 +1823,7 @@ QUnit.module('Views', {
},
intercepts:{
env_updated: function (event) {
- assert.deepEqual(event.data.ids, envIDs,
+ assert.deepEqual(event.data.env.ids, envIDs,
"should notify the environment with the correct ids");
},
},
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index 33b44948fca..b86a820196e 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -150,7 +150,7 @@ QUnit.module('Views', {
View: ListView,
model: 'foo',
data: this.data,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
arch: '<tree delete="0"><field name="foo"/></tree>',
});
@@ -261,7 +261,7 @@ QUnit.module('Views', {
'<field name="foo"/>' +
'<field name="m2o" invisible="1"/>' +
'</tree>',
- mockRPC: function (route, args) {
+ mockRPC: function (route) {
assert.step(_.last(route.split('/')));
return this._super.apply(this, arguments);
},
@@ -765,7 +765,7 @@ QUnit.module('Views', {
View: ListView,
model: 'foo',
data: this.data,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
arch: '<tree><field name="foo"/></tree>',
});
@@ -795,7 +795,7 @@ QUnit.module('Views', {
View: ListView,
model: 'foo',
data: this.data,
- viewOptions: {sidebar: true},
+ viewOptions: {hasSidebar: true},
arch: '<tree><field name="foo"/></tree>',
mockRPC: function (route) {
if (route === '/web/dataset/call_kw/ir.attachment/search_read') {
@@ -1686,7 +1686,7 @@ QUnit.module('Views', {
"'switch_view' event has been triggered");
},
env_updated: function (event) {
- assert.deepEqual(event.data.ids, envIDs,
+ assert.deepEqual(event.data.env.ids, envIDs,
"should notify the environment with the correct ids");
},
},
@@ -2031,7 +2031,7 @@ QUnit.module('Views', {
'<field name="bar"/>' +
'</tree>',
intercepts: {
- warning: function (ev) {
+ warning: function () {
warnings++;
},
},
@@ -2070,14 +2070,13 @@ QUnit.module('Views', {
arch: '<tree><field name="name"/></tree>',
});
- testUtils.intercept(list, "switch_view", function (event) {
- assert.deepEqual(event.data, {
- 'model': 'event',
- 'res_id': '2-20170808020000',
- 'view_type': 'form',
- 'mode': 'readonly'
- },
- "should trigger switch to the form view for the record virtual id");
+ testUtils.intercept(list, 'switch_view', function (event) {
+ assert.deepEqual(_.pick(event.data, 'mode', 'model', 'res_id', 'view_type'), {
+ mode: 'readonly',
+ model: 'event',
+ res_id: '2-20170808020000',
+ view_type: 'form',
+ }, "should trigger a switch_view event to the form view for the record virtual id");
});
list.$('td:contains(virtual)').click();
@@ -2092,7 +2091,7 @@ QUnit.module('Views', {
model: 'foo',
data: this.data,
arch: '<tree editable="bottom"><field name="foo"/></tree>',
- mockRPC: function (route, args) {
+ mockRPC: function (route) {
assert.step(route);
return this._super.apply(this, arguments);
},
@@ -2220,7 +2219,7 @@ QUnit.module('Views', {
print: [],
},
viewOptions: {
- sidebar: true,
+ hasSidebar: true,
},
});
diff --git a/addons/web/static/tests/views/view_dialogs_tests.js b/addons/web/static/tests/views/view_dialogs_tests.js
index b2dc9c5ab0e..08ddd2c91c2 100644
--- a/addons/web/static/tests/views/view_dialogs_tests.js
+++ b/addons/web/static/tests/views/view_dialogs_tests.js
@@ -51,7 +51,7 @@ QUnit.module('Views', {
});
testUtils.intercept(parent, 'env_updated', function () {
- throw new Error("The environment should not be propagated to the view manager");
+ throw new Error("The environment should not be propagated to the action manager");
});
diff --git a/addons/web/static/tests/widgets/data_export_tests.js b/addons/web/static/tests/widgets/data_export_tests.js
index d251e3dea15..192944ce3b5 100644
--- a/addons/web/static/tests/widgets/data_export_tests.js
+++ b/addons/web/static/tests/widgets/data_export_tests.js
@@ -53,7 +53,7 @@ QUnit.module('widgets', {
data: this.data,
arch: '<tree><field name="foo"/></tree>',
viewOptions: {
- sidebar: true,
+ hasSidebar: true,
},
mockRPC: function (route) {
if (route === '/web/export/formats') {
@@ -144,7 +144,7 @@ QUnit.module('widgets', {
data: this.data,
arch: '<tree><field name="foo"/></tree>',
viewOptions: {
- sidebar: true,
+ hasSidebar: true,
},
mockRPC: function (route) {
if (route === '/web/export/formats') {