' +
'',
});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_ungrouped'),
"should have classname 'o_kanban_ungrouped'");
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_test'),
"should have classname 'o_kanban_test'");
assert.strictEqual(kanban.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4,
"should have 4 records");
assert.strictEqual(kanban.$('.o_kanban_ghost').length, 6, "should have 6 ghosts");
assert.strictEqual(kanban.$('.o_kanban_record:contains(gnap)').length, 1,
"should contain gnap");
kanban.destroy();
});
QUnit.test('basic grouped rendering', function (assert) {
assert.expect(13);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
groupBy: ['bar'],
mockRPC: function (route, args) {
if (args.method === 'read_group') {
// the lazy option is important, so the server can fill in
// the empty groups
assert.ok(args.kwargs.lazy, "should use lazy read_group");
}
return this._super(route, args);
},
});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'),
"should have classname 'o_kanban_grouped'");
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_test'),
"should have classname 'o_kanban_test'");
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should contain " + 1 + " record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 3,
"column should contain " + 3 + " record(s)");
// check available actions in kanban header's config dropdown
assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_kanban_toggle_fold').length,
"should be able to fold the column");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive').length,
"should be not able to archive the records");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive').length,
"should be not able to restore the records");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_edit').length,
"should not be able to edit the column");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_delete').length,
"should not be able to delete the column");
// the next line makes sure that reload works properly. It looks useless,
// but it actually test that a grouped local record can be reloaded without
// changing its result.
kanban.reload();
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 3,
"column should contain " + 3 + " record(s)");
kanban.destroy();
});
QUnit.test('basic grouped rendering with active field', function (assert) {
assert.expect(6);
// add active field on partner model and make all records active
this.data.partner.fields.active = {string: 'Active', type: 'char', default: true};
var envIDs = [1, 2, 3, 4]; // the ids that should be in the environment during this test
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'' +
'
' +
'',
groupBy: ['bar'],
intercepts: {
env_updated: function (event) {
assert.deepEqual(event.data.ids, envIDs,
"should notify the environment with the correct ids");
},
},
});
// check available actions in kanban header's config dropdown
assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive').length,
"should be able to archive the records");
assert.ok(kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive').length,
"should be able to restore the records");
// archive the records of the first column
assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 3,
"last column should contain 3 records");
envIDs = [4];
kanban.$('.o_kanban_group:last .o_column_archive').click(); // click on 'Archive'
assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 0,
"last column should contain no record");
kanban.destroy();
});
QUnit.test('pager should be hidden in grouped mode', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
groupBy: ['bar'],
});
kanban.renderPager();
assert.ok(kanban.pager.$el.hasClass('o_hidden'),
"pager should be hidden in grouped kanban");
kanban.destroy();
});
QUnit.test('pager, ungrouped, with default limit', function (assert) {
assert.expect(3);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'',
mockRPC: function (route, args) {
assert.strictEqual(args.limit, 40, "default limit should be 40 in Kanban");
return this._super.apply(this, arguments);
},
});
assert.ok(!kanban.pager.$el.hasClass('o_hidden'),
"pager should be visible in ungrouped kanban");
assert.strictEqual(kanban.pager.state.size, 4, "pager's size should be 4");
kanban.destroy();
});
QUnit.test('pager, ungrouped, with limit given in options', function (assert) {
assert.expect(3);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'',
mockRPC: function (route, args) {
assert.strictEqual(args.limit, 2, "limit should be 2");
return this._super.apply(this, arguments);
},
viewOptions: {
limit: 2,
},
});
assert.strictEqual(kanban.pager.state.limit, 2, "pager's limit should be 2");
assert.strictEqual(kanban.pager.state.size, 4, "pager's size should be 4");
kanban.destroy();
});
QUnit.test('pager, ungrouped, with limit set on arch and given in options', function (assert) {
assert.expect(3);
// the limit given in the arch should take the priority over the one given in options
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'',
mockRPC: function (route, args) {
assert.strictEqual(args.limit, 3, "limit should be 3");
return this._super.apply(this, arguments);
},
viewOptions: {
limit: 2,
},
});
assert.strictEqual(kanban.pager.state.limit, 3, "pager's limit should be 3");
assert.strictEqual(kanban.pager.state.size, 4, "pager's size should be 4");
kanban.destroy();
});
QUnit.test('create in grouped on m2o', function (assert) {
assert.expect(5);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
});
kanban.renderButtons();
assert.ok(kanban.$('.o_kanban_view').hasClass('ui-sortable'),
"columns are sortable when grouped by a m2o field");
assert.ok(kanban.$buttons.find('.o-kanban-button-new').hasClass('btn-primary'),
"'create' button should be btn-primary for grouped kanban with at least one column");
assert.ok(kanban.$('.o_kanban_view > div:last').hasClass('o_column_quick_create'),
"column quick create should be enabled when grouped by a many2one field)");
kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create'
assert.ok(kanban.$('.o_kanban_group:first() > div:nth(1)').hasClass('o_kanban_quick_create'),
"clicking on create should open the quick_create in the first column");
assert.ok(kanban.$('span.o_column_title:contains(hello)').length,
"should have a column title with a value from the many2one");
kanban.destroy();
});
QUnit.test('create in grouped on char', function (assert) {
assert.expect(4);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'',
groupBy: ['foo'],
});
assert.ok(!kanban.$('.o_kanban_view').hasClass('ui-sortable'),
"columns aren't sortable when not grouped by a m2o field");
assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have " + 3 + " columns");
assert.strictEqual(kanban.$('.o_kanban_group:first() .o_column_title').text(), "yop",
"'yop' column should be the first column");
assert.ok(!kanban.$('.o_kanban_view > div:last').hasClass('o_column_quick_create'),
"column quick create should be disabled when not grouped by a many2one field)");
kanban.destroy();
});
QUnit.test('quick create and change state in grouped mode', function (assert) {
assert.expect(1);
this.data.partner.fields.kanban_state = {
string: "Kanban State",
type: "selection",
selection: [["normal", "Grey"], ["done", "Green"], ["blocked", "Red"]],
};
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'
' +
'' +
'
' +
'' +
'',
groupBy: ['foo'],
});
// Quick create kanban record
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
var $quickAdd = kanban.$('.o_kanban_quick_create');
$quickAdd.find('.o_input').val('Test');
$quickAdd.find('.o_kanban_add').click();
// Select state in kanban
kanban.$('.o_status').first().click();
kanban.$('.o_selection ul:first li:first').click();
assert.ok(kanban.$('.o_status').first().hasClass('o_status_green'),
"Kanban state should be done (Green)");
kanban.destroy();
});
QUnit.test('quick create in grouped mode', function (assert) {
assert.expect(8);
var nbRecords = 4;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
groupBy: ['bar'],
intercepts: {
env_updated: function (event) {
assert.strictEqual(event.data.ids.length, nbRecords,
"should update the env with the records ids");
},
}
});
// click to add an element and cancel the quick creation
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
var $quickCreate = kanban.$('.o_kanban_quick_create');
assert.strictEqual($quickCreate.length, 1, "should have a quick create element");
$quickCreate.find('input').trigger($.Event('keydown', {keyCode: $.ui.keyCode.ESCAPE}));
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0,
"should have destroyed the quick create element");
//click to add and element and focus out the blank input, should cancel the quick creation
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
$quickCreate = kanban.$('.o_kanban_quick_create');
$quickCreate.find('input').blur();
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0,
"Blur should have destroyed the quick create element");
// click to really add an element
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
$quickCreate = kanban.$('.o_kanban_quick_create');
$quickCreate.find('input').val('new partner');
$quickCreate.find('input').blur();
// When focus out the input containing value, should not delete the Quick Creation
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
"Blur should not have destroyed the quick create element");
nbRecords = 5;
$quickCreate.find('button.o_kanban_add').click();
assert.strictEqual(this.data.partner.records.length, 5,
"should have created a partner");
assert.strictEqual(_.last(this.data.partner.records).name, "new partner",
"should have correct name");
kanban.destroy();
});
QUnit.test('quick create and edit in grouped mode', function (assert) {
assert.expect(6);
var newRecordID;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
mockRPC: function (route, args) {
var def = this._super.apply(this, arguments);
if (args.method === 'name_create') {
def.then(function (result) {
newRecordID = result[0];
});
}
return def;
},
groupBy: ['bar'],
intercepts: {
switch_view: function (event) {
assert.strictEqual(event.data.mode, "edit",
"should trigger 'open_record' event in edit mode");
assert.strictEqual(event.data.res_id, newRecordID,
"should open the correct record");
},
},
});
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
"first column should contain one record");
// click to add and edit an element
var $quickCreate = kanban.$('.o_kanban_quick_create');
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
$quickCreate = kanban.$('.o_kanban_quick_create');
$quickCreate.find('input').val('new partner');
$quickCreate.find('button.o_kanban_edit').click();
assert.strictEqual(this.data.partner.records.length, 5,
"should have created a partner");
assert.strictEqual(_.last(this.data.partner.records).name, "new partner",
"should have correct name");
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
"first column should now contain two records");
kanban.destroy();
});
QUnit.test('quick create several records in a row', function (assert) {
assert.expect(6);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
groupBy: ['bar'],
});
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
"first column should contain one record");
// click to add an element, fill the input and press ENTER
kanban.$('.o_kanban_header .o_kanban_quick_add i').first().click();
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
"the quick create should be open");
kanban.$('.o_kanban_quick_create input')
.val('new partner 1')
.trigger($.Event('keypress', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
"first column should now contain two records");
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
"the quick create should still be open");
// create a second element in a row
kanban.$('.o_kanban_quick_create input')
.val('new partner 2')
.trigger($.Event('keypress', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3,
"first column should now contain three records");
assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 1,
"the quick create should still be open");
kanban.destroy();
});
QUnit.test('quick create fail in grouped', function (assert) {
assert.expect(7);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
archs: {
'partner,false,form': '
',
},
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (args.method === 'name_create') {
return $.Deferred().reject({
code: 200,
data: {},
message: "Flectra server error",
}, $.Event());
}
return this._super.apply(this, arguments);
},
});
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
"there should be 2 records in first column");
kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create'
assert.ok(kanban.$('.o_kanban_group:first() > div:nth(1)').hasClass('o_kanban_quick_create'),
"clicking on create should open the quick_create in the first column");
kanban.$('.o_kanban_quick_create input')
.val('test')
.trigger($.Event('keypress', {keyCode: $.ui.keyCode.ENTER}));
assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1,
"a form view dialog should have been opened (in edit)");
assert.strictEqual($('.modal .o_field_many2one input').val(), 'hello',
"the correct product_id should already be set");
// specify a name and save
$('.modal input[name=foo]').val('test').trigger('input');
$('.modal-footer .btn-primary').click();
assert.strictEqual($('.modal').length, 0, "the modal should be closed");
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 3,
"there should be 3 records in first column");
var $firstRecord = kanban.$('.o_kanban_group:first .o_kanban_record:first');
assert.strictEqual($firstRecord.text(), 'test',
"the first record of the first column should be the new one");
kanban.destroy();
});
QUnit.test('quick create record in empty grouped kanban', function (assert) {
assert.expect(3);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (args.method === 'read_group') {
// override read_group to return empty groups, as this is
// the case for several models (e.g. project.task grouped
// by stage_id)
var result = [
{__domain: [['product_id', '=', 3]], product_id_count: 0},
{__domain: [['product_id', '=', 5]], product_id_count: 0},
];
return $.when(result);
}
return this._super.apply(this, arguments);
},
});
assert.strictEqual(kanban.$('.o_kanban_group').length, 2,
"there should be 2 columns");
assert.strictEqual(kanban.$('.o_kanban_record').length, 0,
"both columns should be empty");
kanban.$buttons.find('.o-kanban-button-new').click();
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_quick_create').length, 1,
"should have opened the quick create in the first column");
kanban.destroy();
});
QUnit.test('many2many_tags in kanban views', function (assert) {
assert.expect(12);
this.data.partner.records[0].category_ids = [6, 7];
this.data.partner.records[1].category_ids = [7, 8];
this.data.category.records.push({
id: 8,
name: "hello",
color: 0,
});
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'' +
'' +
'
' +
'' +
'',
mockRPC: function (route) {
assert.step(route);
return this._super.apply(this, arguments);
},
intercepts: {
switch_view: function (event) {
assert.deepEqual(event.data, {
mode: 'readonly',
model: 'partner',
res_id: 1,
view_type: 'form',
}, "should trigger an event to open the clicked record in a form view");
},
},
});
var $first_record = kanban.$('.o_kanban_record:first()');
assert.strictEqual($first_record.find('.o_field_many2manytags .o_tag').length, 2,
'first record should contain 2 tags');
assert.ok($first_record.find('.o_tag:first()').hasClass('o_tag_color_2'),
'first tag should have color 2');
assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/category/read'],
'two RPC should have been done (one search read and one read for the m2m)');
// Checks that second records has only one tag as one should be hidden (color 0)
assert.strictEqual(kanban.$('.o_kanban_record').eq(1).find('.o_tag').length, 1,
'there should be only one tag in second record');
// Write on the record using the priority widget to trigger a re-render in readonly
kanban.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').first().click();
assert.verifySteps([
'/web/dataset/search_read',
'/web/dataset/call_kw/category/read',
'/web/dataset/call_kw/partner/write',
'/web/dataset/call_kw/partner/read',
'/web/dataset/call_kw/category/read'
], 'five RPCs should have been done (previous 2, 1 write (triggers a re-render), same 2 at re-render');
assert.strictEqual(kanban.$('.o_kanban_record:first()').find('.o_field_many2manytags .o_tag').length, 2,
'first record should still contain only 2 tags');
// click on a tag (should trigger switch_view)
kanban.$('.o_tag:contains(gold):first').click();
kanban.destroy();
});
QUnit.test('can drag and drop a record from one column to the next', function (assert) {
assert.expect(9);
var envIDs = [1, 3, 2, 4]; // the ids that should be in the environment during this test
this.data.partner.fields.sequence = {type: 'number', string: "Sequence"};
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'edit' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
assert.ok(true, "should call resequence");
return $.when(true);
}
return this._super(route, args);
},
intercepts: {
env_updated: function (event) {
assert.deepEqual(event.data.ids, envIDs,
"should notify the environment with the correct ids");
},
},
});
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 2,
"column should contain 2 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2,
"column should contain 2 record(s)");
assert.strictEqual(kanban.$('.thisiseditable').length, 4, "all records should be editable");
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
envIDs = [3, 2, 4, 1]; // first record of first column moved to the bottom of second column
testUtils.dragAndDrop($record, $group);
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should now contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 3,
"column should contain 3 record(s)");
assert.strictEqual(kanban.$('.thisiseditable').length, 4, "all records should be editable");
kanban.destroy();
});
QUnit.test('drag and drop a record, grouped by selection', function (assert) {
assert.expect(6);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'' +
'',
groupBy: ['state'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
assert.ok(true, "should call resequence");
return $.when(true);
}
if (args.model === 'partner' && args.method === 'write') {
assert.deepEqual(args.args[1], {state: 'def'});
}
return this._super(route, args);
},
});
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
testUtils.dragAndDrop($record, $group);
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 0,
"column should now contain 0 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2,
"column should contain 2 record(s)");
kanban.destroy();
});
QUnit.test('prevent drag and drop of record if grouped by readonly', function (assert) {
assert.expect(12);
this.data.partner.fields.foo.readonly = true;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'' +
'
' +
'' +
'',
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
return $.when();
}
if (args.model === 'partner' && args.method === 'write') {
throw new Error('should not be draggable');
}
return this._super(route, args);
},
});
// simulate an update coming from the searchview, with another groupby given
kanban.update({groupBy: ['state']});
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
// drag&drop a record in another column
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
testUtils.dragAndDrop($record, $group);
// should not be draggable
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should now contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
// simulate an update coming from the searchview, with another groupby given
kanban.update({groupBy: ['foo']});
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2,
"column should contain 2 record(s)");
// drag&drop a record in another column
$record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
$group = kanban.$('.o_kanban_group:nth-child(2)');
testUtils.dragAndDrop($record, $group);
// should not be draggable
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should now contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2,
"column should contain 2 record(s)");
// drag&drop a record in the same column
var $record1 = kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(0)');
var $record2 = kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(1)');
assert.strictEqual($record1.text(), "blipDEF", "first record should be DEF");
assert.strictEqual($record2.text(), "blipGHI", "second record should be GHI");
testUtils.dragAndDrop($record2, $record1, {position: 'top'});
// should still be able to resequence
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(0)').text(), "blipGHI",
"records should have been resequenced");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(1)').text(), "blipDEF",
"records should have been resequenced");
kanban.destroy();
});
QUnit.test('kanban view with default_group_by', function (assert) {
assert.expect(7);
this.data.partner.records.product_id = 1;
this.data.product.records.push({id: 1, display_name: "third product"});
var readGroupCount = 0;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/partner/read_group') {
readGroupCount++;
var correctGroupBy;
if (readGroupCount === 2) {
correctGroupBy = ['product_id'];
} else {
correctGroupBy = ['bar'];
}
// this is done three times
assert.ok(_.isEqual(args.kwargs.groupby, correctGroupBy),
"groupby args should be correct");
}
return this._super.apply(this, arguments);
},
});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'),
"should have classname 'o_kanban_grouped'");
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns");
// simulate an update coming from the searchview, with another groupby given
kanban.update({groupBy: ['product_id']});
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should now have " + 3 + " columns");
// simulate an update coming from the searchview, removing the previously set groupby
kanban.update({groupBy: []});
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns again");
kanban.destroy();
});
QUnit.test('kanban view with create=False', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'',
});
assert.ok(!kanban.$buttons || !kanban.$buttons.find('.o-kanban-button-new').length,
"Create button shouldn't be there");
kanban.destroy();
});
QUnit.test('clicking on a link triggers correct event', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'
' +
'',
});
testUtils.intercept(kanban, 'switch_view', function (event) {
assert.deepEqual(event.data, {
view_type: 'form',
res_id: 1,
mode: 'edit',
model: 'partner',
});
});
kanban.$('a').first().click();
kanban.destroy();
});
QUnit.test('environment is updated when (un)folding groups', function (assert) {
assert.expect(3);
var envIDs = [1, 3, 2, 4]; // the ids that should be in the environment during this test
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
intercepts: {
env_updated: function (event) {
assert.deepEqual(envIDs, event.data.ids,
"should notify the environment with the correct ids");
},
},
});
// fold the second group and check that the res_ids it contains are no
// longer in the environment
envIDs = [1, 3];
kanban.$('.o_kanban_group:last .o_kanban_toggle_fold').click();
// re-open the second group and check that the res_ids it contains are
// back in the environment
envIDs = [1, 3, 2, 4];
kanban.$('.o_kanban_group:last .o_kanban_toggle_fold').click();
kanban.destroy();
});
QUnit.test('create a column in grouped on m2o', function (assert) {
assert.expect(13);
var nbRPCs = 0;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route, args) {
nbRPCs++;
if (args.method === 'name_create') {
assert.ok(true, "should call name_create");
}
return this._super(route, args);
},
});
assert.strictEqual(kanban.$('.o_column_quick_create').length, 1, "should have a quick create column");
assert.notOk(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should not be visible");
kanban.$('.o_column_quick_create').click();
assert.ok(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should be visible");
// discard the column creation and click it again
kanban.$('.o_column_quick_create').click();
assert.notOk(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should not be visible after discard");
kanban.$('.o_column_quick_create').click();
assert.ok(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should be visible");
kanban.$('.o_column_quick_create input').val('new value');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new value)').length, 1,
"the last column should be the newly created one");
assert.ok(_.isNumber(kanban.$('.o_kanban_group:last').data('id')),
'the created column should have the correct id');
assert.ok(!kanban.$('.o_kanban_group:last').hasClass('o_column_folded'),
'the created column should not be folded');
// fold and unfold the created column, and check that no RPC is done (as there is no record)
nbRPCs = 0;
kanban.$('.o_kanban_group:last .o_kanban_toggle_fold').click(); // fold the group
assert.ok(kanban.$('.o_kanban_group:last').hasClass('o_column_folded'),
'the created column should now be folded');
kanban.$('.o_kanban_group:last').click();
assert.ok(!kanban.$('.o_kanban_group:last').hasClass('o_column_folded'),
'the created column should not be folded');
assert.strictEqual(nbRPCs, 0, 'no rpc should have been done when folding/unfolding');
// quick create a record
kanban.$buttons.find('.o-kanban-button-new').click(); // Click on 'Create'
assert.ok(kanban.$('.o_kanban_group:first() > div:nth(1)').hasClass('o_kanban_quick_create'),
"clicking on create should open the quick_create in the first column");
kanban.destroy();
});
QUnit.test('quick create record & column in grouped on m2o', function (assert) {
assert.expect(2);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
});
kanban.$('.o_kanban_group:first .o_kanban_quick_add').click();
var $quickCreate = kanban.$('.o_kanban_quick_create');
$quickCreate.find('input').val('new partner');
$quickCreate.find('button.o_kanban_add').click();
assert.strictEqual(this.data.partner.records.length, 5,
"should have created a partner");
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('new column');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new column)').length, 1,
"the last column should be the newly created one");
kanban.destroy();
});
QUnit.test('delete a column in grouped on m2o', function (assert) {
assert.expect(32);
testUtils.patch(KanbanRenderer, {
_renderGrouped: function () {
this._super.apply(this, arguments);
// set delay and revert animation time to 0 so dummy drag and drop works
if (this.$el.sortable('instance')) {
this.$el.sortable('option', {delay: 0, revert: 0});
}
},
});
var resequencedIDs;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
resequencedIDs = args.ids;
assert.strictEqual(_.reject(args.ids, _.isNumber).length, 0,
"column resequenced should be existing records with IDs");
return $.when(true);
}
if (args.method) {
assert.step(args.method);
}
return this._super(route, args);
},
});
// check the initial rendering
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have two columns");
assert.strictEqual(kanban.$('.o_kanban_group:first').data('id'), 3,
'first column should be [3, "hello"]');
assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 5,
'second column should be [5, "xmo"]');
assert.strictEqual(kanban.$('.o_kanban_group:last .o_column_title').text(), 'xmo',
'second column should have correct title');
assert.strictEqual(kanban.$('.o_kanban_group:last .o_kanban_record').length, 2,
"second column should have two records");
// check available actions in kanban header's config dropdown
assert.ok(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold').length,
"should be able to fold the column");
assert.ok(kanban.$('.o_kanban_group:first .o_column_edit').length,
"should be able to edit the column");
assert.ok(kanban.$('.o_kanban_group:first .o_column_delete').length,
"should be able to delete the column");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive').length,
"should not be able to archive the records");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive').length,
"should not be able to restore the records");
// delete second column (first cancel the confirm request, then confirm)
kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete
assert.ok($('.modal').length, 'a confirm modal should be displayed');
$('.modal .modal-footer .btn-default').click(); // click on cancel
assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 5,
'column [5, "xmo"] should still be there');
kanban.$('.o_kanban_group:last .o_column_delete').click(); // click on delete
assert.ok($('.modal').length, 'a confirm modal should be displayed');
$('.modal .modal-footer .btn-primary').click(); // click on confirm
assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 3,
'last column should now be [3, "hello"]');
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should still have two columns");
assert.ok(!_.isNumber(kanban.$('.o_kanban_group:first').data('id')),
'first column should have no id (Undefined column)');
// check available actions on 'Undefined' column
assert.ok(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold').length,
"should be able to fold the column");
assert.ok(!kanban.$('.o_kanban_group:first .o_column_delete').length,
'Undefined column could not be deleted');
assert.ok(!kanban.$('.o_kanban_group:first .o_column_edit').length,
'Undefined column could not be edited');
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_archive').length,
"should not be able to archive the records");
assert.ok(!kanban.$('.o_kanban_header:first .o_kanban_config .o_column_unarchive').length,
"should not be able to restore the records");
assert.verifySteps(['read_group', 'unlink', 'read_group']);
assert.strictEqual(kanban.renderer.widgets.length, 2,
"the old widgets should have been correctly deleted");
// test column drag and drop having an 'Undefined' column
testUtils.dragAndDrop(
kanban.$('.o_kanban_header_title:first'),
kanban.$('.o_kanban_header_title:last'), {position: 'right'}
);
assert.strictEqual(resequencedIDs, undefined,
"resequencing require at least 2 not Undefined columns");
kanban.$('.o_column_quick_create input').val('once third column');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
var newColumnID = kanban.$('.o_kanban_group:last').data('id');
testUtils.dragAndDrop(
kanban.$('.o_kanban_header_title:first'),
kanban.$('.o_kanban_header_title:last'), {position: 'right'}
);
assert.deepEqual([3, newColumnID], resequencedIDs,
"moving the Undefined column should not affect order of other columns")
testUtils.dragAndDrop(
kanban.$('.o_kanban_header_title:first'),
kanban.$('.o_kanban_header_title:nth(1)'), {position: 'right'}
);
assert.deepEqual([newColumnID, 3], resequencedIDs,
"moved column should be resequenced accordingly")
kanban.destroy();
testUtils.unpatch(KanbanRenderer);
});
QUnit.test('create a column, delete it and create another one', function (assert) {
assert.expect(5);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
});
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have two columns");
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('new column 1');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have two columns");
kanban.$('.o_kanban_group:last .o_column_delete').click();
$('.modal .modal-footer .btn-primary').click();
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have twos columns");
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('new column 2');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have three columns");
assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new column 2)').length, 1,
"the last column should be the newly created one");
kanban.destroy();
});
QUnit.test('edit a column in grouped on m2o', function (assert) {
assert.expect(12);
var nbRPCs = 0;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
archs: {
'product,false,form': '',
},
mockRPC: function (route, args) {
nbRPCs++;
return this._super(route, args);
},
});
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo',
'title of the column should be "xmo"');
// edit the title of column [5, 'xmo'] and close without saving
kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit'
assert.ok($('.modal .o_form_editable').length, 'a form view should be open in a modal');
assert.strictEqual($('.modal .o_form_editable input').val(), 'xmo',
'the name should be "xmo"');
$('.modal .o_form_editable input').val('ged').trigger('input'); // change the value
nbRPCs = 0;
$('.modal .modal-header .close').click(); // click on the cross to close the modal
assert.ok(!$('.modal').length, 'the modal should be closed');
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo',
'title of the column should still be "xmo"');
assert.strictEqual(nbRPCs, 0, 'no RPC should have been done');
// edit the title of column [5, 'xmo'] and discard
kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit'
$('.modal .o_form_editable input').val('ged').trigger('input'); // change the value
nbRPCs = 0;
$('.modal .modal-footer .btn-default').click(); // click on discard
assert.ok(!$('.modal').length, 'the modal should be closed');
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo',
'title of the column should still be "xmo"');
assert.strictEqual(nbRPCs, 0, 'no RPC should have been done');
// edit the title of column [5, 'xmo'] and save
kanban.$('.o_kanban_group[data-id=5] .o_column_edit').click(); // click on 'Edit'
$('.modal .o_form_editable input').val('ged').trigger('input'); // change the value
nbRPCs = 0;
$('.modal .modal-footer .btn-primary').click(); // click on save
assert.ok(!$('.modal').length, 'the modal should be closed');
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'ged',
'title of the column should be "ged"');
assert.strictEqual(nbRPCs, 4, 'should have done 1 write, 1 read_group and 2 search_read');
kanban.destroy();
});
QUnit.test('if view was grouped at start, it stays grouped', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
});
kanban.update({groupBy: []});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'));
kanban.destroy();
});
QUnit.test('if view was not grouped at start, it can be grouped and ungrouped', function (assert) {
assert.expect(3);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
});
assert.notOk(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), "should not be grouped");
kanban.update({groupBy: ['product_id']});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), "should be grouped");
kanban.update({groupBy: []});
assert.notOk(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'), "should not be grouped");
kanban.destroy();
});
QUnit.test('no content helper when no data', function (assert) {
assert.expect(5);
var records = this.data.partner.records;
this.data.partner.records = [];
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'
' +
'' +
'' +
'
' +
'',
viewOptions: {
action: {
help: '
click to add a partner
'
}
},
});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_nocontent'),
"$el should have correct no content class");
assert.strictEqual(kanban.$('.oe_view_nocontent').length, 1,
"should display the no content helper");
assert.strictEqual(kanban.$('.oe_view_nocontent p.hello:contains(add a partner)').length, 1,
"should have rendered no content helper from action");
this.data.partner.records = records;
kanban.reload();
assert.notOk(kanban.$el.hasClass('o_kanban_nocontent'),
"$el should have removed no content class");
assert.strictEqual(kanban.$('.oe_view_nocontent').length, 0,
"should not display the no content helper");
kanban.destroy();
});
QUnit.test('no nocontent helper for grouped kanban with empty groups', function (assert) {
assert.expect(2);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (args.method === 'read_group') {
// override read_group to return empty groups, as this is
// the case for several models (e.g. project.task grouped
// by stage_id)
return this._super.apply(this, arguments).then(function (result) {
_.each(result, function (group) {
group[args.kwargs.groupby[0] + '_count'] = 0;
});
return result;
});
}
return this._super.apply(this, arguments);
},
viewOptions: {
action: {
help: "No content helper",
},
},
});
assert.strictEqual(kanban.$('.o_kanban_group').length, 2,
"there should be two columns");
assert.strictEqual(kanban.$('.o_kanban_record').length, 0,
"there should be no records");
kanban.destroy();
});
QUnit.test('no nocontent helper for grouped kanban with no records', function (assert) {
assert.expect(4);
this.data.partner.records = [];
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
viewOptions: {
action: {
help: "No content helper",
},
},
});
assert.strictEqual(kanban.$('.o_kanban_group').length, 0,
"there should be no columns");
assert.strictEqual(kanban.$('.o_kanban_record').length, 0,
"there should be no records");
assert.strictEqual(kanban.$('.oe_view_nocontent').length, 0,
"there should be no nocontent helper");
assert.strictEqual(kanban.$('.o_column_quick_create').length, 1,
"there should be a column quick create");
kanban.destroy();
});
QUnit.test('nocontent helper for grouped kanban with no records with no group_create', function (assert) {
assert.expect(4);
this.data.partner.records = [];
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
viewOptions: {
action: {
help: "No content helper",
},
},
});
assert.strictEqual(kanban.$('.o_kanban_group').length, 0,
"there should be no columns");
assert.strictEqual(kanban.$('.o_kanban_record').length, 0,
"there should be no records");
assert.strictEqual(kanban.$('.oe_view_nocontent').length, 1,
"there should be a nocontent helper");
assert.strictEqual(kanban.$('.o_column_quick_create').length, 0,
"there should not be a column quick create");
kanban.destroy();
});
QUnit.test('buttons with modifiers', function (assert) {
assert.expect(2);
this.data.partner.records[1].bar = false; // so that test is more complete
var kanban = createView({
View: KanbanView,
model: "partner",
data: this.data,
arch:
'' +
'' +
'' +
'' +
'
' +
'' +
'' +
'
' +
'',
});
assert.strictEqual(kanban.$(".o_btn_test_1").length, 1,
"kanban should have one buttons of type 1");
assert.strictEqual(kanban.$(".o_btn_test_2").length, 3,
"kanban should have three buttons of type 2");
kanban.destroy();
});
QUnit.test('button executes action and reloads', function (assert) {
assert.expect(6);
var kanban = createView({
View: KanbanView,
model: "partner",
data: this.data,
arch:
'' +
'
' +
'' +
'' +
'
' +
'',
mockRPC: function (route) {
assert.step(route);
return this._super.apply(this, arguments);
},
});
assert.ok(kanban.$('button[data-name="a1"]').length,
"kanban should have at least one button a1");
var count = 0;
testUtils.intercept(kanban, 'execute_action', function (event) {
count++;
event.data.on_closed();
});
$('button[data-name="a1"]').first().click();
assert.strictEqual(count, 1, "should have triggered a execute action");
$('button[data-name="a1"]').first().click();
assert.strictEqual(count, 1, "double-click on kanban actions should be debounced");
assert.verifySteps([
'/web/dataset/search_read',
'/web/dataset/call_kw/partner/read'
], 'a read should be done after the call button to reload the record');
kanban.destroy();
});
QUnit.test('rendering date and datetime', function (assert) {
assert.expect(2);
this.data.partner.records[0].date = "2017-01-25";
this.data.partner.records[1].datetime= "2016-12-12 10:55:05";
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'' +
'
' +
'' +
'' +
'
' +
'' +
'',
});
// FIXME: this test is locale dependant. we need to do it right.
assert.strictEqual(kanban.$('div.o_kanban_record:contains(Wed Jan 25)').length, 1,
"should have formatted the date");
assert.strictEqual(kanban.$('div.o_kanban_record:contains(Mon Dec 12)').length, 1,
"should have formatted the datetime");
kanban.destroy();
});
QUnit.test('evaluate conditions on relational fields', function (assert) {
assert.expect(3);
this.data.partner.records[0].product_id = false;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'' +
'
' +
'' +
'' +
'
' +
'' +
'',
});
assert.strictEqual($('.o_kanban_record:not(.o_kanban_ghost)').length, 4,
"there should be 4 records");
assert.strictEqual($('.o_kanban_record:not(.o_kanban_ghost) .btn_a').length, 1,
"only 1 of them should have the 'Action' button");
assert.strictEqual($('.o_kanban_record:not(.o_kanban_ghost) .btn_b').length, 2,
"only 2 of them should have the 'Action' button");
kanban.destroy();
});
QUnit.test('resequence columns in grouped by m2o', function (assert) {
assert.expect(7);
var envIDs = [1, 3, 2, 4]; // the ids that should be in the environment during this test
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route) {
if (route === '/web/dataset/resequence') {
return $.when();
}
return this._super.apply(this, arguments);
},
intercepts: {
env_updated: function (event) {
assert.deepEqual(event.data.ids, envIDs,
"should notify the environment with the correct ids");
},
},
});
assert.ok(kanban.$('.o_kanban_view').hasClass('ui-sortable'),
"columns should be sortable");
assert.strictEqual(kanban.$('.o_kanban_group').length, 2,
"should have two columns");
assert.strictEqual(kanban.$('.o_kanban_group:first').data('id'), 3,
"first column should be id 3 before resequencing");
// there is a 100ms delay on the d&d feature (jquery sortable) for
// kanban columns, making it hard to test. So we rather bypass the d&d
// for this test, and directly call the event handler
envIDs = [2, 4, 1, 3]; // the columns will be inverted
kanban._onResequenceColumn({data: {ids: [5, 3]}});
kanban.update({}, {reload: false}); // re-render without reloading
assert.strictEqual(kanban.$('.o_kanban_group:first').data('id'), 5,
"first column should be id 5 before resequencing");
kanban.destroy();
});
QUnit.test('properly evaluate more complex domains', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'' +
'' +
'' +
'
' +
'' +
'' +
'
' +
'' +
'' +
'',
});
assert.strictEqual(kanban.$('button.oe_kanban_action_button').length, 1,
"only one button should be visible");
kanban.destroy();
});
QUnit.test('edit the kanban color with the colorpicker', function (assert) {
assert.expect(5);
var writeOnColor;
this.data.category.records[0].color = 12;
var kanban = createView({
View: KanbanView,
model: 'category',
data: this.data,
arch: '' +
'' +
'' +
'' +
'
' +
'' +
'' +
'',
mockRPC: function (route, args) {
if (args.method === 'write' && 'color' in args.args[1]) {
writeOnColor = true;
}
return this._super.apply(this, arguments);
},
});
var $firstRecord = kanban.$('.o_kanban_record:first()');
assert.strictEqual(kanban.$('.o_kanban_record.oe_kanban_color_12').length, 0,
"no record should have the color 12");
assert.strictEqual($firstRecord.find('.oe_kanban_colorpicker').length, 1,
"there should be a color picker");
assert.strictEqual($firstRecord.find('.oe_kanban_colorpicker').children().length, 12,
"the color picker should have 12 children (the colors)");
// Set a color
$firstRecord.find('.oe_kanban_colorpicker a.oe_kanban_color_9').click();
assert.ok(writeOnColor, "should write on the color field");
$firstRecord = kanban.$('.o_kanban_record:first()'); // First record is reloaded here
assert.ok($firstRecord.is('.oe_kanban_color_9'),
"the first record should have the color 9");
kanban.destroy();
});
QUnit.test('archive kanban column, when active field is not in the view', function (assert) {
assert.expect(3);
this.data.partner.fields.active = {string: 'Active', type: 'char', default: true};
var writeOnActive;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (args.method === 'write' && 'active' in args.args[1]) {
writeOnActive = true;
}
return this._super.apply(this, arguments);
},
});
var $first_column = kanban.$('.o_kanban_group:first()');
assert.strictEqual($first_column.find('.o_kanban_record').length, 2,
"there should be 2 partners in first column");
$first_column.find('.o_column_archive').click();
assert.ok(writeOnActive, "should write on the active field");
assert.strictEqual($first_column.find('.o_kanban_record').length, 0,
"there should not be partners anymore");
kanban.destroy();
});
QUnit.test('load more records in column', function (assert) {
assert.expect(12);
var envIDs = [1, 2, 4]; // the ids that should be in the environment during this test
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'',
groupBy: ['bar'],
viewOptions: {
limit: 2,
},
mockRPC: function (route, args) {
if (route === '/web/dataset/search_read') {
assert.step([args.limit, args.offset]);
}
return this._super.apply(this, arguments);
},
intercepts:{
env_updated: function (event) {
assert.deepEqual(event.data.ids, envIDs,
"should notify the environment with the correct ids");
},
},
});
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 2,
"there should be 2 records in the column");
// load more
envIDs = [1, 2, 3, 4]; // id 3 will be loaded
kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more').click();
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3,
"there should now be 3 records in the column");
assert.verifySteps([[2, undefined], [2, undefined], [2, 2]],
"the records should be correctly fetched");
// reload
envIDs = [1, 2, 4]; // first group is limited again to 2 records
kanban.reload();
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 2,
"there should be 2 records in the column after reload");
kanban.destroy();
});
QUnit.test('load more records in column with x2many', function (assert) {
assert.expect(10);
this.data.partner.records[0].category_ids = [7];
this.data.partner.records[1].category_ids = [];
this.data.partner.records[2].category_ids = [6];
this.data.partner.records[3].category_ids = [];
// record [2] will be loaded after
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['bar'],
viewOptions: {
limit: 2,
},
mockRPC: function (route, args) {
if (args.model === 'category' && args.method === 'read') {
assert.step(args.args[0]);
}
if (route === '/web/dataset/search_read') {
if (args.limit) {
assert.strictEqual(args.limit, 2,
"the limit should be correctly set");
}
if (args.offset) {
assert.strictEqual(args.offset, 2,
"the offset should be correctly set at load more");
}
}
return this._super.apply(this, arguments);
},
});
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 2,
"there should be 2 records in the column");
assert.verifySteps([[7]], "only the appearing category should be fetched");
// load more
kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more').click();
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3,
"there should now be 3 records in the column");
assert.verifySteps([[7], [6]], "the other categories should not be fetched");
kanban.destroy();
});
QUnit.test('update buttons after column creation', function (assert) {
assert.expect(2);
this.data.partner.records = [];
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'
' +
'',
groupBy: ['product_id'],
});
assert.ok(kanban.$buttons.find('.o-kanban-button-new').hasClass('btn-default'),
"Create button shouldn't be highlighted");
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('new column');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
assert.ok(kanban.$buttons.find('.o-kanban-button-new').hasClass('btn-primary'),
"Create button should now be highlighted");
kanban.destroy();
});
QUnit.test('group_by_tooltip option when grouping on a many2one', function (assert) {
assert.expect(12);
delete this.data.partner.records[3].product_id;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'' +
'
' +
'',
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/read') {
assert.strictEqual(args.args[0].length, 2,
"read on two groups");
assert.deepEqual(args.args[1], ['display_name', 'name'],
"should read on specified fields on the group by relation");
}
return this._super.apply(this, arguments);
},
});
assert.ok(kanban.$('.o_kanban_view').hasClass('o_kanban_grouped'),
"should have classname 'o_kanban_grouped'");
assert.strictEqual(kanban.$('.o_kanban_group').length, 2, "should have " + 2 + " columns");
// simulate an update coming from the searchview, with another groupby given
kanban.update({groupBy: ['product_id']});
assert.strictEqual(kanban.$('.o_kanban_group').length, 3, "should have " + 3 + " columns");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record').length, 2,
"column should contain 2 record(s)");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(3) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
assert.ok(kanban.$('.o_kanban_group:first span.o_column_title:contains(Undefined)').length,
"first column should have a default title for when no value is provided");
assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_header_title').data('original-title'),
"
1 records
",
"first column should have a tooltip with the number of records, but not" +
"the group_by_tooltip title and the many2one field value since it has no value");
assert.ok(kanban.$('.o_kanban_group:eq(1) span.o_column_title:contains(hello)').length,
"second column should have a title with a value from the many2one");
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_header_title').data('original-title'),
"
2 records
Kikou hello
",
"second column should have a tooltip with the number of records, the group_by_tooltip title and many2one field value");
kanban.destroy();
});
QUnit.test('move a record then put it again in the same column', function (assert) {
assert.expect(6);
this.data.partner.records = [];
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
groupBy: ['product_id'],
});
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('column1');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('column2');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_add i').click();
var $quickCreate = kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_create');
$quickCreate.find('input').val('new partner');
$quickCreate.find('button.o_kanban_add').click();
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 0,
"column should contain 0 record");
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 1,
"column should contain 1 records");
var $record = kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(0)');
var $group = kanban.$('.o_kanban_group:eq(0)');
testUtils.dragAndDrop($record, $group);
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 1,
"column should contain 1 records");
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 0,
"column should contain 0 records");
$record = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)');
$group = kanban.$('.o_kanban_group:eq(1)');
testUtils.dragAndDrop($record, $group);
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 0,
"column should contain 0 records");
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 1,
"column should contain 1 records");
kanban.destroy();
});
QUnit.test('resequence a record twice', function (assert) {
assert.expect(10);
this.data.partner.records = [];
var nbResequence = 0;
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'',
groupBy: ['product_id'],
mockRPC: function (route) {
if (route === '/web/dataset/resequence') {
nbResequence++;
return $.when();
}
return this._super.apply(this, arguments);
},
});
kanban.$('.o_column_quick_create').click();
kanban.$('.o_column_quick_create input').val('column1');
kanban.$('.o_column_quick_create button.o_kanban_add').click();
kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i').click();
var $quickCreate = kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_create');
$quickCreate.find('input').val('record1');
$quickCreate.find('button.o_kanban_add').click();
kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i').click();
$quickCreate = kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_create');
$quickCreate.find('input').val('record2');
$quickCreate.find('button.o_kanban_add').click();
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2,
"column should contain 2 records");
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)').text(), "record2",
"records should be correctly ordered");
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)').text(), "record1",
"records should be correctly ordered");
var $record1 = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)');
var $record2 = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)');
testUtils.dragAndDrop($record1, $record2, {position: 'top'});
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2,
"column should contain 2 records");
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)').text(), "record1",
"records should be correctly ordered");
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)').text(), "record2",
"records should be correctly ordered");
testUtils.dragAndDrop($record2, $record1, {position: 'top'});
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2,
"column should contain 2 records");
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)').text(), "record2",
"records should be correctly ordered");
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)').text(), "record1",
"records should be correctly ordered");
assert.strictEqual(nbResequence, 2, "should have resequenced twice");
kanban.destroy();
});
QUnit.test('don\'t fold column quick create after creation', function (assert) {
assert.expect(2);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
});
// add a new column
kanban.$('.o_kanban_group:first .o_kanban_quick_add').click();
var $quickCreate = kanban.$('.o_kanban_quick_create');
$quickCreate.find('input').val('new partner');
$quickCreate.find('button.o_kanban_add').click();
assert.strictEqual(this.data.partner.records.length, 5,
"should have created a 'new partner' column");
assert.strictEqual(kanban.$('.o_kanban_add:visible').length, 1,
"the add button should still be visible");
kanban.destroy();
});
QUnit.test('basic support for widgets', function (assert) {
assert.expect(1);
var MyWidget = Widget.extend({
init: function (parent, dataPoint) {
this.data = dataPoint.data;
},
start: function () {
this.$el.text(JSON.stringify(this.data));
},
});
widgetRegistry.add('test', MyWidget);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch: '' +
'
' +
'' +
'' +
'' +
'
' +
'',
});
assert.strictEqual(kanban.$('.o_widget:eq(2)').text(), '{"foo":"gnap","id":3}',
"widget should have been instantiated");
kanban.destroy();
delete widgetRegistry.map.test;
});
QUnit.test('column progressbars properly work', function (assert) {
assert.expect(2);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch:
'' +
'' +
'' +
'' +
'' +
'
' +
'' +
'
' +
'' +
'',
groupBy: ['bar'],
});
assert.strictEqual(kanban.$('.o_kanban_counter').length, this.data.product.records.length,
"kanban counters should have been created");
assert.strictEqual(parseInt(kanban.$('.o_kanban_counter_side').last().text()), 36,
"counter should display the sum of int_field values");
kanban.destroy();
});
QUnit.test('column progressbars: creating a new column should create a new progressbar', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch:
'' +
'' +
'' +
'' +
'
' +
'' +
'
' +
'' +
'',
groupBy: ['product_id'],
});
var nbProgressBars = kanban.$('.o_kanban_counter').length;
// Create a new column: this should create an empty progressbar
var $columnQuickCreate = kanban.$('.o_column_quick_create');
$columnQuickCreate.click();
$columnQuickCreate.find('input').val('test');
$columnQuickCreate.find('.btn-primary').click();
assert.strictEqual(kanban.$('.o_kanban_counter').length, nbProgressBars + 1,
"a new column with a new column progressbar should have been created");
kanban.destroy();
});
QUnit.test('column progressbars on quick create properly update counter', function (assert) {
assert.expect(1);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch:
'' +
'' +
'' +
'
' +
'' +
'
' +
'' +
'',
groupBy: ['bar'],
});
var initialCount = parseInt(kanban.$('.o_kanban_counter_side').eq(1).text());
kanban.$('.o_kanban_quick_add').eq(1).click();
kanban.$('.o_input').val('Test');
kanban.$('.o_kanban_add').click();
var lastCount = parseInt(kanban.$('.o_kanban_counter_side').eq(1).text());
assert.strictEqual(lastCount, initialCount + 1,
"kanban counters should have updated on quick create");
kanban.destroy();
});
QUnit.test('keep adding quickcreate in first column after a record from this column was moved', function (assert) {
assert.expect(2);
var kanban = createView({
View: KanbanView,
model: 'partner',
data: this.data,
arch:
'' +
'' +
'' +
'
' +
'' +
'',
groupBy: ['int_field'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
return $.when(true);
}
return this._super(route, args);
},
});
var $quickCreateGroup;
var $groups;
_quickCreateAndTest();
testUtils.dragAndDrop($groups.first().find('.o_kanban_record:first'), $groups.eq(1));
_quickCreateAndTest();
kanban.destroy();
function _quickCreateAndTest() {
kanban.$buttons.find('.o-kanban-button-new').click();
$quickCreateGroup = kanban.$('.o_kanban_quick_create').closest('.o_kanban_group');
$groups = kanban.$('.o_kanban_group');
assert.strictEqual($quickCreateGroup[0], $groups[0],
"quick create should have been added in the first column");
}
});
});
});