[IMP] web: add some action_manager tests
This commit is contained in:
committed by
Aaron Bohy
parent
e73b1b1cce
commit
b20a6f60ae
@@ -15,6 +15,7 @@ QUnit.module('ActionManager', {
|
||||
partner: {
|
||||
fields: {
|
||||
foo: {string: "Foo", type: "char"},
|
||||
bar: {string: "Bar", type: "many2one", relation: 'partner'},
|
||||
},
|
||||
records: [
|
||||
{id: 1, display_name: "First record", foo: "yop"},
|
||||
@@ -24,6 +25,16 @@ QUnit.module('ActionManager', {
|
||||
{id: 5, display_name: "Fifth record", foo: "zoup"},
|
||||
],
|
||||
},
|
||||
pony: {
|
||||
fields: {
|
||||
name: {string: 'Name', type: 'char'},
|
||||
},
|
||||
records: [
|
||||
{id: 4, name: 'Twilight Sparkle'},
|
||||
{id: 6, name: 'Applejack'},
|
||||
{id: 9, name: 'Fluttershy'}
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
this.actions = [{
|
||||
@@ -70,17 +81,24 @@ QUnit.module('ActionManager', {
|
||||
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']],
|
||||
}];
|
||||
|
||||
this.archs = {
|
||||
// kanban views
|
||||
'partner,1,kanban': '<kanban><templates><t t-name="kanban-box">' +
|
||||
'<div><field name="foo"/></div>' +
|
||||
'<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>' +
|
||||
@@ -93,14 +111,81 @@ QUnit.module('ActionManager', {
|
||||
'<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>',
|
||||
'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';
|
||||
this.actions[3].view_mode = 'form';
|
||||
|
||||
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);
|
||||
|
||||
@@ -259,6 +344,116 @@ QUnit.module('ActionManager', {
|
||||
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) {
|
||||
@@ -581,6 +776,160 @@ QUnit.module('ActionManager', {
|
||||
|
||||
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);
|
||||
|
||||
@@ -1558,6 +1907,195 @@ QUnit.module('ActionManager', {
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user