[ADD] base modules
This commit is contained in:
672
web_cohort/static/tests/cohort_tests.js
Executable file
672
web_cohort/static/tests/cohort_tests.js
Executable file
@@ -0,0 +1,672 @@
|
||||
odoo.define('web_cohort.cohort_tests', function (require) {
|
||||
'use strict';
|
||||
|
||||
var CohortView = require('web_cohort.CohortView');
|
||||
var testUtils = require('web.test_utils');
|
||||
|
||||
const cpHelpers = testUtils.controlPanel;
|
||||
var createView = testUtils.createView;
|
||||
var createActionManager = testUtils.createActionManager;
|
||||
var patchDate = testUtils.mock.patchDate;
|
||||
|
||||
QUnit.module('Views', {
|
||||
beforeEach: function () {
|
||||
this.data = {
|
||||
subscription: {
|
||||
fields: {
|
||||
id: {string: 'ID', type: 'integer'},
|
||||
start: {string: 'Start', type: 'date', sortable: true},
|
||||
stop: {string: 'Stop', type: 'date', sortable: true},
|
||||
recurring: {string: 'Recurring Price', type: 'integer', store: true},
|
||||
},
|
||||
records: [
|
||||
{id: 1, start: '2017-07-12', stop: '2017-08-11', recurring: 10},
|
||||
{id: 2, start: '2017-08-14', stop: '', recurring: 20},
|
||||
{id: 3, start: '2017-08-21', stop: '2017-08-29', recurring: 10},
|
||||
{id: 4, start: '2017-08-21', stop: '', recurring: 20},
|
||||
{id: 5, start: '2017-08-23', stop: '', recurring: 10},
|
||||
{id: 6, start: '2017-08-24', stop: '', recurring: 22},
|
||||
{id: 7, start: '2017-08-24', stop: '2017-08-29', recurring: 10},
|
||||
{id: 8, start: '2017-08-24', stop: '', recurring: 22},
|
||||
]
|
||||
},
|
||||
lead: {
|
||||
fields: {
|
||||
id: {string: 'ID', type: 'integer'},
|
||||
start: {string: 'Start', type: 'date'},
|
||||
stop: {string: 'Stop', type: 'date'},
|
||||
revenue: {string: 'Revenue', type: 'float', store: true},
|
||||
},
|
||||
records: [
|
||||
{id: 1, start: '2017-07-12', stop: '2017-08-11', revenue: 1200.20},
|
||||
{id: 2, start: '2017-08-14', stop: '', revenue: 500},
|
||||
{id: 3, start: '2017-08-21', stop: '2017-08-29', revenue: 5599.99},
|
||||
{id: 4, start: '2017-08-21', stop: '', revenue: 13500},
|
||||
{id: 5, start: '2017-08-23', stop: '', revenue: 6000},
|
||||
{id: 6, start: '2017-08-24', stop: '', revenue: 1499.99},
|
||||
{id: 7, start: '2017-08-24', stop: '2017-08-29', revenue: 16000},
|
||||
{id: 8, start: '2017-08-24', stop: '', revenue: 22000},
|
||||
]
|
||||
},
|
||||
attendee: {
|
||||
fields: {
|
||||
id: {string: 'ID', type: 'integer'},
|
||||
event_begin_date: {string: 'Event Start Date', type: 'date'},
|
||||
registration_date: {string: 'Registration Date', type: 'date'},
|
||||
},
|
||||
records: [
|
||||
{id: 1, event_begin_date: '2018-06-30', registration_date: '2018-06-13'},
|
||||
{id: 2, event_begin_date: '2018-06-30', registration_date: '2018-06-20'},
|
||||
{id: 3, event_begin_date: '2018-06-30', registration_date: '2018-06-22'},
|
||||
{id: 4, event_begin_date: '2018-06-30', registration_date: '2018-06-22'},
|
||||
{id: 5, event_begin_date: '2018-06-30', registration_date: '2018-06-29'},
|
||||
]
|
||||
},
|
||||
};
|
||||
}
|
||||
}, function () {
|
||||
QUnit.module('CohortView');
|
||||
|
||||
QUnit.test('simple cohort rendering', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" />',
|
||||
});
|
||||
|
||||
assert.containsOnce(cohort, '.table',
|
||||
'should have a table');
|
||||
assert.ok(cohort.$('.table thead tr:first th:first:contains(Start)').length,
|
||||
'should contain "Start" in header of first column');
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(3):contains(Stop - By Day)').length,
|
||||
'should contain "Stop - By Day" in title');
|
||||
assert.ok(cohort.$('.table thead tr:nth-child(2) th:first:contains(+0)').length,
|
||||
'interval should start with 0');
|
||||
assert.ok(cohort.$('.table thead tr:nth-child(2) th:nth-child(16):contains(+15)').length,
|
||||
'interval should end with 15');
|
||||
|
||||
assert.strictEqual(cohort.$buttons.find('.o_cohort_measures_list').length, 1,
|
||||
'should have list of measures');
|
||||
assert.strictEqual(cohort.$buttons.find('.o_cohort_interval_button').length, 4,
|
||||
'should have buttons of intervals');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('no content helper', async function (assert) {
|
||||
assert.expect(1);
|
||||
this.data.subscription.records = [];
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: "subscription",
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" />',
|
||||
});
|
||||
|
||||
assert.containsOnce(cohort, 'div.o_view_nocontent');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('no content helper after update', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: "subscription",
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" measure="recurring"/>',
|
||||
});
|
||||
|
||||
assert.containsNone(cohort, 'div.o_view_nocontent');
|
||||
|
||||
await cohort.update({domain: [['recurring', '>', 25]]});
|
||||
|
||||
assert.containsOnce(cohort, 'div.o_view_nocontent');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('correctly set by default measure and interval', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" />'
|
||||
});
|
||||
|
||||
assert.hasClass(cohort.$buttons.find('.o_cohort_measures_list [data-field=__count__]'),'selected',
|
||||
'count should by default for measure');
|
||||
assert.hasClass(cohort.$buttons.find('.o_cohort_interval_button[data-interval=day]'),'active',
|
||||
'day should by default for interval');
|
||||
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(2):contains(Count)').length,
|
||||
'should contain "Count" in header of second column');
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(3):contains(Stop - By Day)').length,
|
||||
'should contain "Stop - By Day" in title');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('correctly sort measure items', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
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.subscription.fields.flop = {string: 'Abc', type: 'integer', store: true};
|
||||
data.subscription.fields.add = {string: 'add', type: 'integer', store: true};
|
||||
data.subscription.fields.zoo = {string: 'Zoo', type: 'integer', store: true};
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop"/>',
|
||||
});
|
||||
|
||||
const buttonsEls = cpHelpers.getButtons(cohort);
|
||||
const measureButtonEls = buttonsEls[0].querySelectorAll('.o_cohort_measures_list > button');
|
||||
assert.deepEqual(
|
||||
[...measureButtonEls].map(e => e.innerText.trim()),
|
||||
["Abc", "add", "Recurring Price", "Zoo", "Count"]
|
||||
);
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('correctly set measure and interval after changed', async function (assert) {
|
||||
assert.expect(8);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" measure="recurring" interval="week" />'
|
||||
});
|
||||
|
||||
assert.hasClass(cohort.$buttons.find('.o_cohort_measures_list [data-field=recurring]'),'selected',
|
||||
'should recurring for measure');
|
||||
assert.hasClass(cohort.$buttons.find('.o_cohort_interval_button[data-interval=week]'),'active',
|
||||
'should week for interval');
|
||||
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(2):contains(Recurring Price)').length,
|
||||
'should contain "Recurring Price" in header of second column');
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(3):contains(Stop - By Week)').length,
|
||||
'should contain "Stop - By Week" in title');
|
||||
|
||||
await testUtils.dom.click(cohort.$buttons.find('.dropdown-toggle:contains(Measures)'));
|
||||
await testUtils.dom.click(cohort.$buttons.find('.o_cohort_measures_list [data-field=__count__]'));
|
||||
assert.hasClass(cohort.$buttons.find('.o_cohort_measures_list [data-field=__count__]'),'selected',
|
||||
'should active count for measure');
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(2):contains(Count)').length,
|
||||
'should contain "Count" in header of second column');
|
||||
|
||||
await testUtils.dom.click(cohort.$buttons.find('.o_cohort_interval_button[data-interval=month]'));
|
||||
assert.hasClass(cohort.$buttons.find('.o_cohort_interval_button[data-interval=month]'),'active',
|
||||
'should active month for interval');
|
||||
assert.ok(cohort.$('.table thead tr:first th:nth-child(3):contains(Stop - By Month)').length,
|
||||
'should contain "Stop - By Month" in title');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('cohort view without attribute invisible on field', async function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: `<cohort string="Subscription" date_start="start" date_stop="stop"/>`,
|
||||
});
|
||||
|
||||
await testUtils.dom.click(cohort.$('.btn-group:first button'));
|
||||
assert.containsN(cohort, '.o_cohort_measures_list button', 2);
|
||||
assert.containsOnce(cohort, '.o_cohort_measures_list button[data-field="recurring"]');
|
||||
assert.containsOnce(cohort, '.o_cohort_measures_list button[data-field="__count__"]');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('cohort view with attribute invisible on field', async function (assert) {
|
||||
assert.expect(2);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: `
|
||||
<cohort string="Subscription" date_start="start" date_stop="stop">
|
||||
<field name="recurring" invisible="1"/>
|
||||
</cohort>`,
|
||||
});
|
||||
|
||||
await testUtils.dom.click(cohort.$('.btn-group:first button'));
|
||||
assert.containsOnce(cohort, '.o_cohort_measures_list button');
|
||||
assert.containsNone(cohort, '.o_cohort_measures_list button[data-field="recurring"]');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('export cohort', async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" />',
|
||||
session: {
|
||||
get_file: async function (params) {
|
||||
var data = JSON.parse(params.data.data);
|
||||
assert.strictEqual(params.url, '/web/cohort/export');
|
||||
assert.strictEqual(data.interval_string, 'Day');
|
||||
assert.strictEqual(data.measure_string, 'Count');
|
||||
assert.strictEqual(data.date_start_string, 'Start');
|
||||
assert.strictEqual(data.date_stop_string, 'Stop');
|
||||
assert.strictEqual(data.title, 'Subscription');
|
||||
params.complete();
|
||||
return true;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await testUtils.dom.click(cohort.$buttons.find('.o_cohort_download_button'));
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('when clicked on cell redirects to the correct list/form view ', async function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var actionManager = await createActionManager({
|
||||
data: this.data,
|
||||
archs: {
|
||||
'subscription,false,cohort': '<cohort string="Subscriptions" date_start="start" date_stop="stop" measure="__count__" interval="week" />',
|
||||
'subscription,my_list_view,list': '<tree>' +
|
||||
'<field name="start"/>' +
|
||||
'<field name="stop"/>' +
|
||||
'</tree>',
|
||||
'subscription,my_form_view,form': '<form>' +
|
||||
'<field name="start"/>' +
|
||||
'<field name="stop"/>' +
|
||||
'</form>',
|
||||
'subscription,false,list': '<tree>' +
|
||||
'<field name="recurring"/>' +
|
||||
'<field name="start"/>' +
|
||||
'</tree>',
|
||||
'subscription,false,form': '<form>' +
|
||||
'<field name="recurring"/>' +
|
||||
'<field name="start"/>' +
|
||||
'</form>',
|
||||
'subscription,false,search': '<search></search>',
|
||||
},
|
||||
intercepts: {
|
||||
do_action: function (ev) {
|
||||
actionManager.doAction(ev.data.action, ev.data.options);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await actionManager.doAction({
|
||||
name: 'Subscriptions',
|
||||
res_model: 'subscription',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'cohort'], ['my_list_view', 'list'], ['my_form_view', 'form']],
|
||||
});
|
||||
|
||||
// Going to the list view, while clicking Period / Count cell
|
||||
await testUtils.dom.click(actionManager.$('td.o_cohort_value:first'));
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(1)').text(), 'Start',
|
||||
"First field in the list view should be start");
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(2)').text(), 'Stop',
|
||||
"Second field in the list view should be stop");
|
||||
|
||||
// Going back to cohort view
|
||||
await testUtils.dom.click(actionManager.$('.o_back_button'));
|
||||
// Going to the list view
|
||||
await testUtils.dom.click(actionManager.$('td div.o_cohort_value:first'));
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(1)').text(), 'Start',
|
||||
"First field in the list view should be start");
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(2)').text(), 'Stop',
|
||||
"Second field in the list view should be stop");
|
||||
|
||||
// Going to the form view
|
||||
await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row'));
|
||||
|
||||
assert.hasAttrValue(actionManager.$('.o_form_view span:first'), 'name', 'start',
|
||||
"First field in the form view should be start");
|
||||
assert.hasAttrValue(actionManager.$('.o_form_view span:nth(1)'), 'name', 'stop',
|
||||
"Second field in the form view should be stop");
|
||||
|
||||
actionManager.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('test mode churn', async function(assert) {
|
||||
assert.expect(3);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'lead',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Leads" date_start="start" date_stop="stop" interval="week" mode="churn" />',
|
||||
mockRPC: function(route, args) {
|
||||
assert.strictEqual(args.kwargs.mode, "churn", "churn mode should be sent via RPC");
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
|
||||
assert.strictEqual(cohort.$('td .o_cohort_value:first').text().trim(), '0%', 'first col should display 0 percent');
|
||||
assert.strictEqual(cohort.$('td .o_cohort_value:nth(4)').text().trim(), '100%', 'col 5 should display 100 percent');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('test backward timeline', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'attendee',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Attendees" date_start="event_begin_date" date_stop="registration_date" interval="day" timeline="backward" mode="churn"/>',
|
||||
mockRPC: function (route, args) {
|
||||
assert.strictEqual(args.kwargs.timeline, "backward", "backward timeline should be sent via RPC");
|
||||
return this._super(route, args);
|
||||
},
|
||||
});
|
||||
assert.ok(cohort.$('.table thead tr:nth-child(2) th:first:contains(-15)').length,
|
||||
'interval should start with -15');
|
||||
assert.ok(cohort.$('.table thead tr:nth-child(2) th:nth-child(16):contains(0)').length,
|
||||
'interval should end with 0');
|
||||
assert.strictEqual(cohort.$('td .o_cohort_value:first').text().trim(), '20%', 'first col should display 20 percent');
|
||||
assert.strictEqual(cohort.$('td .o_cohort_value:nth(5)').text().trim(), '40%', 'col 6 should display 40 percent');
|
||||
assert.strictEqual(cohort.$('td .o_cohort_value:nth(7)').text().trim(), '80%', 'col 8 should display 80 percent');
|
||||
assert.strictEqual(cohort.$('td .o_cohort_value:nth(14)').text().trim(), '100%', 'col 15 should display 100 percent');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('when clicked on cell redirects to the action list/form view passed in context', async function(assert) {
|
||||
assert.expect(6);
|
||||
|
||||
var actionManager = await createActionManager({
|
||||
data: this.data,
|
||||
archs: {
|
||||
'subscription,false,cohort': '<cohort string="Subscriptions" date_start="start" date_stop="stop" measure="__count__" interval="week" />',
|
||||
'subscription,my_list_view,list': '<tree>' +
|
||||
'<field name="start"/>' +
|
||||
'<field name="stop"/>' +
|
||||
'</tree>',
|
||||
'subscription,my_form_view,form': '<form>' +
|
||||
'<field name="start"/>' +
|
||||
'<field name="stop"/>' +
|
||||
'</form>',
|
||||
'subscription,false,list': '<tree>' +
|
||||
'<field name="recurring"/>' +
|
||||
'<field name="start"/>' +
|
||||
'</tree>',
|
||||
'subscription,false,form': '<form>' +
|
||||
'<field name="recurring"/>' +
|
||||
'<field name="start"/>' +
|
||||
'</form>',
|
||||
'subscription,false,search': '<search></search>',
|
||||
},
|
||||
intercepts: {
|
||||
do_action: function (ev) {
|
||||
actionManager.doAction(ev.data.action, ev.data.options);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await actionManager.doAction({
|
||||
name: 'Subscriptions',
|
||||
res_model: 'subscription',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'cohort']],
|
||||
context: {list_view_id: 'my_list_view', form_view_id: 'my_form_view'},
|
||||
});
|
||||
|
||||
// Going to the list view, while clicking Period / Count cell
|
||||
await testUtils.dom.click(actionManager.$('td.o_cohort_value:first'));
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(1)').text(), 'Start',
|
||||
"First field in the list view should be start");
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(2)').text(), 'Stop',
|
||||
"Second field in the list view should be stop");
|
||||
|
||||
// Going back to cohort view
|
||||
await testUtils.dom.click($('.o_back_button'));
|
||||
|
||||
// Going to the list view
|
||||
await testUtils.dom.click(actionManager.$('td div.o_cohort_value:first'));
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(1)').text(), 'Start',
|
||||
"First field in the list view should be start");
|
||||
assert.strictEqual(actionManager.$('.o_list_view th:nth(2)').text(), 'Stop',
|
||||
"Second field in the list view should be stop");
|
||||
|
||||
// Going to the form view
|
||||
await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row'));
|
||||
|
||||
assert.hasAttrValue(actionManager.$('.o_form_view span:first'), 'name', 'start',
|
||||
"First field in the form view should be start");
|
||||
assert.hasAttrValue(actionManager.$('.o_form_view span:nth(1)'), 'name', 'stop',
|
||||
"Second field in the form view should be stop");
|
||||
|
||||
actionManager.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('rendering of a cohort view with comparison', async function (assert) {
|
||||
assert.expect(29);
|
||||
|
||||
var unpatchDate = patchDate(2017, 7, 25, 1, 0, 0);
|
||||
|
||||
var actionManager = await createActionManager({
|
||||
data: this.data,
|
||||
archs: {
|
||||
'subscription,false,cohort': '<cohort string="Subscriptions" date_start="start" date_stop="stop" measure="__count__" interval="week" />',
|
||||
'subscription,false,search': `
|
||||
<search>
|
||||
<filter date="start" name="date_filter" string="Date"/>
|
||||
</search>
|
||||
`,
|
||||
},
|
||||
intercepts: {
|
||||
do_action: function (ev) {
|
||||
actionManager.doAction(ev.data.action, ev.data.options);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await actionManager.doAction({
|
||||
name: 'Subscriptions',
|
||||
res_model: 'subscription',
|
||||
type: 'ir.actions.act_window',
|
||||
views: [[false, 'cohort']],
|
||||
});
|
||||
|
||||
function verifyContents(results) {
|
||||
var $tables = actionManager.$('table');
|
||||
assert.strictEqual($tables.length, results.length, 'There should be ' + results.length + ' tables');
|
||||
var result;
|
||||
$tables.each(function () {
|
||||
result = results.shift();
|
||||
var $table = $(this);
|
||||
var rowCount = $table.find('.o_cohort_row_clickable').length;
|
||||
|
||||
if (rowCount) {
|
||||
assert.strictEqual(rowCount, result, 'the table should contain ' + result + ' rows');
|
||||
} else {
|
||||
assert.strictEqual($table.find('th:first').text().trim(), result,
|
||||
'the table should contain the time range description' + result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// with no comparison, with data (no filter)
|
||||
verifyContents([3]);
|
||||
assert.containsNone(actionManager, '.o_cohort_no_data');
|
||||
assert.containsNone(actionManager, 'div.o_view_nocontent');
|
||||
|
||||
// with no comparison with no data (filter on 'last_year')
|
||||
await cpHelpers.toggleFilterMenu(actionManager);
|
||||
await cpHelpers.toggleMenuItem(actionManager, 'Date');
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', '2016');
|
||||
|
||||
verifyContents([]);
|
||||
assert.containsNone(actionManager, '.o_cohort_no_data');
|
||||
assert.containsOnce(actionManager, 'div.o_view_nocontent');
|
||||
|
||||
// with comparison active, data and comparisonData (filter on 'this_month' + 'previous_period')
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', '2016');
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', 'August');
|
||||
await cpHelpers.toggleComparisonMenu(actionManager);
|
||||
await cpHelpers.toggleMenuItem(actionManager, 'Date: Previous period');
|
||||
|
||||
verifyContents(['August 2017', 2, 'July 2017', 1]);
|
||||
assert.containsNone(actionManager, '.o_cohort_no_data');
|
||||
assert.containsNone(actionManager, 'div.o_view_nocontent');
|
||||
|
||||
// with comparison active, data, no comparisonData (filter on 'this_year' + 'previous_period')
|
||||
await cpHelpers.toggleFilterMenu(actionManager);
|
||||
await cpHelpers.toggleMenuItem(actionManager, 'Date');
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', 'August');
|
||||
|
||||
verifyContents(['2017', 3, '2016']);
|
||||
assert.containsOnce(actionManager, '.o_cohort_no_data');
|
||||
assert.containsNone(actionManager, 'div.o_view_nocontent');
|
||||
|
||||
// with comparison active, no data, comparisonData (filter on 'Q4' + 'previous_period')
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', 'Q4');
|
||||
|
||||
verifyContents(['Q4 2017', 'Q3 2017', 3]);
|
||||
assert.containsOnce(actionManager, '.o_cohort_no_data');
|
||||
assert.containsNone(actionManager, 'div.o_view_nocontent');
|
||||
|
||||
// with comparison active, no data, no comparisonData (filter on 'last_year' + 'previous_period')
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', '2016');
|
||||
await cpHelpers.toggleMenuItemOption(actionManager, 'Date', '2017');
|
||||
|
||||
verifyContents([]);
|
||||
assert.containsNone(actionManager, '.o_cohort_no_data');
|
||||
assert.containsOnce(actionManager, 'div.o_view_nocontent');
|
||||
|
||||
unpatchDate();
|
||||
actionManager.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('verify context', async function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var cohort = await createView({
|
||||
View: CohortView,
|
||||
model: 'subscription',
|
||||
data: this.data,
|
||||
arch: '<cohort string="Subscription" date_start="start" date_stop="stop" />',
|
||||
mockRPC: function (route, args) {
|
||||
if (args.method === 'get_cohort_data') {
|
||||
assert.ok(args.kwargs.context);
|
||||
}
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
});
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('empty cohort view with action helper', async function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
const cohort = await createView({
|
||||
View: CohortView,
|
||||
model: "subscription",
|
||||
data: this.data,
|
||||
arch: '<cohort date_start="start" date_stop="stop"/>',
|
||||
domain: [['id', '<', 0]],
|
||||
viewOptions: {
|
||||
action: {
|
||||
context: {},
|
||||
help: '<p class="abc">click to add a foo</p>'
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.containsOnce(cohort, '.o_view_nocontent .abc');
|
||||
assert.containsNone(cohort, 'table');
|
||||
|
||||
await cohort.reload({ domain: [] });
|
||||
|
||||
assert.containsNone(cohort, '.o_view_nocontent .abc');
|
||||
assert.containsOnce(cohort, 'table');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('empty cohort view with sample data', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const cohort = await createView({
|
||||
View: CohortView,
|
||||
model: "subscription",
|
||||
data: this.data,
|
||||
arch: '<cohort sample="1" date_start="start" date_stop="stop"/>',
|
||||
domain: [['id', '<', 0]],
|
||||
viewOptions: {
|
||||
action: {
|
||||
context: {},
|
||||
help: '<p class="abc">click to add a foo</p>'
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.hasClass(cohort.el, 'o_view_sample_data');
|
||||
assert.containsOnce(cohort, '.o_view_nocontent .abc');
|
||||
assert.containsOnce(cohort, 'table.o_sample_data_disabled');
|
||||
|
||||
await cohort.reload({ domain: [] });
|
||||
|
||||
assert.doesNotHaveClass(cohort.el, 'o_view_sample_data');
|
||||
assert.containsNone(cohort, '.o_view_nocontent .abc');
|
||||
assert.containsOnce(cohort, 'table');
|
||||
assert.doesNotHaveClass(cohort.$('table'), 'o_sample_data_disabled');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('non empty cohort view with sample data', async function (assert) {
|
||||
assert.expect(7);
|
||||
|
||||
const cohort = await createView({
|
||||
View: CohortView,
|
||||
model: "subscription",
|
||||
data: this.data,
|
||||
arch: '<cohort sample="1" date_start="start" date_stop="stop"/>',
|
||||
viewOptions: {
|
||||
action: {
|
||||
context: {},
|
||||
help: '<p class="abc">click to add a foo</p>'
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
assert.doesNotHaveClass(cohort.el, 'o_view_sample_data');
|
||||
assert.containsNone(cohort, '.o_view_nocontent .abc');
|
||||
assert.containsOnce(cohort, 'table');
|
||||
assert.doesNotHaveClass(cohort.$('table'), 'o_sample_data_disabled');
|
||||
|
||||
await cohort.reload({ domain: [['id', '<', 0]] });
|
||||
|
||||
assert.doesNotHaveClass(cohort.el, 'o_view_sample_data');
|
||||
assert.containsOnce(cohort, '.o_view_nocontent .abc');
|
||||
assert.containsNone(cohort, 'table');
|
||||
|
||||
cohort.destroy();
|
||||
});
|
||||
});
|
||||
});
|
||||
171
web_cohort/static/tests/mock_server.js
Executable file
171
web_cohort/static/tests/mock_server.js
Executable file
@@ -0,0 +1,171 @@
|
||||
odoo.define('web_cohort.MockServer', function (require) {
|
||||
'use strict';
|
||||
|
||||
var MockServer = require('web.MockServer');
|
||||
|
||||
MockServer.include({
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @private
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_performRpc: function (route, args) {
|
||||
if (args.method === 'get_cohort_data') {
|
||||
return this._mockGetCohortData(args.model, args.kwargs);
|
||||
} else {
|
||||
return this._super(route, args);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} model
|
||||
* @param {Object} kwargs
|
||||
* @returns {Promise}
|
||||
*/
|
||||
_mockGetCohortData: function (model, kwargs) {
|
||||
var self = this;
|
||||
var displayFormats = {
|
||||
'day': 'DD MMM YYYY',
|
||||
'week': 'ww YYYY',
|
||||
'month': 'MMMM YYYY',
|
||||
'year': 'Y',
|
||||
};
|
||||
var rows = [];
|
||||
var totalValue = 0;
|
||||
var initialChurnValue = 0;
|
||||
var columnsAvg = {};
|
||||
|
||||
var groups = this._mockReadGroup(model, {
|
||||
domain: kwargs.domain,
|
||||
fields: [kwargs.date_start],
|
||||
groupby: [kwargs.date_start + ':' + kwargs.interval],
|
||||
});
|
||||
var totalCount = groups.length;
|
||||
_.each(groups, function (group) {
|
||||
var format;
|
||||
switch (kwargs.interval) {
|
||||
case 'day':
|
||||
format = 'YYYY-MM-DD';
|
||||
break;
|
||||
case 'week':
|
||||
format = 'ww YYYY';
|
||||
break;
|
||||
case 'month':
|
||||
format = 'MMMM YYYY';
|
||||
break;
|
||||
case 'year':
|
||||
format = 'Y';
|
||||
break;
|
||||
}
|
||||
var cohortStartDate = moment(group[kwargs.date_start + ':' + kwargs.interval], format);
|
||||
|
||||
var records = self._mockSearchReadController({
|
||||
model: model,
|
||||
domain: group.__domain,
|
||||
});
|
||||
var value = 0;
|
||||
if (kwargs.measure === '__count__') {
|
||||
value = records.length;
|
||||
} else {
|
||||
if (records.length) {
|
||||
value = _.pluck(records.records, kwargs.measure).reduce(function (a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
}
|
||||
totalValue += value;
|
||||
var initialValue = value;
|
||||
|
||||
var columns = [];
|
||||
var colStartDate = cohortStartDate.clone();
|
||||
if (kwargs.timeline === 'backward') {
|
||||
colStartDate = colStartDate.subtract(15, kwargs.interval);
|
||||
}
|
||||
for (var column = 0; column <= 15; column++) {
|
||||
if (!columnsAvg[column]) {
|
||||
columnsAvg[column] = {'percentage': 0, 'count': 0};
|
||||
}
|
||||
if (column !== 0) {
|
||||
colStartDate.add(1, kwargs.interval);
|
||||
}
|
||||
if (colStartDate > moment()) {
|
||||
columnsAvg[column]['percentage'] += 0;
|
||||
columnsAvg[column]['count'] += 0;
|
||||
columns.push({
|
||||
'value': '-',
|
||||
'churn_value': '-',
|
||||
'percentage': '',
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
var compareDate = colStartDate.format(displayFormats[kwargs.interval]);
|
||||
var colRecords = _.filter(records.records, function (record) {
|
||||
return record[kwargs.date_stop] && moment(record[kwargs.date_stop], 'YYYY-MM-DD').format(displayFormats[kwargs.interval]) == compareDate;
|
||||
});
|
||||
var colValue = 0;
|
||||
if (kwargs.measure === '__count__') {
|
||||
colValue = colRecords.length;
|
||||
} else {
|
||||
if (colRecords.length) {
|
||||
colValue = _.pluck(colRecords, kwargs.measure).reduce(function (a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (kwargs.timeline === 'backward' && column === 0) {
|
||||
colRecords = _.filter(records.records, function (record) {
|
||||
return record[kwargs.date_stop] && moment(record[kwargs.date_stop], 'YYYY-MM-DD') >= colStartDate;
|
||||
});
|
||||
if (kwargs.measure === '__count__') {
|
||||
initialValue = colRecords.length;
|
||||
} else {
|
||||
if (colRecords.length) {
|
||||
initialValue = _.pluck(colRecords, kwargs.measure).reduce(function (a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
}
|
||||
initialChurnValue = value - initialValue;
|
||||
}
|
||||
var previousValue = column === 0 ? initialValue : columns[column - 1]['value'];
|
||||
var remainingValue = previousValue - colValue;
|
||||
var previousChurnValue = column === 0 ? initialChurnValue : columns[column - 1]['churn_value'];
|
||||
var churnValue = colValue + previousChurnValue;
|
||||
var percentage = value ? parseFloat(remainingValue / value) : 0;
|
||||
if (kwargs.mode === 'churn') {
|
||||
percentage = 1 - percentage;
|
||||
}
|
||||
percentage = Number((100 * percentage).toFixed(1));
|
||||
columnsAvg[column]['percentage'] += percentage;
|
||||
columnsAvg[column]['count'] += 1;
|
||||
columns.push({
|
||||
'value': remainingValue,
|
||||
'churn_value': churnValue,
|
||||
'percentage': percentage,
|
||||
'domain': [],
|
||||
'period': compareDate,
|
||||
});
|
||||
}
|
||||
rows.push({
|
||||
'date': cohortStartDate.format(displayFormats[kwargs.interval]),
|
||||
'value': value,
|
||||
'domain': group.__domain,
|
||||
'columns': columns,
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.resolve({
|
||||
'rows': rows,
|
||||
'avg': {'avg_value': totalCount ? (totalValue / totalCount) : 0, 'columns_avg': columnsAvg},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user