This rev. introduces robust helpers to use in the JS tests suite to
interact with DOM and components, and starts using them (almost)
everywhere.
All the helpers are exposed though testUtils.js.
There are 2 kinds of helpers:
1. Assertions
-------------
* assert.containsNone, containsN, containsOnce check that the DOM
(or a specific part of the DOM) contains a `selector`. It
generates a correct error message automatically.
ex: assert.strictEqual(form.$('.o_form_editable'), 1, "msg");
-> assert.containsOnce(form, '.o_form_editable');
* assert.isVisible, isNotVisible check that the DOM has an element
visible or not. They also check that the element is actually in
the DOM (before most tests didn't verify this).
* assert.hasClass, doesNotHaveClass, hasAttrVAlue, check specific
properties of a DOM element, and also validate that it is
applied on a single existing DOM element (before most tests
didn't verify this).
ex: assert.notOk(form.$('button').hasClass('btn-primary'));
-> assert.doesNotHaveClass(form.$('button'), 'btn-primary');
2. Utilities
------------
The goal of the utilities is to centralize the definition of many
standard components and interactions, ensuring that when we
refactor the JS framework, we do not need to change all the tests.
Existing mock utilities (addMockEnvironment, intercept, path,
patchDate, unpatch and fieldsViewGet) are moved to
'testUtils.mock.*'.
Existing DOM utilities are moved to 'testUtils.dom.*'.
New dom utilities are created for opendDatePicker, click,
clickFirst and clickLast. Helper `click` verifies that there is
exactly 1 element visible in the DOM you click on, `clickFirst`
and `clickLast` verify that there are more than one element on the
DOM.
ex: form.$('button').click();
-> testUtils.dom.click(form.$('button'));
New Form utilities: (testUtils.form.*)
clickEdit, clickSave, clickCreate, clickDiscard, all clicks on
the control panel buttons of the form.
`reload` reloads the form data.
New modal, graph, kanban and pivot utils (testUtils.pivot.*,
testUtils.kanban.*, etc.).
New fields utils: (testUtils.fields.*)
* editInput, editSelect: allow to change the value of a field,
using a selector to identify it. They validate that the input
exists and trigger the change event automatically.
* editAndTrigger: allow to modify a field and trigger specific
events after the value change
* many2one (testUtils.fields.many2one.*)
clickOpenDropdown, clickHighlightedItem, clickItem,
searchAndClickItem: use a field name instead of a selector and
do all the complex mechanism to open, filter and highlight
many2one fields.
Joint work with aab, dam, ged, mge, svs and vsc.
1519 lines
56 KiB
JavaScript
1519 lines
56 KiB
JavaScript
odoo.define('web.pivot_tests', function (require) {
|
|
"use strict";
|
|
|
|
var core = require('web.core');
|
|
var PivotView = require('web.PivotView');
|
|
var testUtils = require('web.test_utils');
|
|
|
|
var createActionManager = testUtils.createActionManager;
|
|
var patchDate = testUtils.mock.patchDate;
|
|
|
|
var _t = core._t;
|
|
var createView = testUtils.createView;
|
|
|
|
QUnit.module('Views', {
|
|
beforeEach: function () {
|
|
this.data = {
|
|
partner: {
|
|
fields: {
|
|
foo: {string: "Foo", type: "integer"},
|
|
bar: {string: "bar", type: "boolean"},
|
|
date: {string: "Date", type: "date", store: true, sortable: true},
|
|
product_id: {string: "Product", type: "many2one", relation: 'product', store: true},
|
|
other_product_id: {string: "Other Product", type: "many2one", relation: 'product', store: true},
|
|
non_stored_m2o: {string: "Non Stored M2O", type: "many2one", relation: 'product'},
|
|
customer: {string: "Customer", type: "many2one", relation: 'customer', store: true},
|
|
computed_field: {string: "Computed and not stored", compute:true},
|
|
},
|
|
records: [
|
|
{
|
|
id: 1,
|
|
foo: 12,
|
|
bar: true,
|
|
date: '2016-12-14',
|
|
product_id: 37,
|
|
customer: 1,
|
|
computed_field: 19,
|
|
}, {
|
|
id: 2,
|
|
foo: 1,
|
|
bar: true,
|
|
date: '2016-10-26',
|
|
product_id: 41,
|
|
customer: 2,
|
|
computed_field: 23,
|
|
}, {
|
|
id: 3,
|
|
foo: 17,
|
|
bar: true,
|
|
date: '2016-12-15',
|
|
product_id: 41,
|
|
customer: 2,
|
|
computed_field: 26,
|
|
}, {id: 4,
|
|
foo: 2,
|
|
bar: false,
|
|
date: '2016-04-11',
|
|
product_id: 41,
|
|
customer: 1,
|
|
computed_field: 19,
|
|
},
|
|
]
|
|
},
|
|
product: {
|
|
fields: {
|
|
name: {string: "Product Name", type: "char"}
|
|
},
|
|
records: [{
|
|
id: 37,
|
|
display_name: "xphone",
|
|
}, {
|
|
id: 41,
|
|
display_name: "xpad",
|
|
}]
|
|
},
|
|
customer: {
|
|
fields: {
|
|
name: {string: "Customer Name", type: "char"}
|
|
},
|
|
records: [{
|
|
id: 1,
|
|
display_name: "First",
|
|
}, {
|
|
id: 2,
|
|
display_name: "Second",
|
|
}]
|
|
},
|
|
};
|
|
}
|
|
}, function () {
|
|
QUnit.module('PivotView');
|
|
|
|
QUnit.test('simple pivot rendering', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot string="Partners">' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
mockRPC: function (route, args) {
|
|
assert.strictEqual(args.kwargs.lazy, false,
|
|
"the read_group should be done with the lazy=false option");
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.hasClass(pivot.$el,'o_enable_linking',
|
|
"root node should have classname 'o_enable_linking'");
|
|
assert.strictEqual(pivot.$('td.o_pivot_cell_value:contains(32)').length, 1,
|
|
"should contain a pivot cell with the sum of all records");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot rendering with widget', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot string="Partners">' +
|
|
'<field name="foo" type="measure" widget="float_time"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.strictEqual(pivot.$('td.o_pivot_cell_value:contains(32:00)').length, 1,
|
|
"should contain a pivot cell with the sum of all records");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view without "string" attribute', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
// this is important for export functionality.
|
|
assert.strictEqual(pivot.title, _t("Untitled"), "should have a valid title");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view add computed fields explicitly defined as measure', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="computed_field" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.ok(pivot.measures.computed_field, "measures contains the field 'computed_field'");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('clicking on a cell triggers a do_action', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
intercepts: {
|
|
do_action: function (ev) {
|
|
assert.deepEqual(ev.data.action, {
|
|
context: {someKey: true, userContextKey: true},
|
|
domain: [['product_id', '=', 37]],
|
|
name: 'Partners',
|
|
res_model: 'partner',
|
|
target: 'current',
|
|
type: 'ir.actions.act_window',
|
|
view_mode: 'list',
|
|
view_type: 'list',
|
|
views: [[false, 'list'], [2, 'form']],
|
|
}, "should trigger do_action with the correct args");
|
|
},
|
|
},
|
|
session: {
|
|
user_context: {userContextKey: true},
|
|
},
|
|
viewOptions: {
|
|
action: {
|
|
views: [
|
|
{ viewID: 2, type: 'form' },
|
|
{ viewID: 5, type: 'kanban' },
|
|
{ viewID: false, type: 'list' },
|
|
{ viewID: false, type: 'pivot' },
|
|
],
|
|
},
|
|
context: {someKey: true, search_default_test: 3},
|
|
title: 'Partners',
|
|
}
|
|
});
|
|
|
|
assert.hasClass(pivot.$el,'o_enable_linking',
|
|
"root node should have classname 'o_enable_linking'");
|
|
testUtils.dom.click(pivot.$('.o_pivot_cell_value:contains(12)')); // should trigger a do_action
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view with disable_linking="True"', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot disable_linking="True">' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
intercepts: {
|
|
do_action: function () {
|
|
assert.ok(false, "should not trigger do_action");
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.doesNotHaveClass(pivot.$el, 'o_enable_linking',
|
|
"root node should not have classname 'o_enable_linking'");
|
|
assert.containsOnce(pivot, '.o_pivot_cell_value',
|
|
"should have one cell");
|
|
testUtils.dom.click(pivot.$('.o_pivot_cell_value')); // should not trigger a do_action
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view grouped by date field', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var data = this.data;
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
mockRPC: function (route, params) {
|
|
var wrong_fields = _.filter(params.kwargs.fields, function (field) {
|
|
return !(field in data.partner.fields);
|
|
});
|
|
assert.ok(!wrong_fields.length, 'fields given to read_group should exist on the model');
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('without measures, pivot view uses __count by default', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot></pivot>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read_group') {
|
|
assert.deepEqual(args.kwargs.fields, ['__count'],
|
|
"should make a read_group with no valid fields");
|
|
}
|
|
return this._super(route, args);
|
|
}
|
|
});
|
|
|
|
var $countMeasure = pivot.$buttons.find('.dropdown-item[data-field=__count]:first');
|
|
assert.hasClass($countMeasure,'selected', "The count measure should be activated");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view can be reloaded', function (assert) {
|
|
assert.expect(4);
|
|
var readGroupCount = 0;
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot></pivot>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read_group') {
|
|
readGroupCount++;
|
|
}
|
|
return this._super(route, args);
|
|
}
|
|
});
|
|
|
|
assert.strictEqual(pivot.$('td.o_pivot_cell_value:contains(4)').length, 1,
|
|
"should contain a pivot cell with the number of all records");
|
|
assert.strictEqual(readGroupCount, 1, "should have done 1 rpc");
|
|
|
|
testUtils.pivot.reload(pivot, {domain: [['foo', '>', 10]]});
|
|
assert.strictEqual(pivot.$('td.o_pivot_cell_value:contains(2)').length, 1,
|
|
"should contain a pivot cell with the number of remaining records");
|
|
assert.strictEqual(readGroupCount, 2, "should have done 2 rpcs");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view grouped by many2one field', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.containsOnce(pivot, '.o_pivot_header_cell_opened',
|
|
"should have one opened header");
|
|
assert.strictEqual(pivot.$('.o_pivot_header_cell_closed:contains(xphone)').length, 1,
|
|
"should display one header with 'xphone'");
|
|
assert.strictEqual(pivot.$('.o_pivot_header_cell_closed:contains(xpad)').length, 1,
|
|
"should display one header with 'xpad'");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('basic folding/unfolding', function (assert) {
|
|
assert.expect(7);
|
|
|
|
var rpcCount = 0;
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
mockRPC: function () {
|
|
rpcCount++;
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.containsN(pivot, 'tbody tr', 3,
|
|
"should have 3 rows: 1 for the opened header, and 2 for data");
|
|
|
|
// click on the opened header to close it
|
|
testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened'));
|
|
|
|
assert.containsOnce(pivot, 'tbody tr', "should have 1 row");
|
|
|
|
// click on closed header to open dropdown
|
|
testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
|
|
|
|
assert.containsOnce(pivot, '.o_pivot_field_menu .dropdown-item[data-field="date"]:first',
|
|
"should have the date field as proposition");
|
|
assert.containsOnce(pivot, '.o_field_selection .dropdown-item[data-field="product_id"]:first',
|
|
"should have the product_id field as proposition");
|
|
assert.containsNone(pivot, '.o_field_selection .dropdown-item[data-field="non_stored_m2o"]:first',
|
|
"should not have the non_stored_m2o field as proposition");
|
|
|
|
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"]:first'));
|
|
|
|
assert.containsN(pivot, 'tbody tr', 4,
|
|
"should have 4 rows: one for header, 3 for data");
|
|
assert.strictEqual(rpcCount, 3,
|
|
"should have done 3 rpcs (initial load) + open header with different groupbys");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('more folding/unfolding', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
// open dropdown to zoom into first row
|
|
testUtils.dom.clickFirst(pivot.$('tbody .o_pivot_header_cell_closed'));
|
|
// click on date by day
|
|
pivot.$('.dropdown-menu.show .o_inline_dropdown .dropdown-menu').toggle(); // unfold inline dropdown
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="day"]'));
|
|
|
|
// open dropdown to zoom into second row
|
|
testUtils.dom.clickLast(pivot.$('tbody td.o_pivot_header_cell_closed'));
|
|
|
|
assert.containsN(pivot, 'tbody tr', 7,
|
|
"should have 7 rows (1 for total, 1 for xphone, 1 for xpad, 4 for data)");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view can be flipped', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var rpcCount = 0;
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'</pivot>',
|
|
mockRPC: function () {
|
|
rpcCount++;
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.containsN(pivot, 'tbody tr', 3,
|
|
"should have 3 rows: 1 for the open header, and 2 for data");
|
|
|
|
rpcCount = 0;
|
|
testUtils.dom.click(pivot.$buttons.find('.o_pivot_flip_button'));
|
|
|
|
assert.strictEqual(rpcCount, 0, "should not have done any rpc");
|
|
assert.containsOnce(pivot, 'tbody tr',
|
|
"should have 1 rows: 1 for the main header");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('can toggle extra measure', function (assert) {
|
|
assert.expect(8);
|
|
|
|
var rpcCount = 0;
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
mockRPC: function () {
|
|
rpcCount++;
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 3,
|
|
"should have 3 cells: 1 for the open header, and 2 for data");
|
|
assert.doesNotHaveClass(pivot.$buttons.find('.dropdown-item[data-field=__count]:first'), 'selected',
|
|
"the __count measure should not be selected");
|
|
|
|
rpcCount = 0;
|
|
testUtils.pivot.toggleMeasuresDropdown(pivot);
|
|
testUtils.pivot.clickMeasure(pivot, '__count');
|
|
|
|
assert.hasClass(pivot.$buttons.find('.dropdown-item[data-field=__count]:first'),'selected',
|
|
"the __count measure should be selected");
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 6,
|
|
"should have 6 cells: 2 for the open header, and 4 for data");
|
|
assert.strictEqual(rpcCount, 2,
|
|
"should have done 2 rpcs to reload data");
|
|
|
|
testUtils.pivot.clickMeasure(pivot, '__count');
|
|
|
|
assert.doesNotHaveClass(pivot.$buttons.find('.dropdown-item[data-field=__count]:first'), 'selected',
|
|
"the __count measure should not be selected");
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 3,
|
|
"should have 3 cells: 1 for the open header, and 2 for data");
|
|
assert.strictEqual(rpcCount, 2,
|
|
"should not have done any extra rpcs");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('no content helper when no active measure', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot string="Partners">' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.containsNone(pivot, '.o_view_nocontent',
|
|
"should not have a no_content_helper");
|
|
assert.containsOnce(pivot, 'table',
|
|
"should have a table in DOM");
|
|
|
|
testUtils.pivot.toggleMeasuresDropdown(pivot);
|
|
testUtils.pivot.clickMeasure(pivot, '__count');
|
|
|
|
assert.containsOnce(pivot, '.o_view_nocontent',
|
|
"should have a no_content_helper");
|
|
assert.containsNone(pivot, 'table',
|
|
"should not have a table in DOM");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('no content helper when no data', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot string="Partners">' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.containsNone(pivot, '.o_view_nocontent',
|
|
"should not have a no_content_helper");
|
|
assert.containsOnce(pivot, 'table',
|
|
"should have a table in DOM");
|
|
|
|
testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
|
|
|
|
assert.containsOnce(pivot, '.o_view_nocontent',
|
|
"should have a no_content_helper");
|
|
assert.containsNone(pivot, 'table',
|
|
"should not have a table in DOM");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('no content helper when no data, part 2', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.records = [];
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot string="Partners"></pivot>',
|
|
});
|
|
|
|
assert.containsOnce(pivot, '.o_view_nocontent',
|
|
"should have a no_content_helper");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('no content helper when no data, part 3', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot string="Partners"></pivot>',
|
|
viewOptions: {
|
|
domain: [['foo', '=', 12345]]
|
|
},
|
|
});
|
|
|
|
assert.containsOnce(pivot, '.o_view_nocontent',
|
|
"should have a no_content_helper");
|
|
testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
|
|
assert.containsOnce(pivot, '.o_view_nocontent',
|
|
"should still have a no_content_helper");
|
|
testUtils.pivot.reload(pivot, {domain: []});
|
|
assert.containsNone(pivot, '.o_view_nocontent',
|
|
"should not have a no_content_helper");
|
|
|
|
// tries to open a field selection menu, to make sure it was not
|
|
// removed from the dom.
|
|
testUtils.dom.clickFirst(pivot.$('.o_pivot_header_cell_closed'));
|
|
assert.containsOnce(pivot, '.o_pivot_field_menu',
|
|
"the field selector menu exists");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('tries to restore previous state after domain change', function (assert) {
|
|
assert.expect(5);
|
|
|
|
var rpcCount = 0;
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
mockRPC: function () {
|
|
rpcCount++;
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 3,
|
|
"should have 3 cells: 1 for the open header, and 2 for data");
|
|
assert.strictEqual(pivot.$('.o_pivot_measure_row:contains(Foo)').length, 1,
|
|
"should have 1 row for measure Foo");
|
|
|
|
testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
|
|
|
|
rpcCount = 0;
|
|
testUtils.pivot.reload(pivot, {domain: []});
|
|
|
|
assert.equal(rpcCount, 2, "should have reloaded data");
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 3,
|
|
"should still have 3 cells: 1 for the open header, and 2 for data");
|
|
assert.strictEqual(pivot.$('.o_pivot_measure_row:contains(Foo)').length, 1,
|
|
"should still have 1 row for measure Foo");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('can be grouped with the update function', function (assert) {
|
|
assert.expect(4);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.containsOnce(pivot, '.o_pivot_cell_value',
|
|
"should have only 1 cell");
|
|
assert.containsOnce(pivot, 'tbody tr',
|
|
"should have 1 rows");
|
|
|
|
testUtils.pivot.reload(pivot, {groupBy: ['product_id']});
|
|
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 3,
|
|
"should have 3 cells");
|
|
assert.containsN(pivot, 'tbody tr', 3,
|
|
"should have 3 rows");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('can sort data in a column by clicking on header', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.strictEqual($('td.o_pivot_cell_value').text(), "321220",
|
|
"should have proper values in cells (total, result 1, result 2");
|
|
|
|
testUtils.dom.click(pivot.$('th.o_pivot_measure_row'));
|
|
|
|
assert.strictEqual($('td.o_pivot_cell_value').text(), "322012",
|
|
"should have proper values in cells (total, result 2, result 1");
|
|
|
|
testUtils.dom.click(pivot.$('th.o_pivot_measure_row'));
|
|
|
|
assert.strictEqual($('td.o_pivot_cell_value').text(), "321220",
|
|
"should have proper values in cells (total, result 1, result 2");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('can expand all rows', function (assert) {
|
|
assert.expect(7);
|
|
|
|
var nbReadGroups = 0;
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'</pivot>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read_group') {
|
|
nbReadGroups++;
|
|
}
|
|
return this._super.apply(this, arguments);
|
|
},
|
|
});
|
|
|
|
assert.strictEqual(nbReadGroups, 2, "should have done 2 read_group RPCS");
|
|
assert.strictEqual(pivot.$('td.o_pivot_cell_value').text(), "321220",
|
|
"should have proper values in cells (total, result 1, result 2)");
|
|
|
|
// expand on date:days, product
|
|
nbReadGroups = 0;
|
|
testUtils.pivot.reload(pivot, {groupBy: ['date:days', 'product_id']});
|
|
|
|
assert.strictEqual(nbReadGroups, 3, "should have done 3 read_group RPCS");
|
|
assert.containsN(pivot, 'tbody tr', 8,
|
|
"should have 7 rows (total + 3 for December and 2 for October and April)");
|
|
|
|
// collapse the last two rows
|
|
testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
|
|
testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
|
|
|
|
assert.containsN(pivot, 'tbody tr', 6,
|
|
"should have 6 rows now");
|
|
|
|
// expand all
|
|
nbReadGroups = 0;
|
|
testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button'));
|
|
|
|
assert.strictEqual(nbReadGroups, 3, "should have done 3 read_group RPCS");
|
|
assert.containsN(pivot, 'tbody tr', 8,
|
|
"should have 8 rows again");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('expand all with a delay', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var def;
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'</pivot>',
|
|
mockRPC: function (route, args) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (args.method === 'read_group') {
|
|
return $.when(def).then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
// expand on date:days, product
|
|
testUtils.pivot.reload(pivot, {groupBy: ['date:days', 'product_id']});
|
|
|
|
assert.containsN(pivot, 'tbody tr', 8,
|
|
"should have 7 rows (total + 3 for December and 2 for October and April)");
|
|
|
|
// collapse the last two rows
|
|
testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
|
|
testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
|
|
|
|
assert.containsN(pivot, 'tbody tr', 6,
|
|
"should have 6 rows now");
|
|
|
|
// expand all
|
|
def = $.Deferred();
|
|
testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button'));
|
|
def.resolve();
|
|
|
|
assert.containsN(pivot, 'tbody tr', 8,
|
|
"should have 8 rows again");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('can download a file', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
session: {
|
|
get_file: function (args) {
|
|
assert.strictEqual(args.url, '/web/pivot/export_xls',
|
|
"should call get_file with correct parameters");
|
|
args.complete();
|
|
},
|
|
},
|
|
});
|
|
|
|
testUtils.dom.click(pivot.$buttons.find('.o_pivot_download'));
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('download button is disabled when there is no data', function (assert) {
|
|
assert.expect(1);
|
|
|
|
this.data.partner.records = [];
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.hasAttrValue(pivot.$buttons.find('.o_pivot_download'), 'disabled', 'disabled',
|
|
"download button should be disabled");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('getContext correctly returns measures and groupbys', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="date" interval="day" type="col"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.deepEqual(pivot.getContext(), {
|
|
pivot_column_groupby: ['date:day'],
|
|
pivot_measures: ['foo'],
|
|
pivot_row_groupby: [],
|
|
}, "context should be correct");
|
|
|
|
// expand header on field customer
|
|
testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed:nth(1)'));
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first'));
|
|
assert.deepEqual(pivot.getContext(), {
|
|
pivot_column_groupby: ['date:day', 'customer'],
|
|
pivot_measures: ['foo'],
|
|
pivot_row_groupby: [],
|
|
}, "context should be correct");
|
|
|
|
// expand row on field product_id
|
|
testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
|
|
assert.deepEqual(pivot.getContext(), {
|
|
pivot_column_groupby: ['date:day', 'customer'],
|
|
pivot_measures: ['foo'],
|
|
pivot_row_groupby: ['product_id'],
|
|
}, "context should be correct");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('correctly uses pivot_ keys from the context', function (assert) {
|
|
assert.expect(7);
|
|
|
|
this.data.partner.fields.amount = {string: "Amount", type: "float"};
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="date" interval="day" type="col"/>' +
|
|
'<field name="amount" type="measure"/>' +
|
|
'</pivot>',
|
|
viewOptions: {
|
|
context: {
|
|
pivot_measures: ['foo'],
|
|
pivot_column_groupby: ['customer'],
|
|
pivot_row_groupby: ['product_id'],
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.containsOnce(pivot, 'thead .o_pivot_header_cell_opened',
|
|
"column: should have one opened header");
|
|
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(First)').length, 1,
|
|
"column: should display one closed header with 'First'");
|
|
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(Second)').length, 1,
|
|
"column: should display one closed header with 'Second'");
|
|
|
|
assert.containsOnce(pivot, 'tbody .o_pivot_header_cell_opened',
|
|
"row: should have one opened header");
|
|
assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xphone)').length, 1,
|
|
"row: should display one closed header with 'xphone'");
|
|
assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xpad)').length, 1,
|
|
"row: should display one closed header with 'xpad'");
|
|
|
|
assert.strictEqual(pivot.$('tbody tr:first td:nth(3)').text(), '32',
|
|
"selected measure should be foo, with total 32");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('correctly uses pivot_ keys from the context (at reload)', function (assert) {
|
|
assert.expect(8);
|
|
|
|
this.data.partner.fields.amount = {string: "Amount", type: "float"};
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="date" interval="day" type="col"/>' +
|
|
'<field name="amount" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.strictEqual(pivot.$('tbody tr:first td.o_pivot_cell_value:last').text(), '0.00',
|
|
"the active measure should be amount");
|
|
|
|
var reloadParams = {
|
|
context: {
|
|
pivot_measures: ['foo'],
|
|
pivot_column_groupby: ['customer'],
|
|
pivot_row_groupby: ['product_id'],
|
|
},
|
|
};
|
|
testUtils.pivot.reload(pivot, reloadParams);
|
|
|
|
assert.containsOnce(pivot, 'thead .o_pivot_header_cell_opened',
|
|
"column: should have one opened header");
|
|
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(First)').length, 1,
|
|
"column: should display one closed header with 'First'");
|
|
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(Second)').length, 1,
|
|
"column: should display one closed header with 'Second'");
|
|
|
|
assert.containsOnce(pivot, 'tbody .o_pivot_header_cell_opened',
|
|
"row: should have one opened header");
|
|
assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xphone)').length, 1,
|
|
"row: should display one closed header with 'xphone'");
|
|
assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xpad)').length, 1,
|
|
"row: should display one closed header with 'xpad'");
|
|
|
|
assert.strictEqual(pivot.$('tbody tr:first td:nth(3)').text(), '32',
|
|
"selected measure should be foo, with total 32");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('correctly use group_by key from the context', function (assert) {
|
|
assert.expect(7);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: 'partner',
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="customer" type="col" />' +
|
|
'<field name="foo" type="measure" />' +
|
|
'</pivot>',
|
|
groupBy: ['product_id'],
|
|
});
|
|
|
|
assert.containsOnce(pivot, 'thead .o_pivot_header_cell_opened',
|
|
'column: should have one opened header');
|
|
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(First)').length, 1,
|
|
'column: should display one closed header with "First"');
|
|
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed:contains(Second)').length, 1,
|
|
'column: should display one closed header with "Second"');
|
|
|
|
assert.containsOnce(pivot, 'tbody .o_pivot_header_cell_opened',
|
|
'row: should have one opened header');
|
|
assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xphone)').length, 1,
|
|
'row: should display one closed header with "xphone"');
|
|
assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed:contains(xpad)').length, 1,
|
|
'row: should display one closed header with "xpad"');
|
|
|
|
assert.strictEqual(pivot.$('tbody tr:first td:nth(3)').text(), '32',
|
|
'selected measure should be foo, with total 32');
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot still handles __count__ measure', function (assert) {
|
|
// for retro-compatibility reasons, the pivot view still handles
|
|
// '__count__' measure.
|
|
assert.expect(2);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot></pivot>',
|
|
mockRPC: function (route, args) {
|
|
if (args.method === 'read_group') {
|
|
assert.deepEqual(args.kwargs.fields, ['__count'],
|
|
"should make a read_group with field __count");
|
|
}
|
|
return this._super(route, args);
|
|
},
|
|
viewOptions: {
|
|
context: {
|
|
pivot_measures: ['__count__'],
|
|
},
|
|
},
|
|
});
|
|
|
|
var $countMeasure = pivot.$buttons.find('.dropdown-item[data-field=__count]:first');
|
|
assert.hasClass($countMeasure,'selected', "The count measure should be activated");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('not use a many2one as a measure by default', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id"/>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'</pivot>',
|
|
});
|
|
assert.notOk(pivot.measures.product_id,
|
|
"should not have product_id as measure");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('use a many2one as a measure with specified additional measure', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id"/>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'</pivot>',
|
|
viewOptions: {
|
|
additionalMeasures: ['product_id'],
|
|
},
|
|
});
|
|
assert.ok(pivot.measures.product_id,
|
|
"should have product_id as measure");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view with many2one field as a measure', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="measure"/>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.strictEqual(pivot.$('table tbody tr').text().trim(), "Total2112",
|
|
"should display product_id count as measure");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('m2o as measure, drilling down into data', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
|
|
// click on date by month
|
|
pivot.$('.dropdown-menu.show .o_inline_dropdown .dropdown-menu').toggle(); // unfold inline dropdown
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="month"]'));
|
|
|
|
assert.strictEqual(pivot.$('.o_pivot_cell_value').text(), '2211',
|
|
'should have loaded the proper data');
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view with same many2one field as a measure and grouped by', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="row"/>' +
|
|
'</pivot>',
|
|
viewOptions: {
|
|
additionalMeasures: ['product_id'],
|
|
},
|
|
});
|
|
|
|
testUtils.pivot.toggleMeasuresDropdown(pivot);
|
|
testUtils.pivot.clickMeasure(pivot, 'product_id');
|
|
assert.strictEqual(pivot.$('.o_pivot_cell_value').text(), '421131',
|
|
'should have loaded the proper data');
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view with same many2one field as a measure and grouped by (and drill down)', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="product_id" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
|
|
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
|
|
|
|
assert.strictEqual(pivot.$('.o_pivot_cell_value').text(), '211',
|
|
'should have loaded the proper data');
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('Row and column groupbys plus a domain', function (assert) {
|
|
assert.expect(3);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
// Set a column groupby
|
|
testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed'));
|
|
testUtils.dom.click(pivot.$('.o_field_selection .dropdown-item[data-field=customer]:first'));
|
|
|
|
// Set a Row groupby
|
|
testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
|
|
testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field=product_id]:first'));
|
|
|
|
// Set a domain
|
|
testUtils.pivot.reload(pivot, {domain: [['product_id', '=', 41]]});
|
|
|
|
var expectedContext = {pivot_column_groupby: ['customer'],
|
|
pivot_measures: ['foo'],
|
|
pivot_row_groupby: ['product_id']};
|
|
|
|
// Mock 'save as favorite'
|
|
assert.deepEqual(pivot.getContext(), expectedContext,
|
|
'The pivot view should have the right context');
|
|
|
|
var $xpadHeader = pivot.$('tbody .o_pivot_header_cell_closed[data-original-title=Product]');
|
|
assert.equal($xpadHeader.length, 1,
|
|
'There should be only one product line because of the domain');
|
|
|
|
assert.equal($xpadHeader.text(), 'xpad',
|
|
'The product should be the right one');
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('parallel data loading should discard all but the last one', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var def;
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
mockRPC: function (route, args) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (args.method === 'read_group') {
|
|
return $.when(def).then(_.constant(result));
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
def = $.Deferred();
|
|
testUtils.pivot.reload(pivot, {groupBy: ['product_id']});
|
|
testUtils.pivot.reload(pivot, {groupBy: ['product_id', 'customer']});
|
|
def.resolve();
|
|
|
|
assert.containsN(pivot, '.o_pivot_cell_value', 6,
|
|
"should have 6 cells");
|
|
assert.containsN(pivot, 'tbody tr', 6,
|
|
"should have 6 rows");
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot measures should be alphabetically sorted', function (assert) {
|
|
assert.expect(2);
|
|
|
|
var data = this.data;
|
|
// It's important to compare capitalized and lowercased words
|
|
// to be sure the sorting is effective with both of them
|
|
data.partner.fields.bouh = {string: "bouh", type: "integer"};
|
|
data.partner.fields.modd = {string: "modd", type: "integer"};
|
|
data.partner.fields.zip = {string: "Zip", type: "integer"};
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: data,
|
|
arch: '<pivot>' +
|
|
'<field name="zip" type="measure"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'<field name="bouh" type="measure"/>' +
|
|
'<field name="modd" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
assert.strictEqual(pivot.$buttons.find('.o_pivot_measures_list .dropdown-item:first').data('field'), 'bouh',
|
|
"Bouh should be the first measure");
|
|
assert.strictEqual(pivot.$buttons.find('.o_pivot_measures_list .dropdown-item:last').data('field'), '__count',
|
|
"Count should be the last measure");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('pivot view should use default order for auto sorting', function (assert) {
|
|
assert.expect(1);
|
|
|
|
var pivot = createView({
|
|
View: PivotView,
|
|
model: "partner",
|
|
data: this.data,
|
|
arch: '<pivot default_order="foo asc">' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
});
|
|
|
|
assert.hasClass(pivot.$('thead tr:last th:last'),'o_pivot_measure_row_sorted_asc',
|
|
"Last thead should be sorted in ascending order");
|
|
|
|
pivot.destroy();
|
|
});
|
|
|
|
QUnit.test('rendering of pivot view with comparison', function (assert) {
|
|
assert.expect(91);
|
|
|
|
this.data.partner.records[0].date = '2016-12-15';
|
|
this.data.partner.records[1].date = '2016-12-17';
|
|
this.data.partner.records[2].date = '2016-11-22';
|
|
this.data.partner.records[3].date = '2016-11-03';
|
|
|
|
this.data.partner.fields.company_type = {string: "Company Type", type: "selection", selection: [["company", "Company"], ["individual", "Individual"]], searchable: true, store: true, sortable: true};
|
|
|
|
this.data.partner.records[0].company_type = 'company';
|
|
this.data.partner.records[1].company_type = 'individual';
|
|
this.data.partner.records[2].company_type = 'company';
|
|
this.data.partner.records[3].company_type = 'individual';
|
|
|
|
|
|
var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0);
|
|
|
|
var results, i, length;
|
|
|
|
|
|
function checkCellValues (results) {
|
|
length = results.length;
|
|
for (i = 0; i < length; i++) {
|
|
assert.strictEqual($('.o_pivot .o_pivot_cell_value div').eq(i).text().trim(), results.shift());
|
|
}
|
|
}
|
|
|
|
// create an action manager to test the interactions with the search view
|
|
var actionManager = createActionManager({
|
|
data: this.data,
|
|
archs: {
|
|
'partner,false,pivot': '<pivot>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
'partner,false,search': '<search></search>',
|
|
},
|
|
});
|
|
|
|
actionManager.doAction({
|
|
res_model: 'partner',
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'pivot']],
|
|
flags: {
|
|
pivot: {
|
|
additionalMeasures: ['product_id'],
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
// with no data
|
|
|
|
testUtils.dom.click($('.o_time_range_menu_button'));
|
|
testUtils.dom.click($('.o_time_range_menu .o_comparison_checkbox'));
|
|
$('.o_time_range_selector').val('today');
|
|
testUtils.dom.click($('.o_time_range_menu .o_apply_range'));
|
|
|
|
assert.strictEqual($('.o_pivot p.o_view_nocontent_empty_folder').length, 1);
|
|
|
|
// with data, no row groupby
|
|
testUtils.dom.click($('.o_time_range_menu_button'));
|
|
$('.o_time_range_selector').val('this_month');
|
|
testUtils.dom.click($('.o_time_range_menu .o_apply_range'));
|
|
results = [
|
|
"13", "0", "100%", "0", "19", "-100%", "13", "19", "-31.58%"
|
|
];
|
|
checkCellValues(results);
|
|
|
|
// with data, with row groupby
|
|
|
|
testUtils.dom.click($('.o_pivot .o_pivot_header_cell_closed').eq(2));
|
|
testUtils.dom.click($('.o_pivot .o_field_selection a[data-field="product_id"]'));
|
|
results = [
|
|
"13", "0", "100%", "0", "19", "-100%", "13", "19", "-31.58%" ,
|
|
"12", "0", "100%", "12", "0" , "100%" ,
|
|
"1" , "0", "100%", "0", "19", "-100%", "1" , "19" , "-94.74%"
|
|
];
|
|
checkCellValues(results);
|
|
|
|
testUtils.pivot.toggleMeasuresDropdown(actionManager.getCurrentController().widget);
|
|
testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="foo"]'));
|
|
testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="product_id"]'));
|
|
results = [
|
|
"2", "0", "100%", "0", "1", "-100%", "2", "1", "100%" ,
|
|
"1", "0", "100%", "1", "0" , "100%" ,
|
|
"1" , "0", "100%", "0", "1", "-100%", "1" , "1" , "100%"
|
|
];
|
|
checkCellValues(results);
|
|
|
|
testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="__count"]'));
|
|
testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="product_id"]'));
|
|
results = [
|
|
"2", "0", "100%", "0", "2", "-100%", "2", "2", "0%" ,
|
|
"1", "0", "100%", "1", "0" , "100%" ,
|
|
"1" , "0", "100%", "0", "2", "-100%", "1" , "2" , "-50%"
|
|
];
|
|
checkCellValues(results);
|
|
|
|
testUtils.dom.clickFirst($('.o_pivot .o_pivot_header_cell_opened'));
|
|
results = [
|
|
"2", "2", "0%" ,
|
|
"1", "0", "100%" ,
|
|
"1", "2", "-50%"
|
|
];
|
|
checkCellValues(results);
|
|
|
|
unpatchDate();
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('export data in excel with comparison', function (assert) {
|
|
assert.expect(10);
|
|
|
|
this.data.partner.records[0].date = '2016-12-15';
|
|
this.data.partner.records[1].date = '2016-12-17';
|
|
this.data.partner.records[2].date = '2016-11-22';
|
|
this.data.partner.records[3].date = '2016-11-03';
|
|
|
|
var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0);
|
|
|
|
// create an action manager to test the interactions with the search view
|
|
var actionManager = createActionManager({
|
|
data: this.data,
|
|
archs: {
|
|
'partner,false,pivot': '<pivot>' +
|
|
'<field name="date" interval="month" type="col"/>' +
|
|
'<field name="foo" type="measure"/>' +
|
|
'</pivot>',
|
|
'partner,false,search': '<search></search>',
|
|
},
|
|
session: {
|
|
get_file: function (args) {
|
|
var data = JSON.parse(args.data.data);
|
|
_.each(data.headers, function (l) {
|
|
assert.step(l.map(function (o) {return o.title;}));
|
|
});
|
|
assert.step(data.measure_row.map(function (o) {return o.measure;}));
|
|
assert.step(data.nbr_measures);
|
|
assert.step(data.rows.map(function (o) {return o.values.length;}));
|
|
assert.strictEqual(args.url, '/web/pivot/export_xls',
|
|
"should call get_file with correct parameters");
|
|
args.complete();
|
|
},
|
|
},
|
|
});
|
|
|
|
actionManager.doAction({
|
|
res_model: 'partner',
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'pivot']],
|
|
});
|
|
|
|
// open time range menu
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
|
|
// select 'Today' as range
|
|
$('.o_control_panel .o_time_range_selector').val('today');
|
|
// check checkbox 'Compare To'
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
|
|
// Click on 'Apply' button
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
|
|
|
|
// the time range menu configuration is by now: Date, Today, checkbox checked, Previous Period
|
|
// With the data above, the time ranges contain no record.
|
|
assert.strictEqual($('.o_pivot p.o_view_nocontent_empty_folder').length, 1, "there should be no data");
|
|
// export data should be impossible since the pivot buttons
|
|
// are deactivated (exception: the 'Measures' button).
|
|
assert.ok($('.o_control_panel button.o_pivot_download').prop('disabled'));
|
|
|
|
// open time range menu
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
|
|
// select 'This Month' as date range
|
|
$('.o_control_panel .o_time_range_selector').val('this_month');
|
|
|
|
// Click on 'Apply' button
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
|
|
// the time range menu configuration is by now: Date, This Month, checkbox checked, Previous Period
|
|
// With the data above, the time ranges contain some records.
|
|
// export data. Should execute 'get_file'
|
|
testUtils.dom.click($('.o_control_panel button.o_pivot_download'));
|
|
|
|
assert.verifySteps([
|
|
// Headers
|
|
["Total", ""],
|
|
["December 2016" , "November 2016"],
|
|
["Foo", "Foo", "Foo"],
|
|
[
|
|
"This Month", "Previous Period", "Variation",
|
|
"This Month", "Previous Period", "Variation",
|
|
"This Month", "Previous Period", "Variation"
|
|
],
|
|
// number of 'measures'
|
|
3,
|
|
// rows values length
|
|
[9]
|
|
]);
|
|
|
|
unpatchDate();
|
|
actionManager.destroy();
|
|
});
|
|
|
|
QUnit.test('rendering of pivot view with comparison and count measure', function (assert) {
|
|
assert.expect(10);
|
|
|
|
var mockMock = false;
|
|
var nbReadGroup = 0;
|
|
|
|
this.data.partner.records[0].date = '2016-12-15';
|
|
this.data.partner.records[1].date = '2016-12-17';
|
|
this.data.partner.records[2].date = '2016-12-22';
|
|
this.data.partner.records[3].date = '2016-12-03';
|
|
|
|
var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0);
|
|
|
|
// create an action manager to test the interactions with the search view
|
|
var actionManager = createActionManager({
|
|
data: this.data,
|
|
archs: {
|
|
'partner,false,pivot': '<pivot>' +
|
|
'<field name="customer" type="row"/>' +
|
|
'</pivot>',
|
|
'partner,false,search': '<search></search>',
|
|
},
|
|
mockRPC: function (route, args) {
|
|
var result = this._super.apply(this, arguments);
|
|
if (args.method === 'read_group' && mockMock) {
|
|
nbReadGroup++;
|
|
if (nbReadGroup === 4) {
|
|
// this modification is necessary because mockReadGroup does not
|
|
// properly reflect the server response when there is no record
|
|
// and a groupby list of length at least one.
|
|
return $.when([{}]);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
});
|
|
|
|
actionManager.doAction({
|
|
res_model: 'partner',
|
|
type: 'ir.actions.act_window',
|
|
views: [[false, 'pivot']],
|
|
});
|
|
|
|
mockMock = true;
|
|
|
|
// activate 'This Month' and 'Previous Period' in time range menu
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
|
|
$('.o_control_panel .o_time_range_selector').val('this_month');
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
|
|
testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
|
|
|
|
var results = [
|
|
"4", "0", "100%",
|
|
"2", "0", "100%",
|
|
"2", "0", "100%"
|
|
];
|
|
|
|
for (var i = 0; i < 9; i++) {
|
|
assert.strictEqual($('.o_pivot .o_pivot_cell_value div').eq(i).text().trim(), results.shift());
|
|
}
|
|
assert.strictEqual($('.o_pivot_header_cell_closed').length, 3, "there should be exactly three closed header ('Total','First', 'Second')");
|
|
|
|
unpatchDate();
|
|
actionManager.destroy();
|
|
});
|
|
});
|
|
});
|