3365 lines
122 KiB
JavaScript
3365 lines
122 KiB
JavaScript
odoo.define('web.action_manager_tests', function (require) {
|
|
"use strict";
|
|
|
|
var ReportClientAction = require('report.client_action');
|
|
var NotificationService = require('web.NotificationService');
|
|
var AbstractAction = require('web.AbstractAction');
|
|
var AbstractStorageService = require('web.AbstractStorageService');
|
|
var BasicFields = require('web.basic_fields');
|
|
var ControlPanelMixin = require('web.ControlPanelMixin');
|
|
var core = require('web.core');
|
|
var ListController = require('web.ListController');
|
|
var StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin');
|
|
var RamStorage = require('web.RamStorage');
|
|
var ReportService = require('web.ReportService');
|
|
var SessionStorageService = require('web.SessionStorageService');
|
|
var testUtils = require('web.test_utils');
|
|
var Widget = require('web.Widget');
|
|
var createActionManager = testUtils.createActionManager;
|
|
|
|
QUnit.module('ActionManager', {
|
|
beforeEach: function () {
|
|
this.data = {
|
|
partner: {
|
|
fields: {
|
|
foo: {string: "Foo", type: "char"},
|
|
bar: {string: "Bar", type: "many2one", relation: 'partner'},
|
|
},
|
|
records: [
|
|
{id: 1, display_name: "First record", foo: "yop", bar: 2},
|
|
{id: 2, display_name: "Second record", foo: "blip", bar: 1},
|
|
{id: 3, display_name: "Third record", foo: "gnap", bar: 1},
|
|
{id: 4, display_name: "Fourth record", foo: "plop", bar: 2},
|
|
{id: 5, display_name: "Fifth record", foo: "zoup", bar: 2},
|
|
],
|
|
},
|
|
pony: {
|
|
fields: {
|
|
name: {string: 'Name', type: 'char'},
|
|
},
|
|
records: [
|
|
{id: 4, name: 'Twilight Sparkle'},
|
|
{id: 6, name: 'Applejack'},
|
|
{id: 9, name: 'Fluttershy'}
|
|
],
|
|
},
|
|
};
|
|
|
|
this.actions = [{
|
|
id: 1,
|
|
name: 'Partners Action 1',
|
|
res_model: 'partner',
|
|
type: 'ir.actions.act_window',
|
|
views: [[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',
|
|
views: [[false, 'form']],
|
|
}, {
|
|
id: 6,
|
|
name: 'Partner',
|
|
res_id: 2,
|
|
res_model: 'partner',
|
|
target: 'inline',
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'form']],
|
|
}, {
|
|
id: 7,
|
|
name: "Some Report",
|
|
report_name: 'some_report',
|
|
report_type: 'qweb-pdf',
|
|
type: 'ir.actions.report',
|
|
}, {
|
|
id: 8,
|
|
name: 'Favorite Ponies',
|
|
res_model: 'pony',
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'list'], [false, 'form']],
|
|
}, {
|
|
id: 9,
|
|
name: 'A Client Action',
|
|
tag: 'ClientAction',
|
|
type: 'ir.actions.client',
|
|
}];
|
|
|
|
this.archs = {
|
|
// kanban views
|
|
'partner,1,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>',
|
|
'partner,2,list': '<tree limit="3"><field name="foo"/></tree>',
|
|
'pony,false,list': '<tree><field name="name"/></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>',
|
|
'pony,false,form': '<form>' +
|
|
'<field name="name"/>' +
|
|
'</form>',
|
|
|
|
// search views
|
|
'partner,false,search': '<search><field name="foo" string="Foo"/></search>',
|
|
'partner,1,search': '<search>' +
|
|
'<filter name="bar" help="Bar" domain="[(\'bar\', \'=\', 1)]"/>' +
|
|
'</search>',
|
|
'pony,false,search': '<search></search>',
|
|
};
|
|
},
|
|
}, function () {
|
|
QUnit.module('Misc');
|
|
|
|
QUnit.test('breadcrumbs and actions with target inline', function (assert) {
|
|
assert.expect(3);
|
|
|
|
this.actions[3].views = [[false, 'form']];
|
|
this.actions[3].target = 'inline';
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
|
|
actionManager.doAction(4);
|
|
assert.ok(!$('.o_control_panel').is(':visible'),
|
|
"control panel should not be visible");
|
|
|
|
actionManager.doAction(1, {clear_breadcrumbs: true});
|
|
assert.ok($('.o_control_panel').is(':visible'),
|
|
"control panel should now be visible");
|
|
assert.strictEqual($('.o_control_panel .breadcrumb').text(), "Partners Action 1",
|
|
"should have only one current action visible in breadcrumbs");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('no widget memory leaks when doing some action stuff', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var delta = 0;
|
|
testUtils.patch(Widget, {
|
|
init: function () {
|
|
delta++;
|
|
this._super.apply(this, arguments);
|
|
},
|
|
destroy: function () {
|
|
delta--;
|
|
this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction(8);
|
|
|
|
var n = delta;
|
|
actionManager.doAction(4);
|
|
// kanban view is loaded, switch to list view
|
|
$('.o_control_panel .o_cp_switch_list').click();
|
|
// open a record in form view
|
|
actionManager.$('.o_list_view .o_data_row:first').click();
|
|
// go back to action 7 in breadcrumbs
|
|
$('.o_control_panel .breadcrumb a:first').click();
|
|
|
|
assert.strictEqual(delta, n,
|
|
"should have properly destroyed all other widgets");
|
|
actionManager.destroy();
|
|
testUtils.unpatch(Widget);
|
|
});
|
|
|
|
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('no memory leaks when executing an action while loading views', 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 === 'load_views') {
|
|
return $.when(def).then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
// execute action 4 to know the number of widgets it instantiates
|
|
actionManager.doAction(4);
|
|
var n = delta;
|
|
|
|
// execute a first action (its 'load_views' RPC is blocked)
|
|
def = $.Deferred();
|
|
actionManager.doAction(3, {clear_breadcrumbs: true});
|
|
|
|
// execute another action meanwhile (and unlock the RPC)
|
|
actionManager.doAction(4, {clear_breadcrumbs: true});
|
|
def.resolve();
|
|
|
|
assert.strictEqual(n, delta,
|
|
"all widgets of action 3 should have been destroyed");
|
|
|
|
actionManager.destroy();
|
|
testUtils.unpatch(Widget);
|
|
});
|
|
|
|
QUnit.test('no memory leaks when executing an action while loading data of default 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) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (route === '/web/dataset/search_read') {
|
|
return $.when(def).then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
// execute action 4 to know the number of widgets it instantiates
|
|
actionManager.doAction(4);
|
|
var n = delta;
|
|
|
|
// execute a first action (its 'search_read' RPC is blocked)
|
|
def = $.Deferred();
|
|
actionManager.doAction(3, {clear_breadcrumbs: true});
|
|
|
|
// execute another action meanwhile (and unlock the RPC)
|
|
actionManager.doAction(4, {clear_breadcrumbs: true});
|
|
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.test('stores and restores scroll position', function (assert) {
|
|
assert.expect(7);
|
|
|
|
var left;
|
|
var top;
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
getScrollPosition: function (ev) {
|
|
assert.step('getScrollPosition');
|
|
ev.data.callback({left: left, top: top});
|
|
},
|
|
scrollTo: function (ev) {
|
|
assert.step('scrollTo left ' + ev.data.left + ', top ' + ev.data.top);
|
|
},
|
|
},
|
|
});
|
|
|
|
// execute a first action and simulate a scroll
|
|
assert.step('execute action 3');
|
|
actionManager.doAction(3);
|
|
left = 50;
|
|
top = 100;
|
|
|
|
// execute a second action (in which we don't scroll)
|
|
assert.step('execute action 4');
|
|
actionManager.doAction(4);
|
|
|
|
// go back using the breadcrumbs
|
|
assert.step('go back to action 3');
|
|
$('.o_control_panel .breadcrumb a').click();
|
|
|
|
assert.verifySteps([
|
|
'execute action 3',
|
|
'execute action 4',
|
|
'getScrollPosition', // of action 3, before leaving it
|
|
'go back to action 3',
|
|
'getScrollPosition', // of action 4, before leaving it
|
|
'scrollTo left 50, top 100', // restore scroll position of action 3
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.module('Push State');
|
|
|
|
QUnit.test('properly push state', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var stateDescriptions = [
|
|
{action: 4, model: "partner", title: "Partners Action 4", view_type: "kanban"},
|
|
{action: 8, model: "pony", title: "Favorite Ponies", view_type: "list"},
|
|
{action: 8, id: 4, model: "pony", title: "Twilight Sparkle", view_type: "form"},
|
|
];
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
push_state: function (event) {
|
|
var descr = stateDescriptions.shift();
|
|
assert.deepEqual(_.extend({}, event.data.state), descr,
|
|
"should notify the environment of new state");
|
|
},
|
|
},
|
|
});
|
|
actionManager.doAction(4);
|
|
actionManager.doAction(8);
|
|
actionManager.$('tr.o_data_row:first').click();
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('push state after action is loaded, not before', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
push_state: function () {
|
|
assert.step('push_state');
|
|
},
|
|
},
|
|
mockRPC: function (route) {
|
|
assert.step(route);
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
actionManager.doAction(4);
|
|
assert.verifySteps([
|
|
'/web/action/load',
|
|
'/web/dataset/call_kw/partner',
|
|
'/web/dataset/search_read',
|
|
'push_state'
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('do not push state for actions in target=new', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
push_state: function () {
|
|
assert.step('push_state');
|
|
},
|
|
},
|
|
});
|
|
actionManager.doAction(4);
|
|
assert.verifySteps(['push_state']);
|
|
actionManager.doAction(5);
|
|
assert.verifySteps(['push_state']);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('do not push state when action fails', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
push_state: function () {
|
|
assert.step('push_state');
|
|
},
|
|
},
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read') {
|
|
// this is the rpc to load form view
|
|
return $.Deferred().reject();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
actionManager.doAction(8);
|
|
assert.verifySteps(['push_state']);
|
|
actionManager.$('tr.o_data_row:first').click();
|
|
assert.verifySteps(['push_state']);
|
|
// we make sure here that the list view is still in the dom
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 1,
|
|
"there should still be a list view in dom");
|
|
|
|
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 = AbstractAction.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(3);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
push_state: function () {
|
|
assert.step('push_state');
|
|
},
|
|
},
|
|
});
|
|
actionManager.loadState({action: 3});
|
|
|
|
assert.verifySteps([], "should not push the loaded state");
|
|
|
|
actionManager.$('tr.o_data_row:first').click();
|
|
|
|
assert.verifySteps(['push_state'],
|
|
"should push the state of it changes afterwards");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('should not push a loaded state of a client action', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var ClientAction = Widget.extend({
|
|
init: function (parent, action, options) {
|
|
this._super.apply(this, arguments);
|
|
this.controllerID = options.controllerID;
|
|
},
|
|
start: function () {
|
|
var self = this;
|
|
var $button = $('<button>').text('Click Me!');
|
|
$button.on('click', function () {
|
|
self.trigger_up('push_state', {
|
|
controllerID: self.controllerID,
|
|
state: {someValue: 'X'},
|
|
});
|
|
});
|
|
this.$el.append($button);
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
core.action_registry.add('ClientAction', ClientAction);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
push_state: function (ev) {
|
|
assert.step('push_state');
|
|
assert.deepEqual(ev.data.state, {
|
|
action: 9,
|
|
someValue: 'X',
|
|
title: 'A Client Action',
|
|
});
|
|
},
|
|
},
|
|
});
|
|
actionManager.loadState({action: 9});
|
|
|
|
assert.verifySteps([], "should not push the loaded state");
|
|
|
|
actionManager.$('button').click();
|
|
|
|
assert.verifySteps(['push_state'],
|
|
"should push the state of it changes afterwards");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('change a param of an ir.actions.client in the url', function (assert) {
|
|
assert.expect(7);
|
|
|
|
var ClientAction = AbstractAction.extend(ControlPanelMixin, {
|
|
className: 'o_client_action',
|
|
init: function (parent, action) {
|
|
this._super.apply(this, arguments);
|
|
var context = action.context;
|
|
this.a = context.params && context.params.a || 'default value';
|
|
},
|
|
start: function () {
|
|
assert.step('start');
|
|
this.$el.text(this.a);
|
|
this.trigger_up('push_state', {
|
|
controllerID: this.controllerID,
|
|
state: {a: this.a},
|
|
});
|
|
},
|
|
});
|
|
core.action_registry.add('ClientAction', ClientAction);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
|
|
// execute the client action
|
|
actionManager.doAction(9);
|
|
|
|
assert.strictEqual(actionManager.$('.o_client_action').text(), 'default value',
|
|
"should have rendered the client action");
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
|
|
"there should be one controller in the breadcrumbs");
|
|
|
|
// update param 'a' in the url
|
|
actionManager.loadState({
|
|
action: 9,
|
|
a: 'new value',
|
|
});
|
|
|
|
assert.strictEqual(actionManager.$('.o_client_action').text(), 'new value',
|
|
"should have rerendered the client action with the correct param");
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
|
|
"there should still be one controller in the breadcrumbs");
|
|
|
|
// should have executed the client action twice
|
|
assert.verifySteps(['start', 'start']);
|
|
|
|
actionManager.destroy();
|
|
delete core.action_registry.map.ClientAction;
|
|
});
|
|
|
|
QUnit.test('load a window action without id (in a multi-record view)', function (assert) {
|
|
assert.expect(14);
|
|
|
|
var RamStorageService = AbstractStorageService.extend({
|
|
name: 'session_storage',
|
|
storage: new RamStorage(),
|
|
});
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
services: [RamStorageService],
|
|
mockRPC: function (route, args) {
|
|
assert.step(args.method || route);
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
testUtils.intercept(actionManager, 'call_service', function (ev) {
|
|
if (ev.data.service === 'session_storage') {
|
|
assert.step(ev.data.method);
|
|
}
|
|
}, true);
|
|
|
|
actionManager.doAction(4);
|
|
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
|
|
"should display a kanban view");
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners Action 4',
|
|
"breadcrumbs should display the display_name of the action");
|
|
|
|
actionManager.loadState({
|
|
model: 'partner',
|
|
view_type: 'list',
|
|
});
|
|
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners Action 4',
|
|
"should still be in the same action");
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 0,
|
|
"should no longer display a kanban view");
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 1,
|
|
"should display a list view");
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load', // action 3
|
|
'load_views', // action 3
|
|
'/web/dataset/search_read', // action 3
|
|
'setItem', // action 3
|
|
'getItem', // loadState
|
|
'load_views', // loaded action
|
|
'/web/dataset/search_read', // loaded action
|
|
'setItem', // loaded action
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.module('Concurrency management');
|
|
|
|
QUnit.test('drop previous actions if possible', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var def = $.Deferred();
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route) {
|
|
var result = this._super.apply(this, arguments);
|
|
assert.step(route);
|
|
if (route === '/web/action/load') {
|
|
return def.then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
actionManager.doAction(4);
|
|
actionManager.doAction(8);
|
|
|
|
def.resolve();
|
|
|
|
// action 4 loads a kanban view first, 6 loads a list view. We want a list
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 1,
|
|
'there should be a list view in DOM');
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load', // load action 4
|
|
'/web/action/load', // load action 6
|
|
'/web/dataset/call_kw/pony', // load views for action 6
|
|
'/web/dataset/search_read', // search read for list view action 6
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('handle switching view and switching back on slow network', function (assert) {
|
|
assert.expect(8);
|
|
|
|
var def = $.Deferred();
|
|
var defs = [$.when(), def, $.when()];
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route) {
|
|
assert.step(route);
|
|
var result = this._super.apply(this, arguments);
|
|
if (route === '/web/dataset/search_read') {
|
|
var def = defs.shift();
|
|
return def.then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
actionManager.doAction(4);
|
|
|
|
// kanban view is loaded, switch to list view
|
|
$('.o_control_panel .o_cp_switch_list').click();
|
|
|
|
// here, list view is not ready yet, because def is not resolved
|
|
// switch back to kanban view
|
|
$('.o_control_panel .o_cp_switch_kanban').click();
|
|
|
|
// here, we want the kanban view to reload itself, regardless of list view
|
|
assert.verifySteps([
|
|
"/web/action/load", // initial load action
|
|
"/web/dataset/call_kw/partner", // load views
|
|
"/web/dataset/search_read", // search_read for kanban view
|
|
"/web/dataset/search_read", // search_read for list view (not resolved yet)
|
|
"/web/dataset/search_read" // search_read for kanban view reload (not resolved yet)
|
|
]);
|
|
|
|
// we resolve def => list view is now ready (but we want to ignore it)
|
|
def.resolve();
|
|
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
|
|
"there should be a kanban view in dom");
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"there should not be a list view in dom");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('when an server action takes too much time...', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var def = $.Deferred();
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route) {
|
|
if (route === '/web/action/run') {
|
|
return def.then(_.constant(1));
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
actionManager.doAction(2);
|
|
actionManager.doAction(4);
|
|
|
|
def.resolve();
|
|
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li.active').text(), 'Partners Action 4',
|
|
'action 4 should be loaded');
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('clicking quickly on breadcrumbs...', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var def = $.when();
|
|
|
|
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 def.then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
// create a situation with 3 breadcrumbs: kanban/form/list
|
|
actionManager.doAction(4);
|
|
actionManager.$('.o_kanban_record:first').click();
|
|
actionManager.doAction(8);
|
|
|
|
// now, the next read operations will be deferred (this is the read
|
|
// operation for the form view reload)
|
|
def = $.Deferred();
|
|
|
|
// click on the breadcrumbs for the form view, then on the kanban view
|
|
// before the form view is fully reloaded
|
|
$('.o_control_panel .breadcrumb li:eq(1)').click();
|
|
$('.o_control_panel .breadcrumb li:eq(0)').click();
|
|
|
|
// resolve the form view read
|
|
def.resolve();
|
|
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li.active').text(), 'Partners Action 4',
|
|
'action 4 should be loaded and visible');
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
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.test('execute a new action while loading views', function (assert) {
|
|
assert.expect(10);
|
|
|
|
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 === 'load_views') {
|
|
return $.when(def).then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
// execute a first action (its 'load_views' RPC is blocked)
|
|
def = $.Deferred();
|
|
actionManager.doAction(3);
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"should not display the list view of action 3");
|
|
|
|
// execute another action meanwhile (and unlock the RPC)
|
|
actionManager.doAction(4);
|
|
def.resolve();
|
|
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
|
|
"should display the kanban view of action 4");
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"should not display the list view of action 3");
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
|
|
"there should be one controller in the breadcrumbs");
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load', // action 3
|
|
'load_views', // action 3
|
|
'/web/action/load', // action 4
|
|
'load_views', // action 4
|
|
'/web/dataset/search_read', // search read action 4
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('execute a new action while loading data of default view', function (assert) {
|
|
assert.expect(11);
|
|
|
|
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') {
|
|
return $.when(def).then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
// execute a first action (its 'search_read' RPC is blocked)
|
|
def = $.Deferred();
|
|
actionManager.doAction(3);
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"should not display the list view of action 3");
|
|
|
|
// execute another action meanwhile (and unlock the RPC)
|
|
actionManager.doAction(4);
|
|
def.resolve();
|
|
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
|
|
"should display the kanban view of action 4");
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"should not display the list view of action 3");
|
|
assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
|
|
"there should be one controller in the breadcrumbs");
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load', // action 3
|
|
'load_views', // action 3
|
|
'/web/dataset/search_read', // search read action 3
|
|
'/web/action/load', // action 4
|
|
'load_views', // action 4
|
|
'/web/dataset/search_read', // search read action 4
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('open a record while reloading the list view', function (assert) {
|
|
assert.expect(12);
|
|
|
|
var def;
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (route === '/web/dataset/search_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");
|
|
assert.strictEqual(actionManager.$('.o_list_view .o_data_row').length, 5,
|
|
"list view should contain 5 records");
|
|
assert.strictEqual($('.o_control_panel .o_list_buttons').length, 1,
|
|
"list view buttons should be displayed in control panel");
|
|
|
|
// reload (the search_read RPC will be blocked)
|
|
def = $.Deferred();
|
|
$('.o_control_panel .o_cp_switch_list').click(); // click on the switch button
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view .o_data_row').length, 5,
|
|
"list view should still contain 5 records");
|
|
assert.strictEqual($('.o_control_panel .o_list_buttons').length, 1,
|
|
"list view buttons should still be displayed in control panel");
|
|
|
|
// open a record in form view
|
|
actionManager.$('.o_list_view .o_data_row:first').click();
|
|
|
|
assert.strictEqual(actionManager.$('.o_form_view').length, 1,
|
|
"should display the form view");
|
|
assert.strictEqual($('.o_control_panel .o_list_buttons').length, 0,
|
|
"list view buttons should no longer be displayed in control panel");
|
|
assert.strictEqual($('.o_control_panel .o_form_buttons_view').length, 1,
|
|
"form view buttons should be displayed instead");
|
|
|
|
// unblock the search_read RPC
|
|
def.resolve();
|
|
|
|
assert.strictEqual(actionManager.$('.o_form_view').length, 1,
|
|
"should display the form view");
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"should not display the list view");
|
|
assert.strictEqual($('.o_control_panel .o_list_buttons').length, 0,
|
|
"list view buttons should still not be displayed in control panel");
|
|
assert.strictEqual($('.o_control_panel .o_form_buttons_view').length, 1,
|
|
"form view buttons should still be displayed instead");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.module('Client Actions');
|
|
|
|
QUnit.test('can execute client actions from tag name', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var ClientAction = AbstractAction.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 = AbstractAction.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 = AbstractAction.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.test('breadcrumb is updated on title change', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var ClientAction = Widget.extend(ControlPanelMixin, {
|
|
className: 'o_client_action_test',
|
|
events: {
|
|
click: function () {
|
|
this.set("title", 'new title');
|
|
},
|
|
},
|
|
start: function () {
|
|
this.set("title", 'initial title');
|
|
this.$el.text('Hello World');
|
|
},
|
|
});
|
|
var actionManager = createActionManager();
|
|
core.action_registry.add('HelloWorldTest', ClientAction);
|
|
actionManager.doAction('HelloWorldTest');
|
|
|
|
assert.strictEqual($('ol.breadcrumb').text(), "initial title",
|
|
"should have initial title as breadcrumb content");
|
|
|
|
actionManager.$('.o_client_action_test').click();
|
|
assert.strictEqual($('ol.breadcrumb').text(), "new title",
|
|
"should have updated title as breadcrumb content");
|
|
|
|
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.test('handle server actions returning false', 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') {
|
|
return $.when(false);
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
// execute an action in target="new"
|
|
actionManager.doAction(5, {
|
|
on_close: assert.step.bind(assert, 'close handler'),
|
|
});
|
|
assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
|
|
"should have rendered a form view in a modal");
|
|
|
|
// execute a server action that returns false
|
|
actionManager.doAction(2);
|
|
assert.strictEqual($('.o_technical_modal').length, 0,
|
|
"should have closed the modal");
|
|
assert.verifySteps([
|
|
'/web/action/load', // action 5
|
|
'load_views',
|
|
'default_get',
|
|
'/web/action/load', // action 2
|
|
'/web/action/run',
|
|
'close handler',
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.module('Report actions');
|
|
|
|
QUnit.test('can execute report actions from db ID', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
services: [ReportService],
|
|
mockRPC: function (route, args) {
|
|
assert.step(args.method || route);
|
|
if (route === '/report/check_wkhtmltopdf') {
|
|
return $.when('ok');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
session: {
|
|
get_file: function (params) {
|
|
assert.step(params.url);
|
|
params.success();
|
|
params.complete();
|
|
return true;
|
|
},
|
|
},
|
|
});
|
|
actionManager.doAction(7, {
|
|
on_close: function () {
|
|
assert.step('on_close');
|
|
},
|
|
});
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load',
|
|
'/report/check_wkhtmltopdf',
|
|
'/web/static/src/img/spin.png', // block UI image
|
|
'/report/download',
|
|
'on_close',
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('should trigger a notification if wkhtmltopdf is to upgrade', function (assert) {
|
|
assert.expect(6);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
services: [ReportService, NotificationService.extend({
|
|
notify: function (params) {
|
|
assert.step(params.type || 'notification');
|
|
}
|
|
})],
|
|
mockRPC: function (route, args) {
|
|
assert.step(args.method || route);
|
|
if (route === '/report/check_wkhtmltopdf') {
|
|
return $.when('upgrade');
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
session: {
|
|
get_file: function (params) {
|
|
assert.step(params.url);
|
|
params.success();
|
|
params.complete();
|
|
return true;
|
|
},
|
|
},
|
|
});
|
|
actionManager.doAction(7);
|
|
assert.verifySteps([
|
|
'/web/action/load',
|
|
'/report/check_wkhtmltopdf',
|
|
'notification',
|
|
'/web/static/src/img/spin.png', // block UI image
|
|
'/report/download',
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('should open the report client action if wkhtmltopdf is broken', function (assert) {
|
|
assert.expect(6);
|
|
|
|
// patch the report client action to override its iframe's url so that
|
|
// it doesn't trigger an RPC when it is appended to the DOM (for this
|
|
// usecase, using removeSRCAttribute doesn't work as the RPC is
|
|
// triggered as soon as the iframe is in the DOM, even if its src
|
|
// attribute is removed right after)
|
|
testUtils.patch(ReportClientAction, {
|
|
start: function () {
|
|
var self = this;
|
|
return this._super.apply(this, arguments).then(function () {
|
|
self.iframe.src = 'test: ' + self.iframe.getAttribute('src');
|
|
});
|
|
}
|
|
});
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
services: [ReportService, NotificationService.extend({
|
|
notify: function (params) {
|
|
assert.step(params.type || 'notification');
|
|
}
|
|
})],
|
|
mockRPC: function (route, args) {
|
|
assert.step(args.method || route);
|
|
if (route === '/report/check_wkhtmltopdf') {
|
|
return $.when('broken');
|
|
}
|
|
if (route === 'test: /report/html/some_report') {
|
|
return $.when();
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
session: {
|
|
get_file: function (params) {
|
|
assert.step(params.url); // should not be called
|
|
return true;
|
|
},
|
|
},
|
|
});
|
|
actionManager.doAction(7);
|
|
|
|
assert.strictEqual(actionManager.$('.o_report_iframe').length, 1,
|
|
"should have opened the report client action");
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load',
|
|
'/report/check_wkhtmltopdf',
|
|
'notification',
|
|
'test: /report/html/some_report', // report client action's iframe
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
testUtils.unpatch(ReportClientAction);
|
|
});
|
|
|
|
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('restore previous view state when switching back', function (assert) {
|
|
assert.expect(5);
|
|
|
|
this.actions[2].views.unshift([false, 'graph']);
|
|
this.archs['partner,false,graph'] = '<graph></graph>';
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction(3);
|
|
|
|
assert.ok($('.o_control_panel .fa-bar-chart-o').hasClass('active'),
|
|
"bar chart button is active");
|
|
assert.ok(!$('.o_control_panel .fa-line-chart').hasClass('active'),
|
|
"line chart button is not active");
|
|
|
|
// display line chart
|
|
$('.o_control_panel .fa-line-chart').click();
|
|
assert.ok($('.o_control_panel .fa-line-chart').hasClass('active'),
|
|
"line chart button is now active");
|
|
|
|
// switch to kanban and back to graph view
|
|
$('.o_control_panel .o_cp_switch_kanban').click();
|
|
assert.strictEqual($('.o_control_panel .fa-line-chart').length, 0,
|
|
"graph buttons are no longer in control panel");
|
|
|
|
$('.o_control_panel .o_cp_switch_graph').click();
|
|
assert.ok($('.o_control_panel .fa-line-chart').hasClass('active'),
|
|
"line chart button is still active");
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('view switcher is properly highlighted in graph view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
// note: this test should be moved to graph tests ?
|
|
|
|
this.actions[2].views.splice(1, 1, [false, 'graph']);
|
|
this.archs['partner,false,graph'] = '<graph></graph>';
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction(3);
|
|
|
|
assert.ok($('.o_control_panel .o_cp_switch_list').hasClass('active'),
|
|
"list button in control panel is active");
|
|
assert.ok(!$('.o_control_panel .o_cp_switch_graph').hasClass('active'),
|
|
"graph button in control panel is not active");
|
|
|
|
// switch to graph view
|
|
$('.o_control_panel .o_cp_switch_graph').click();
|
|
assert.ok(!$('.o_control_panel .o_cp_switch_list').hasClass('active'),
|
|
"list button in control panel is not active");
|
|
assert.ok($('.o_control_panel .o_cp_switch_graph').hasClass('active'),
|
|
"graph button in control panel is active");
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('can interact with search view', function (assert) {
|
|
assert.expect(2);
|
|
|
|
this.archs['partner,false,search'] = '<search>'+
|
|
'<group>'+
|
|
'<filter name="foo" string="foo" context="{\'group_by\': \'foo\'}"/>' +
|
|
'</group>'+
|
|
'</search>';
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction(3);
|
|
|
|
assert.ok(!actionManager.$('.o_list_view').hasClass('o_list_view_grouped'),
|
|
"list view is not grouped");
|
|
// open search view sub menus
|
|
$('.o_control_panel .o_searchview_more').click();
|
|
|
|
// open group by dropdown
|
|
$('.o_control_panel .o_cp_right button:contains(Group By)').click();
|
|
|
|
// click on first link
|
|
$('.o_control_panel .o_group_by_menu a:first').click();
|
|
|
|
assert.ok(actionManager.$('.o_list_view').hasClass('o_list_view_grouped'),
|
|
'list view is now grouped');
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('can open a many2one external window', function (assert) {
|
|
// AAB: this test could be merged with 'many2ones in form views' in relational_fields_tests.js
|
|
assert.expect(8);
|
|
|
|
this.data.partner.records[0].bar = 2;
|
|
this.archs['partner,false,search'] = '<search>'+
|
|
'<group>'+
|
|
'<filter name="foo" string="foo" context="{\'group_by\': \'foo\'}"/>' +
|
|
'</group>'+
|
|
'</search>';
|
|
this.archs['partner,false,form'] = '<form>' +
|
|
'<group>' +
|
|
'<field name="foo"/>' +
|
|
'<field name="bar"/>' +
|
|
'</group>' +
|
|
'</form>';
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route, args) {
|
|
assert.step(route);
|
|
if (args.method === "get_formview_id") {
|
|
return $.when(false);
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
actionManager.doAction(3);
|
|
|
|
// open first record in form view
|
|
actionManager.$('.o_data_row:first').click();
|
|
// click on edit
|
|
$('.o_control_panel .o_form_button_edit').click();
|
|
|
|
// click on external button for m2o
|
|
actionManager.$('.o_external_button').click();
|
|
assert.verifySteps([
|
|
'/web/action/load', // initial load action
|
|
'/web/dataset/call_kw/partner', // load views
|
|
'/web/dataset/search_read', // read list view data
|
|
'/web/dataset/call_kw/partner/read', // read form view data
|
|
'/web/dataset/call_kw/partner/get_formview_id', // get form view id
|
|
'/web/dataset/call_kw/partner', // load form view for modal
|
|
'/web/dataset/call_kw/partner/read' // read data for m2o record
|
|
]);
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('ask for confirmation when leaving a "dirty" view', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction(4);
|
|
|
|
// open record in form view
|
|
actionManager.$('.o_kanban_record:first').click();
|
|
|
|
// edit record
|
|
$('.o_control_panel button.o_form_button_edit').click();
|
|
actionManager.$('input[name="foo"]').val('pinkypie').trigger('input');
|
|
|
|
// go back to kanban view
|
|
$('.o_control_panel .breadcrumb li:first a').click();
|
|
|
|
assert.strictEqual($('.modal .modal-body').text(),
|
|
"The record has been modified, your changes will be discarded. Do you want to proceed?",
|
|
"should display a modal dialog to confirm discard action");
|
|
|
|
// cancel
|
|
$('.modal .modal-footer button.btn-default').click();
|
|
|
|
assert.strictEqual(actionManager.$('.o_form_view').length, 1,
|
|
"should still be in form view");
|
|
|
|
// go back again to kanban view
|
|
$('.o_control_panel .breadcrumb li:first a').click();
|
|
|
|
// confirm discard
|
|
$('.modal .modal-footer button.btn-primary').click();
|
|
|
|
assert.strictEqual(actionManager.$('.o_form_view').length, 0,
|
|
"should no longer be in form view");
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
|
|
"should be in kanban view");
|
|
|
|
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.test('honor group_by specified in actions context', function (assert) {
|
|
assert.expect(5);
|
|
|
|
_.findWhere(this.actions, {id: 3}).context = "{'group_by': 'bar'}";
|
|
this.archs['partner,false,search'] = '<search>'+
|
|
'<group>'+
|
|
'<filter name="foo" string="foo" context="{\'group_by\': \'foo\'}"/>' +
|
|
'</group>'+
|
|
'</search>';
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction(3);
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view_grouped').length, 1,
|
|
"should be grouped");
|
|
assert.strictEqual(actionManager.$('.o_group_header').length, 2,
|
|
"should be grouped by 'bar' (two groups) at first load");
|
|
|
|
// groupby 'bar' using the searchview
|
|
$('.o_control_panel .o_searchview_more').click(); // open search view sub menus
|
|
$('.o_control_panel .o_cp_right button:contains(Group By)').click(); // open groupby dropdown
|
|
$('.o_control_panel .o_group_by_menu a:first').click(); // click on 'Foo'
|
|
|
|
assert.strictEqual(actionManager.$('.o_group_header').length, 5,
|
|
"should be grouped by 'foo' (five groups)");
|
|
|
|
// remove the groupby in the searchview
|
|
$('.o_control_panel .o_searchview .o_facet_remove').click();
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view_grouped').length, 1,
|
|
"should still be grouped");
|
|
assert.strictEqual(actionManager.$('.o_group_header').length, 2,
|
|
"should be grouped by 'bar' (two groups) at reload");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('switch request to unknown view type', function (assert) {
|
|
assert.expect(7);
|
|
|
|
this.actions.push({
|
|
id: 33,
|
|
name: 'Partners',
|
|
res_model: 'partner',
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'list'], [1, 'kanban']], // no form view
|
|
});
|
|
|
|
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(33);
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 1,
|
|
"should display the list view");
|
|
|
|
// try to open a record in a form view
|
|
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,
|
|
"should not display the form view");
|
|
|
|
assert.verifySteps([
|
|
'/web/action/load',
|
|
'load_views',
|
|
'/web/dataset/search_read',
|
|
]);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('save current search', function (assert) {
|
|
assert.expect(4);
|
|
|
|
testUtils.patch(ListController, {
|
|
getContext: function () {
|
|
return {
|
|
shouldBeInFilterContext: true,
|
|
};
|
|
},
|
|
});
|
|
|
|
this.actions.push({
|
|
id: 33,
|
|
context: {
|
|
shouldNotBeInFilterContext: false,
|
|
},
|
|
name: 'Partners',
|
|
res_model: 'partner',
|
|
search_view_id: [1, 'a custom search view'],
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'list']],
|
|
});
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
intercepts: {
|
|
create_filter: function (event) {
|
|
var filter = event.data.filter;
|
|
assert.deepEqual(filter.domain, [['bar', '=', 1]],
|
|
"should save the correct domain");
|
|
assert.deepEqual(filter.context, {shouldBeInFilterContext: true},
|
|
"should save the correct context");
|
|
},
|
|
},
|
|
});
|
|
actionManager.doAction(33);
|
|
|
|
assert.strictEqual(actionManager.$('.o_data_row').length, 5,
|
|
"should contain 5 records");
|
|
|
|
// filter on bar
|
|
$('.o_control_panel .o_filters_menu a:contains(Bar)').click();
|
|
|
|
assert.strictEqual(actionManager.$('.o_data_row').length, 2,
|
|
"should contain 2 records");
|
|
|
|
// save filter
|
|
$('.o_control_panel .o_save_search a').click(); // toggle 'Save current search'
|
|
$('.o_control_panel .o_save_name input[type=text]').val('some name'); // name the filter
|
|
$('.o_control_panel .o_save_name button').click(); // click on 'Save'
|
|
|
|
testUtils.unpatch(ListController);
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test("search menus are still available when switching between actions", function (assert) {
|
|
assert.expect(3);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
|
|
actionManager.doAction(1);
|
|
assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1,
|
|
"the search options should be available");
|
|
|
|
actionManager.doAction(3);
|
|
assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1,
|
|
"the search options should be available");
|
|
|
|
// go back using the breadcrumbs
|
|
$('.o_control_panel .breadcrumb a:first').click();
|
|
assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1,
|
|
"the search options should be available");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test("doAction with option 'keepSearchView'", function (assert) {
|
|
assert.expect(4);
|
|
|
|
this.actions.push({
|
|
id: 33,
|
|
name: 'Partners',
|
|
res_model: 'partner',
|
|
search_view_id: [1, 'a specific search view'],
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'list']],
|
|
});
|
|
|
|
var checkRPC = false;
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route, args) {
|
|
if (checkRPC && route === '/web/dataset/search_read') {
|
|
assert.deepEqual(args.domain, [['bar', '=', 1]],
|
|
"should search with the correct domain");
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
actionManager.doAction(33);
|
|
|
|
checkRPC = true;
|
|
$('.o_control_panel .o_filters_menu a:contains(Bar)').click(); // filter on bar
|
|
assert.strictEqual($('.o_control_panel .o_facet_values').text().trim(), 'Bar',
|
|
"the filter on Bar should appear in the search view");
|
|
|
|
actionManager.doAction(3, {keepSearchView: true});
|
|
assert.strictEqual($('.o_control_panel .o_facet_values').text().trim(), 'Bar',
|
|
"the filter on Bar should still be in the search view");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test("current act_window action is stored in session_storage", function (assert) {
|
|
assert.expect(1);
|
|
|
|
var expectedAction = _.extend({}, _.findWhere(this.actions, {id: 3}), {
|
|
context: {},
|
|
});
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
services: [SessionStorageService.extend({
|
|
setItem: function (key, value) {
|
|
assert.strictEqual(value, JSON.stringify(expectedAction),
|
|
"should store the executed action in the sessionStorage");
|
|
},
|
|
})],
|
|
});
|
|
|
|
actionManager.doAction(3);
|
|
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test("store evaluated context of current action in session_storage", function (assert) {
|
|
// this test ensures that we don't store stringified instances of
|
|
// CompoundContext in the session_storage, as they would be meaningless
|
|
// once restored
|
|
assert.expect(1);
|
|
|
|
var expectedAction = _.extend({}, _.findWhere(this.actions, {id: 4}), {
|
|
context: {
|
|
active_model: 'partner',
|
|
active_id: 1,
|
|
active_ids: [1],
|
|
},
|
|
});
|
|
var checkSessionStorage = false;
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
services: [SessionStorageService.extend({
|
|
setItem: function (key, value) {
|
|
if (checkSessionStorage) {
|
|
assert.strictEqual(value, JSON.stringify(expectedAction),
|
|
"should correctly store the executed action in the sessionStorage");
|
|
}
|
|
},
|
|
})],
|
|
});
|
|
|
|
// execute an action and open a record in form view
|
|
actionManager.doAction(3);
|
|
actionManager.$('.o_list_view .o_data_row:first').click();
|
|
|
|
// click on 'Execute action' button (it executes an action with a CompoundContext as context)
|
|
checkSessionStorage = true;
|
|
actionManager.$('.o_form_view button:contains(Execute action)').click();
|
|
|
|
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.test('on_attach_callback is called for actions in target="new"', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var ClientAction = AbstractAction.extend({
|
|
className: 'o_test',
|
|
on_attach_callback: function () {
|
|
assert.step('on_attach_callback');
|
|
assert.ok(actionManager.currentDialogController,
|
|
"the currentDialogController should have been set already");
|
|
},
|
|
});
|
|
core.action_registry.add('test', ClientAction);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction({
|
|
tag: 'test',
|
|
target: 'new',
|
|
type: 'ir.actions.client',
|
|
});
|
|
|
|
assert.strictEqual($('.modal .o_test').length, 1,
|
|
"should have rendered the client action in a dialog");
|
|
assert.verifySteps(['on_attach_callback']);
|
|
|
|
actionManager.destroy();
|
|
delete core.action_registry.map.test;
|
|
});
|
|
|
|
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();
|
|
});
|
|
|
|
QUnit.test('doAction resolved with an action', function (assert) {
|
|
assert.expect(4);
|
|
|
|
this.actions.push({
|
|
id: 21,
|
|
name: 'A Close Action',
|
|
type: 'ir.actions.act_window_close',
|
|
});
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
|
|
actionManager.doAction(21).then(function (action) {
|
|
assert.ok(action, "doAction should be resolved with an action");
|
|
assert.strictEqual(action.id, 21,
|
|
"should be resolved with correct action id");
|
|
assert.strictEqual(action.name, 'A Close Action',
|
|
"should be resolved with correct action name");
|
|
assert.strictEqual(action.type, 'ir.actions.act_window_close',
|
|
"should be resolved with correct action type");
|
|
actionManager.destroy();
|
|
});
|
|
});
|
|
|
|
QUnit.test('properly drop client actions after new action is initiated', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var slowWillStartDef = $.Deferred();
|
|
|
|
var ClientAction = AbstractAction.extend({
|
|
willStart: function () {
|
|
return slowWillStartDef;
|
|
},
|
|
});
|
|
|
|
core.action_registry.add('slowAction', ClientAction);
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction('slowAction');
|
|
actionManager.doAction(4);
|
|
slowWillStartDef.resolve();
|
|
assert.strictEqual(actionManager.$('.o_kanban_view').length, 1,
|
|
'should have loaded a kanban view');
|
|
|
|
actionManager.destroy();
|
|
delete core.action_registry.map.slowAction;
|
|
});
|
|
|
|
|
|
QUnit.test('abstract action does not crash on navigation_moves', function (assert) {
|
|
assert.expect(1);
|
|
var ClientAction = AbstractAction.extend({
|
|
});
|
|
core.action_registry.add('ClientAction', ClientAction);
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction('ClientAction');
|
|
actionManager.trigger_up('navigation_move', {direction:'down'});
|
|
|
|
assert.ok(true); // no error so it's good
|
|
actionManager.destroy();
|
|
delete core.action_registry.ClientAction;
|
|
});
|
|
|
|
QUnit.test('fields in abstract action does not crash on navigation_moves', function (assert) {
|
|
assert.expect(1);
|
|
var self = this;
|
|
|
|
// create a client action with 2 input field
|
|
var inputWidget;
|
|
var secondInputWidget;
|
|
var ClientAction = AbstractAction.extend(StandaloneFieldManagerMixin, {
|
|
init: function () {
|
|
this._super.apply(this, arguments);
|
|
StandaloneFieldManagerMixin.init.call(this);
|
|
},
|
|
start: function () {
|
|
var _self = this;
|
|
|
|
return this.model.makeRecord('partner', [{
|
|
name: 'display_name',
|
|
type: 'char',
|
|
}]).then(function (recordID) {
|
|
var record = _self.model.get(recordID);
|
|
inputWidget = new BasicFields.InputField(_self, 'display_name', record, {mode: 'edit',});
|
|
_self._registerWidget(recordID, 'display_name', inputWidget);
|
|
|
|
secondInputWidget = new BasicFields.InputField(_self, 'display_name', record, {mode: 'edit',});
|
|
secondInputWidget.attrs = {className:"secondField"};
|
|
_self._registerWidget(recordID, 'display_name', secondInputWidget);
|
|
|
|
inputWidget.appendTo(_self.$el);
|
|
secondInputWidget.appendTo(_self.$el);
|
|
});
|
|
}
|
|
});
|
|
core.action_registry.add('ClientAction', ClientAction);
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
});
|
|
actionManager.doAction('ClientAction');
|
|
inputWidget.$el[0].focus();
|
|
var event = $.Event('keydown', {
|
|
which: $.ui.keyCode.TAB,
|
|
keyCode: $.ui.keyCode.TAB,
|
|
});
|
|
$(inputWidget.$el[0]).trigger(event);
|
|
|
|
assert.notOk(event.isDefaultPrevented(),
|
|
"the keyboard event default should not be prevented"); // no crash is good
|
|
actionManager.destroy();
|
|
delete core.action_registry.ClientAction;
|
|
});
|
|
|
|
QUnit.test('web client is not deadlocked when a view crashes', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var readOnFirstRecordDef = $.Deferred();
|
|
|
|
var actionManager = createActionManager({
|
|
actions: this.actions,
|
|
archs: this.archs,
|
|
data: this.data,
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read' && args.args[0][0] === 1) {
|
|
return readOnFirstRecordDef;
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
}
|
|
});
|
|
|
|
actionManager.doAction(3);
|
|
|
|
// open first record in form view. this will crash and will not
|
|
// display a form view
|
|
actionManager.$('.o_list_view .o_data_row:first').click();
|
|
|
|
readOnFirstRecordDef.reject("not working as intended");
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 1,
|
|
"there should still be a list view in dom");
|
|
|
|
// open another record, the read will not crash
|
|
actionManager.$('.o_list_view .o_data_row:eq(2)').click();
|
|
|
|
assert.strictEqual(actionManager.$('.o_list_view').length, 0,
|
|
"there should not be a list view in dom");
|
|
|
|
assert.strictEqual(actionManager.$('.o_form_view').length, 1,
|
|
"there should be a form view in dom");
|
|
|
|
actionManager.destroy();
|
|
});
|
|
});
|
|
|
|
});
|