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', async function (assert) { assert.expect(3); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); 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 rendering with string attribute on field', async function (assert) { assert.expect(1); this.data.partner.fields.foo = {string: "Foo", type: "integer", store: true}; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); assert.strictEqual(pivot.$('.o_pivot_measure_row').text(), "BAR", "the displayed name should be the one set in the string attribute"); pivot.destroy(); }); QUnit.test('pivot rendering with string attribute on non stored field', async function (assert) { assert.expect(1); this.data.partner.fields.fubar = {string: "Fubar", type: "integer", store:false}; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); assert.containsOnce(pivot, '.o_pivot', 'Non stored fields can have a string attribute'); pivot.destroy(); }); QUnit.test('pivot rendering with invisible attribute on field', async function (assert) { assert.expect(2); // when invisible, a field should neither be an active measure, // nor be a selectable measure. _.extend(this.data.partner.fields, { foo: {string: "Foo", type: "integer", store: true}, foo2: {string: "Foo2", type: "integer", store: true} }); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); // there should be only one displayed measure as the other one is invisible assert.containsOnce(pivot, '.o_pivot_measure_row'); // there should be only one measure besides count, as the other one is invisible assert.containsN(pivot, '.o_cp_left .dropdown-item', 2); pivot.destroy(); }); QUnit.test('pivot view without "string" attribute', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); // 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); assert.ok(pivot.measures.computed_field, "measures contains the field 'computed_field'"); pivot.destroy(); }); QUnit.test('clicking on a cell triggers a do_action', async function (assert) { assert.expect(2); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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'"); await 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"', async function (assert) { assert.expect(2); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', 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"); await testUtils.dom.click(pivot.$('.o_pivot_cell_value')); // should not trigger a do_action pivot.destroy(); }); QUnit.test('pivot view grouped by date field', async function (assert) { assert.expect(2); var data = this.data; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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', async function (assert) { assert.expect(2); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', 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', async function (assert) { assert.expect(4); var readGroupCount = 0; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', 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"); await 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', async function (assert) { assert.expect(3); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); 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', async function (assert) { assert.expect(7); var rpcCount = 0; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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 await 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 await 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"); await 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); // open dropdown to zoom into first row await 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 await testUtils.nextTick(); await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="day"]')); // open dropdown to zoom into second row await 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', async function (assert) { assert.expect(3); var rpcCount = 0; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', 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; await 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', async function (assert) { assert.expect(8); var rpcCount = 0; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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; await testUtils.pivot.toggleMeasuresDropdown(pivot); await 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"); await 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', async function (assert) { assert.expect(4); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '', }); assert.containsNone(pivot, '.o_view_nocontent', "should not have a no_content_helper"); assert.containsOnce(pivot, 'table', "should have a table in DOM"); await testUtils.pivot.toggleMeasuresDropdown(pivot); await 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', async function (assert) { assert.expect(4); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '', }); assert.containsNone(pivot, '.o_view_nocontent', "should not have a no_content_helper"); assert.containsOnce(pivot, 'table', "should have a table in DOM"); await 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', async function (assert) { assert.expect(1); this.data.partner.records = []; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', }); assert.containsOnce(pivot, '.o_view_nocontent', "should have a no_content_helper"); pivot.destroy(); }); QUnit.test('no content helper when no data, part 3', async function (assert) { assert.expect(4); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', viewOptions: { domain: [['foo', '=', 12345]] }, }); assert.containsOnce(pivot, '.o_view_nocontent', "should have a no_content_helper"); await testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]}); assert.containsOnce(pivot, '.o_view_nocontent', "should still have a no_content_helper"); await 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. await 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', async function (assert) { assert.expect(5); var rpcCount = 0; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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"); await testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]}); rpcCount = 0; await 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', async function (assert) { assert.expect(4); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); assert.containsOnce(pivot, '.o_pivot_cell_value', "should have only 1 cell"); assert.containsOnce(pivot, 'tbody tr', "should have 1 rows"); await 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', async function (assert) { assert.expect(3); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); assert.strictEqual($('td.o_pivot_cell_value').text(), "321220", "should have proper values in cells (total, result 1, result 2"); await 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"); await 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', async function (assert) { assert.expect(7); var nbReadGroups = 0; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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; await 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 await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened')); await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened')); assert.containsN(pivot, 'tbody tr', 6, "should have 6 rows now"); // expand all nbReadGroups = 0; await 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', async function (assert) { assert.expect(3); var def; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', mockRPC: function (route, args) { var result = this._super.apply(this, arguments); if (args.method === 'read_group') { return Promise.resolve(def).then(_.constant(result)); } return result; }, }); // expand on date:days, product await 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 await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened')); await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened')); assert.containsN(pivot, 'tbody tr', 6, "should have 6 rows now"); // expand all def = testUtils.makeTestPromise(); await testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button')); def.resolve(); await testUtils.nextTick(); assert.containsN(pivot, 'tbody tr', 8, "should have 8 rows again"); pivot.destroy(); }); QUnit.test('can download a file', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', session: { get_file: function (args) { assert.strictEqual(args.url, '/web/pivot/export_xls', "should call get_file with correct parameters"); args.complete(); }, }, }); await testUtils.dom.click(pivot.$buttons.find('.o_pivot_download')); pivot.destroy(); }); QUnit.test('download button is disabled when there is no data', async function (assert) { assert.expect(1); this.data.partner.records = []; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); assert.hasAttrValue(pivot.$buttons.find('.o_pivot_download'), 'disabled', 'disabled', "download button should be disabled"); pivot.destroy(); }); QUnit.test('getOwnedQueryParams correctly returns measures and groupbys', async function (assert) { assert.expect(3); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: ['date:day'], pivot_measures: ['foo'], pivot_row_groupby: [], }, }, "context should be correct"); // expand header on field customer await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed:nth(1)')); await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first')); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: ['date:day', 'customer'], pivot_measures: ['foo'], pivot_row_groupby: [], }, }, "context should be correct"); // expand row on field product_id await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed')); await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first')); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: ['date:day', 'customer'], pivot_measures: ['foo'], pivot_row_groupby: ['product_id'], }, }, "context should be correct"); pivot.destroy(); }); QUnit.test('correctly remove pivot_ keys from the context', async function (assert) { assert.expect(5); this.data.partner.fields.amount = {string: "Amount", type: "float"}; // Equivalent to loading with default filter var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', viewOptions: { context: { pivot_measures: ['foo'], pivot_column_groupby: ['customer'], pivot_row_groupby: ['product_id'], }, }, }); // Equivalent to unload the filter var reloadParams = { context: {}, }; await pivot.reload(reloadParams); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: ['customer'], pivot_measures: ['foo'], pivot_row_groupby: ['product_id'], }, }, "context should be correct"); // Let's get rid of the rows groupBy await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_opened')); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: ['customer'], pivot_measures: ['foo'], pivot_row_groupby: [], }, }, "context should be correct"); // And now, get rid of the col groupby await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_opened')); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: [], pivot_measures: ['foo'], pivot_row_groupby: [], }, }, "context should be correct"); await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed')); await testUtils.dom.click( pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first')); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: [], pivot_measures: ['foo'], pivot_row_groupby: ['product_id'], }, }, "context should be correct"); await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed')); await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first')); assert.deepEqual(pivot.getOwnedQueryParams(), { context: { pivot_column_groupby: ['customer'], pivot_measures: ['foo'], pivot_row_groupby: ['product_id'], }, }, "context should be correct"); pivot.destroy(); }); QUnit.test('Unload Filter, reset display, load another filter', async function (assert) { assert.expect(18); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', viewOptions: { context: { pivot_measures: ['foo'], pivot_column_groupby: ['customer'], pivot_row_groupby: ['product_id'], }, }, }); // Check Columns assert.strictEqual(pivot.$('thead .o_pivot_header_cell_opened').length, 1, 'The column should be grouped'); assert.strictEqual(pivot.$('thead tr:contains("First")').length, 1, 'There should be a column "First"'); assert.strictEqual(pivot.$('thead tr:contains("Second")').length, 1, 'There should be a column "Second"'); // Check Rows assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_opened').length, 1, 'The row should be grouped'); assert.strictEqual(pivot.$('tbody tr:contains("xphone")').length, 1, 'There should be a row "xphone"'); assert.strictEqual(pivot.$('tbody tr:contains("xpad")').length, 1, 'There should be a row "xpad"'); // Equivalent to unload the filter var reloadParams = { context: {}, }; await pivot.reload(reloadParams); // collapse all headers await testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened:first')); await testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened')); // Check Columns assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed').length, 1, 'The column should not be grouped'); assert.strictEqual(pivot.$('thead tr:contains("First")').length, 0, 'There should not be a column "First"'); assert.strictEqual(pivot.$('thead tr:contains("Second")').length, 0, 'There should not be a column "Second"'); // Check Rows assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_closed').length, 1, 'The row should not be grouped'); assert.strictEqual(pivot.$('tbody tr:contains("xphone")').length, 0, 'There should not be a row "xphone"'); assert.strictEqual(pivot.$('tbody tr:contains("xpad")').length, 0, 'There should not be a row "xpad"'); // Equivalent to load another filter reloadParams = { context: { pivot_measures: ['foo'], pivot_column_groupby: ['customer'], pivot_row_groupby: ['product_id'], }, }; await pivot.reload(reloadParams); // Check Columns assert.strictEqual(pivot.$('thead .o_pivot_header_cell_opened').length, 1, 'The column should be grouped'); assert.strictEqual(pivot.$('thead tr:contains("First")').length, 1, 'There should be a column "First"'); assert.strictEqual(pivot.$('thead tr:contains("Second")').length, 1, 'There should be a column "Second"'); // Check Rows assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_opened').length, 1, 'The row should be grouped'); assert.strictEqual(pivot.$('tbody tr:contains("xphone")').length, 1, 'There should be a row "xphone"'); assert.strictEqual(pivot.$('tbody tr:contains("xpad")').length, 1, 'There should be a row "xpad"'); pivot.destroy(); }); QUnit.skip('Reload, group by columns, reload', async function (assert) { assert.expect(2); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', }); // Set a column groupby pivot.$('thead .o_pivot_header_cell_closed').click(); pivot.$('.o_field_selection .dropdown-item[data-field=customer]').click(); // Set a domain await pivot.update({domain: [['product_id', '=', 41]]}); var expectedContext = {pivot_column_groupby: ['customer'], pivot_measures: ['__count'], pivot_row_groupby: []}; // Check that column groupbys were not lost assert.deepEqual(pivot.getOwnedQueryParams(), {context: expectedContext}, 'Column groupby not lost after first reload'); // Set a column groupby pivot.$('thead .o_pivot_header_cell_closed').click(); pivot.$('.o_field_selection .dropdown-item[data-field=product_id]').click(); // Set a domain await pivot.update({domain: [['product_id', '=', 37]]}); expectedContext = {pivot_column_groupby: ['customer', 'product_id'], pivot_measures: ['__count'], pivot_row_groupby: []}; assert.deepEqual(pivot.getOwnedQueryParams(), {context: expectedContext}, 'Column groupby not lost after second reload'); pivot.destroy(); }); QUnit.skip('Empty results keep groupbys', async function (assert) { assert.expect(2); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', }); // Set a column groupby pivot.$('thead .o_pivot_header_cell_closed').click(); pivot.$('.o_field_selection .dropdown-item[data-field=customer]').click(); // Set a domain for empty results await pivot.update({domain: [['id', '=', false]]}); var expectedContext = {pivot_column_groupby: ['customer'], pivot_measures: ['__count'], pivot_row_groupby: []}; assert.deepEqual(pivot.getOwnedQueryParams(), {context: expectedContext}, 'Column groupby not lost after empty results'); // Set a domain for not empty results await pivot.update({domain: [['product_id', '=', 37]]}); assert.deepEqual(pivot.getOwnedQueryParams(), {context: expectedContext}, 'Column groupby not lost after reload after empty results'); pivot.destroy(); }); QUnit.test('correctly uses pivot_ keys from the context', async function (assert) { assert.expect(7); this.data.partner.fields.amount = {string: "Amount", type: "float"}; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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)', async function (assert) { assert.expect(8); this.data.partner.fields.amount = {string: "Amount", type: "float"}; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); 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'], }, }; await 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', async function (assert) { assert.expect(7); var pivot = await createView({ View: PivotView, model: 'partner', data: this.data, arch: '' + '' + '' + '', 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_row_groupby key with default groupBy from the context', async function (assert) { assert.expect(6); this.data.partner.fields.amount = {string: "Amount", type: "float"}; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', groupBy: ['customer'], viewOptions: { context: { pivot_row_groupby: ['product_id'], }, }, }); assert.strictEqual(pivot.$('thead .o_pivot_header_cell_opened').length, 1, "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'"); // With pivot_row_groupby, groupBy customer should replace and eventually display product_id assert.strictEqual(pivot.$('tbody .o_pivot_header_cell_opened').length, 1, "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'"); pivot.destroy(); }); QUnit.test('pivot still handles __count__ measure', async function (assert) { // for retro-compatibility reasons, the pivot view still handles // '__count__' measure. assert.expect(2); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '', 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '' + '', }); 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); await 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 await 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', viewOptions: { additionalMeasures: ['product_id'], }, }); await testUtils.pivot.toggleMeasuresDropdown(pivot); await 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)', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed')); await 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', async function (assert) { assert.expect(3); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); // Set a column groupby await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed')); await testUtils.dom.click(pivot.$('.o_field_selection .dropdown-item[data-field=customer]:first')); // Set a Row groupby await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed')); await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field=product_id]:first')); // Set a domain await testUtils.pivot.reload(pivot, {domain: [['product_id', '=', 41]]}); var expectedContext = { context: { pivot_column_groupby: ['customer'], pivot_measures: ['foo'], pivot_row_groupby: ['product_id'], }, }; // Mock 'save as favorite' assert.deepEqual(pivot.getOwnedQueryParams(), 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', async function (assert) { assert.expect(2); var def; var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', mockRPC: function (route, args) { var result = this._super.apply(this, arguments); if (args.method === 'read_group') { return Promise.resolve(def).then(_.constant(result)); } return result; }, }); def = testUtils.makeTestPromise(); testUtils.pivot.reload(pivot, {groupBy: ['product_id']}); testUtils.pivot.reload(pivot, {groupBy: ['product_id', 'customer']}); await def.resolve(); await testUtils.nextTick(); 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', async 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 = await createView({ View: PivotView, model: "partner", data: data, arch: '' + '' + '' + '' + '' + '', }); 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', async function (assert) { assert.expect(1); var pivot = await createView({ View: PivotView, model: "partner", data: this.data, arch: '' + '' + '', }); 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', async 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 = await createActionManager({ data: this.data, archs: { 'partner,false,pivot': '' + '' + '' + '', 'partner,false,search': '', } }); await actionManager.doAction({ res_model: 'partner', type: 'ir.actions.act_window', views: [[false, 'pivot']], flags: { pivot: { additionalMeasures: ['product_id'], } } }); // with no data await testUtils.dom.click($('.o_time_range_menu_button')); await testUtils.dom.click($('.o_time_range_menu .o_comparison_checkbox')); $('.o_time_range_selector').val('today'); await 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 await testUtils.dom.click($('.o_time_range_menu_button')); $('.o_time_range_selector').val('this_month'); await 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 await testUtils.dom.click($('.o_pivot .o_pivot_header_cell_closed').eq(2)); await 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); await testUtils.pivot.toggleMeasuresDropdown(actionManager.getCurrentController().widget); await testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="foo"]')); await 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); await testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="__count"]')); await 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); await testUtils.dom.clickFirst($('.o_pivot .o_pivot_header_cell_opened')); results = [ "2", "2", "0%" , "1", "0", "100%" , "1", "2", "-50%" ]; checkCellValues(results); $('.o_search_options button:contains("Favorites")').click(); var $favorites = $('.dropdown-menu.o_favorites_menu'); $favorites.find('a.o_save_search').click(); $favorites.find('.o_input').val('Fav').trigger('input'); $favorites.find('button').click(); unpatchDate(); actionManager.destroy(); }); QUnit.test('export data in excel with comparison', async 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 = await createActionManager({ data: this.data, archs: { 'partner,false,pivot': '' + '' + '' + '', 'partner,false,search': '', }, session: { get_file: function (args) { var data = JSON.parse(args.data.data); _.each(data.headers, function (l) { var titles = l.map(function (o) {return o.title;}); assert.step(JSON.stringify(titles)); }); var measures = data.measure_row.map(function (o) {return o.measure;}); assert.step(JSON.stringify(measures)); assert.step(String(data.nbr_measures)); var valuesLength = data.rows.map(function (o) {return o.values.length;}); assert.step(JSON.stringify(valuesLength)); assert.strictEqual(args.url, '/web/pivot/export_xls', "should call get_file with correct parameters"); args.complete(); }, }, }); await actionManager.doAction({ res_model: 'partner', type: 'ir.actions.act_window', views: [[false, 'pivot']], }); // open time range menu await 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' await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); // Click on 'Apply' button await 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 await 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 await 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' await 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', async 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 = await createActionManager({ data: this.data, archs: { 'partner,false,pivot': '' + '' + '', 'partner,false,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 Promise.resolve([{}]); } } return result; }, }); await 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 await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button')); $('.o_control_panel .o_time_range_selector').val('this_month'); await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); await 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(); }); QUnit.module('Sort in comparison mode', { beforeEach: async function () { this.data.partner.records[0].date = '2016-12-15'; this.data.partner.records[1].date = '2016-12-17'; this.data.partner.records[2].date = '2016-11-22'; this.data.partner.records[3].date = '2016-11-03'; this.data.partner.fields.company_type = {string: "Company Type", type: "selection", selection: [["company", "Company"], ["individual", "individual"]], searchable: true, store: true, sortable: true}; this.data.partner.records[0].company_type = 'company'; this.data.partner.records[1].company_type = 'individual'; this.data.partner.records[2].company_type = 'company'; this.data.partner.records[3].company_type = 'individual'; this.unpatchDate = patchDate(2016, 11, 20, 1, 0, 0); this.actualResult = function () { var actualResult = $('.o_pivot .o_pivot_cell_value div').map(function() { return $( this ).text(); }).get().join(); return actualResult; }; // create an action manager to test the interactions with the search view this.actionManager = await createActionManager({ data: this.data, archs: { 'partner,false,pivot': '' + '' + '' + '' + '', 'partner,false,search': '', }, }); await this.actionManager.doAction({ res_model: 'partner', type: 'ir.actions.act_window', views: [[false, 'pivot']], flags: { pivot: { additionalMeasures: ['product_id'], } } }); // open time range menu await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button')); // select 'Today' as range await testUtils.fields.editInput($('.o_control_panel .o_time_range_selector'), 'this_month'); // check checkbox 'Compare To' await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox')); // Click on 'Apply' button await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range')); // We are in comparison mode }, afterEach: function () { this.unpatchDate(); this.actionManager.destroy(); }, }, function () { QUnit.test('when clicking on measure, sort by "This Month" (period of interest)', async function (assert) { assert.expect(1); // click on 'Foo' in column Total/Company await testUtils.dom.click($('.o_pivot_measure_row').eq(0)); var results = [ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", "12", "0", "100%", "12", "0" , "100%", "1", "0", "100%", "1" , "0", "100%", "0", "17", "-100%", "0", "17", "-100%", "0", "2", "-100%", "0" , "2" , "-100%" ]; assert.strictEqual(this.actualResult(), results.join()); }); QUnit.test( 'click on a period of interest header sort according to the appropriate column ' + 'first in ascending order then in descending order', async function (assert) { assert.expect(2); // click on 'This Month' in column Total/Individual/Foo await testUtils.dom.click($('.o_pivot_measure_row').eq(6)); var results = [ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", "1", "0", "100%", "1" , "0", "100%", "12", "0", "100%", "12", "0" , "100%", "0", "17", "-100%", "0", "17", "-100%", "0", "2", "-100%", "0" , "2" , "-100%" ]; var actualResult = $('.o_pivot .o_pivot_cell_value div').text(); assert.strictEqual(actualResult, results.join('')); // click once again on 'This Month' in column Total/Individual/Foo await testUtils.dom.click($('.o_pivot_measure_row').eq(6)); results = [ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", "12", "0", "100%", "12", "0" , "100%", "0", "17", "-100%", "0", "17", "-100%", "0", "2", "-100%", "0" , "2" , "-100%", "1", "0", "100%", "1" , "0", "100%" ]; assert.strictEqual(this.actualResult(), results.join()); }); QUnit.test('click on a period of comparison header sort according to appropriate column', async function (assert) { assert.expect(1); // click on 'Previous Period' in column Total/Individual/Foo await testUtils.dom.click($('.o_pivot_measure_row').eq(7)); var results = [ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", "0", "2", "-100%", "0" , "2" , "-100%", "12", "0", "100%", "12", "0" , "100%", "1", "0", "100%", "1" , "0", "100%", "0", "17", "-100%", "0", "17", "-100%" ]; assert.strictEqual(this.actualResult(), results.join()); }); QUnit.test('click on a variation header sort according to appropriate column', async function (assert) { assert.expect(1); // click on 'Variation' in column Total/Individual/Foo await testUtils.dom.click($('.o_pivot_measure_row').eq(11)); var results = [ "12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%", "12", "0", "100%", "12", "0" , "100%", "1", "0", "100%", "1" , "0", "100%", "0", "17", "-100%", "0", "17", "-100%", "0", "2", "-100%", "0" , "2" , "-100%" ]; assert.strictEqual(this.actualResult(), results.join()); }); }); }); });