summaryrefslogtreecommitdiff
path: root/addons/web/static/tests
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-10-22 15:39:05 +0200
committerChristophe Simonis <chs@odoo.com>2018-10-22 16:59:51 +0200
commitb81c2bce846c94b5695d680ebbc30f1cfe51e614 (patch)
tree385190eb54adfbcdf8ff437d2cc667ddd1013718 /addons/web/static/tests
parent933165ec3afa0676de4b2f3662c4c1bb2f97efc5 (diff)
parent3c108977c1e7d9361894c38bcd253030e8097479 (diff)
[MERGE] forward port branch saas-11.4 up to 3c108977c1e
Diffstat (limited to 'addons/web/static/tests')
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js110
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js130
-rw-r--r--addons/web/static/tests/helpers/mock_server.js4
-rw-r--r--addons/web/static/tests/helpers/test_utils.js6
-rw-r--r--addons/web/static/tests/services/notification_service_tests.js34
-rw-r--r--addons/web/static/tests/views/kanban_model_tests.js7
-rw-r--r--addons/web/static/tests/views/kanban_tests.js516
-rw-r--r--addons/web/static/tests/views/list_tests.js24
8 files changed, 803 insertions, 28 deletions
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index 7db578b5d4e..81c21cf6052 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -10,6 +10,7 @@ var KanbanView = require('web.KanbanView');
var ListView = require('web.ListView');
var session = require('web.session');
var testUtils = require('web.test_utils');
+var field_registry = require('web.field_registry');
var createView = testUtils.createView;
var createAsyncView = testUtils.createAsyncView;
@@ -1907,6 +1908,49 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test("pdf_viewer: upload rendering", function (assert) {
+ assert.expect(6);
+
+ testUtils.patch(field_registry.map.pdf_viewer, {
+ on_file_change: function (ev) {
+ ev.target = {files: [new Blob()]};
+ this._super.apply(this, arguments);
+ },
+ _getURI: function (fileURI) {
+ var res = this._super.apply(this, arguments);
+ assert.step('_getURI');
+ assert.ok(_.str.startsWith(fileURI, 'blob:'));
+ this.PDFViewerApplication = {
+ open: function (URI) {
+ assert.step('open');
+ assert.ok(_.str.startsWith(URI, 'blob:'));
+ },
+ };
+ return 'about:blank';
+ },
+ });
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:
+ '<form>' +
+ '<field name="document" widget="pdf_viewer"/>' +
+ '</form>',
+ });
+
+ // first upload initialize iframe
+ form.$('input[type="file"]').trigger('change');
+ assert.verifySteps(['_getURI']);
+ // second upload call pdfjs method inside iframe
+ form.$('input[type="file"]').trigger('change');
+ assert.verifySteps(['_getURI', 'open']);
+
+ testUtils.unpatch(field_registry.map.pdf_viewer);
+ form.destroy();
+ });
+
QUnit.test('text field rendering in list view', function (assert) {
assert.expect(1);
@@ -2106,6 +2150,40 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('image fields in x2many list are loaded correctly', function (assert) {
+ assert.expect(2);
+
+ this.data.partner_type.fields.image = {name: 'image', type: 'binary'};
+ this.data.partner_type.records[0].image = 'product_image';
+ this.data.partner.records[0].timmy = [12];
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="timmy" widget="many2many">' +
+ '<tree>' +
+ '<field name="image" widget="image"/>' +
+ '</tree>' +
+ '</field>' +
+ '</form>',
+ res_id: 1,
+ mockRPC: function (route, args) {
+ if (route === 'data:image/png;base64,product_image') {
+ assert.ok(true, "The list's image should have been fetched");
+ return $.when();
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(form.$('tr.o_data_row').length, 1,
+ 'There should be one record in the many2many');
+
+ form.destroy();
+ });
+
QUnit.test('image fields with required attribute', function (assert) {
assert.expect(2);
@@ -2779,8 +2857,7 @@ QUnit.module('basic_fields', {
form.$buttons.find('.o_form_button_edit').click();
assert.strictEqual(form.$('.o_datepicker_input').val(), expectedDateString,
'the datetime should be correct in edit mode');
- // click on the input and select 22 February at 8:23:33
- form.$('.o_datepicker_input').click();
+ // select 22 February at 8:23:33
assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open');
$('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection
$('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection
@@ -2900,8 +2977,7 @@ QUnit.module('basic_fields', {
assert.strictEqual(list.$('input.o_datepicker_input').val(), expectedDateString,
'the date should be correct in edit mode');
- // click on the input and select 22 February at 8:23:33
- list.$('input.o_datepicker_input').click();
+ // select 22 February at 8:23:33
assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open');
$('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Month selection
$('.bootstrap-datetimepicker-widget .picker-switch').first().click(); // Year selection
@@ -3061,6 +3137,32 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('datepicker option: daysOfWeekDisabled', function (assert) {
+ assert.expect(2);
+
+ this.data.partner.fields.datetime.default = "2017-08-02 12:00:05";
+ this.data.partner.fields.datetime.required = true;
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<field name="datetime" ' +
+ 'options=\'{"datepicker": {"daysOfWeekDisabled": [0, 6]}}\'/>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ form.$buttons.find('.o_form_button_create').click();
+ assert.ok($('.day:last-child(),.day:nth-child(2)').hasClass('disabled'),
+ 'first and last days must be disabled');
+ assert.notOk($('.day:not(:last-child()):not(:nth-child(2))').hasClass('disabled'),
+ 'other days must stay clickable');
+
+ form.destroy();
+ });
+
QUnit.module('FieldMonetary');
QUnit.test('monetary field in form view', function (assert) {
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index 99f97fbda54..e1e91863448 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -5580,7 +5580,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('pressing enter in a o2m with a required empty m2o', function (assert) {
+ QUnit.test('pressing enter in a o2m with a required empty field', function (assert) {
assert.expect(4);
this.data.turtle.fields.turtle_foo.required = true;
@@ -10259,6 +10259,81 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('click on URL should not open the record', function (assert) {
+ assert.expect(2);
+
+ this.data.partner.records[0].turtles = [1];
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<field name="turtles">' +
+ '<tree>' +
+ '<field name="display_name" widget="email"/>' +
+ '<field name="turtle_foo" widget="url"/>' +
+ '</tree>' +
+ '<form></form>' +
+ '</field>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ form.$('.o_email_cell a').click();
+ assert.strictEqual($('.modal .o_form_view').length, 0,
+ 'click should not open the modal');
+
+ form.$('.o_url_cell a').click();
+ assert.strictEqual($('.modal .o_form_view').length, 0,
+ 'click should not open the modal');
+ form.destroy();
+ });
+
+ QUnit.test('create and edit on m2o in o2m, and press ESCAPE', function (assert) {
+ assert.expect(4);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<field name="turtles">' +
+ '<tree editable="top">' +
+ '<field name="turtle_trululu"/>' +
+ '</tree>' +
+ '</field>' +
+ '</form>',
+ archs: {
+ 'partner,false,form': '<form><field name="display_name"/></form>',
+ },
+ });
+
+ form.$('.o_field_x2many_list_row_add a').click();
+
+ assert.strictEqual(form.$('.o_selected_row').length, 1,
+ "should have create a new row in edition");
+
+ var $input = form.$('.o_field_widget[name="turtle_trululu"] input');
+ $input.click();
+ $input.autocomplete('widget').find('.o_m2o_dropdown_option').focus().click();
+
+ assert.strictEqual($('.modal .o_form_view').length, 1,
+ "should have opened a form view in a dialog");
+
+ $('.modal .o_form_view .o_field_widget[name=display_name]').trigger($.Event('keydown', {
+ which: $.ui.keyCode.ESCAPE,
+ keyCode: $.ui.keyCode.ESCAPE,
+ }));
+
+ assert.strictEqual($('.modal .o_form_view').length, 0,
+ "should have closed the dialog");
+ assert.strictEqual(form.$('.o_selected_row').length, 1,
+ "new row should still be present");
+
+ form.destroy();
+ });
+
QUnit.test('one2many add a line should not crash if orderedResIDs is not set', function (assert) {
// There is no assertion, the code will just crash before the bugfix.
assert.expect(0);
@@ -13679,6 +13754,59 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('when creating a new many2one on a x2many then discarding it immediately with ESCAPE, it should not crash', function (assert) {
+ var done = assert.async();
+ assert.expect(1);
+
+ this.data.partner.records[0].turtles = [];
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ viewOptions: {
+ mode: 'edit',
+ },
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<sheet>' +
+ '<field name="turtles">' +
+ '<tree editable="top">' +
+ '<field name="turtle_foo"/>' +
+ '<field name="turtle_trululu"/>' +
+ '</tree>' +
+ '</field>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ archs: {
+ 'partner,false,form': '<form><group><field name="foo"/><field name="bar"/></group></form>'
+ },
+ });
+
+ // add a new line
+ form.$el.find('.o_field_x2many_list_row_add>a').click();
+
+ // open the field turtle_trululu (one2many)
+ var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
+ form.$el.find('.o_input_dropdown>input').click();
+
+ concurrency.delay(0).then(function () {
+ // click create and edit
+ $('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter').click();
+
+ // hit escape immediately
+ var escapeKey = $.ui.keyCode.ESCAPE;
+ $(document.activeElement).trigger(
+ $.Event('keydown', {which: escapeKey, keyCode: escapeKey}));
+
+ assert.ok('did not crash');
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
+ form.destroy();
+ done();
+ });
+ });
+
QUnit.test('navigating through an editable list with custom controls [REQUIRE FOCUS]', function (assert) {
assert.expect(5);
diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js
index 83bd275d9e0..75f8afeeff2 100644
--- a/addons/web/static/tests/helpers/mock_server.js
+++ b/addons/web/static/tests/helpers/mock_server.js
@@ -904,10 +904,14 @@ var MockServer = Class.extend({
var offset = args.offset ? Number(args.offset) : 0;
var field = args.field ? args.field : 'sequence';
var records = this.data[args.model].records;
+ if (!(field in this.data[args.model].fields)) {
+ return false;
+ }
for (var i in args.ids) {
var record = _.findWhere(records, {id: args.ids[i]});
record[field] = Number(i) + offset;
}
+ return true;
},
/**
* Simulate a 'search_count' operation
diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js
index 6594b274be1..6b8ddfee91b 100644
--- a/addons/web/static/tests/helpers/test_utils.js
+++ b/addons/web/static/tests/helpers/test_utils.js
@@ -257,6 +257,12 @@ function createAsyncView(params) {
controlPanel.appendTo($web_client);
var $content = $('<div>').addClass('o_content').appendTo($web_client);
+ if (params.interceptsPropagate) {
+ _.each(params.interceptsPropagate, function (cb, name) {
+ intercept(widget, name, cb, true);
+ });
+ }
+
return view.getController(widget).then(function (view) {
// override the view's 'destroy' so that it calls 'destroy' on the widget
// instead, as the widget is the parent of the view and the mockServer.
diff --git a/addons/web/static/tests/services/notification_service_tests.js b/addons/web/static/tests/services/notification_service_tests.js
index 195222881c5..df3c1657c92 100644
--- a/addons/web/static/tests/services/notification_service_tests.js
+++ b/addons/web/static/tests/services/notification_service_tests.js
@@ -246,4 +246,38 @@ QUnit.module('Services', {
});
});
+ QUnit.test('Display a custom notification', function (assert) {
+ var done = assert.async();
+ assert.expect(3);
+
+ var Custom = Notification.extend({
+ init: function (parent, params) {
+ this._super.apply(this, arguments);
+ assert.ok(params.customParams, 'instantiate custom notification');
+ },
+ start: function () {
+ var self = this;
+ return this._super().then(function () {
+ self.$el.html('Custom');
+ });
+ },
+ });
+
+ var view = createView(this.viewParams);
+ view.call('notification', 'notify', {
+ Notification: Custom,
+ customParams: true,
+ });
+ assert.strictEqual(
+ $('body .o_notification_manager .o_notification:contains(Custom)').length, 1,
+ "should display the notification");
+ view.destroy();
+ setTimeout(function () {
+ assert.strictEqual(
+ $('body .o_notification_manager .o_notification').length, 0,
+ "should destroy the notification");
+ done();
+ });
+ });
+
});});
diff --git a/addons/web/static/tests/views/kanban_model_tests.js b/addons/web/static/tests/views/kanban_model_tests.js
index 1a3391c720d..20eb2918d04 100644
--- a/addons/web/static/tests/views/kanban_model_tests.js
+++ b/addons/web/static/tests/views/kanban_model_tests.js
@@ -192,6 +192,8 @@ QUnit.module('Views', {
var done = assert.async();
assert.expect(8);
+ this.data.product.fields.sequence = {string: "Sequence", type: "integer"};
+ this.data.partner.fields.sequence = {string: "Sequence", type: "integer"};
this.data.partner.records.push({id: 3, foo: 'aaa', product_id: 37});
var nbReseq = 0;
@@ -204,7 +206,7 @@ QUnit.module('Views', {
if (nbReseq === 1) { // resequencing columns
assert.deepEqual(args.ids, [41, 37],
"ids should be correct");
- assert.strictEqual(args.model, 'product_id',
+ assert.strictEqual(args.model, 'product',
"model should be correct");
} else if (nbReseq === 2) { // resequencing records
assert.deepEqual(args.ids, [3, 1],
@@ -212,7 +214,6 @@ QUnit.module('Views', {
assert.strictEqual(args.model, 'partner',
"model should be correct");
}
- return $.when();
}
return this._super.apply(this, arguments);
},
@@ -229,7 +230,7 @@ QUnit.module('Views', {
"first group should be res_id 37");
// resequence columns
- return model.resequence('product_id', [41, 37], stateID);
+ return model.resequence('product', [41, 37], stateID);
})
.then(function (stateID) {
var state = model.get(stateID);
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index 66476aaad35..17c0c022e85 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -1559,7 +1559,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record fail in grouped', function (assert) {
+ QUnit.test('quick create record fail in grouped by many2one', function (assert) {
assert.expect(8);
var kanban = createView({
@@ -1684,6 +1684,120 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('quick create record fails in grouped by char', function (assert) {
+ assert.expect(7);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="foo"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ archs: {
+ 'partner,false,form': '<form>' +
+ '<field name="foo"/>' +
+ '</form>',
+ },
+ mockRPC: function (route, args) {
+ if (args.method === 'name_create') {
+ return $.Deferred().reject({
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ }, $.Event());
+ }
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], {foo: 'yop'},
+ "should write the correct value for foo");
+ assert.deepEqual(args.kwargs.context, {default_foo: 'yop', default_name: 'test'},
+ "should send the correct default value for foo");
+ }
+ return this._super.apply(this, arguments);
+ },
+ groupBy: ['foo'],
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "there should be 1 record in first column");
+
+ kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click();
+ kanban.$('.o_kanban_quick_create input').val('test').trigger('input');
+ kanban.$('.o_kanban_add').click();
+
+ 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_widget[name=foo]').val(), 'yop',
+ "the correct default value for foo should already be set");
+
+ $('.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, 2,
+ "there should be 2 records in first column");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record fails in grouped by selection', function (assert) {
+ assert.expect(7);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="state"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ archs: {
+ 'partner,false,form': '<form>' +
+ '<field name="state"/>' +
+ '</form>',
+ },
+ mockRPC: function (route, args) {
+ if (args.method === 'name_create') {
+ return $.Deferred().reject({
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ }, $.Event());
+ }
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], {state: 'abc'},
+ "should write the correct value for state");
+ assert.deepEqual(args.kwargs.context, {default_state: 'abc', default_name: 'test'},
+ "should send the correct default value for state");
+ }
+ return this._super.apply(this, arguments);
+ },
+ groupBy: ['state'],
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "there should be 1 record in first column");
+
+ kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click();
+ kanban.$('.o_kanban_quick_create input').val('test').trigger('input');
+ kanban.$('.o_kanban_add').click();
+
+ 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_widget[name=state]').val(), '"abc"',
+ "the correct default value for state should already be set");
+
+ $('.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, 2,
+ "there should be 2 records in first column");
+
+ kanban.destroy();
+ });
+
QUnit.test('quick create record in empty grouped kanban', function (assert) {
assert.expect(3);
@@ -1726,6 +1840,327 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('quick create record in grouped on date(time) field', function (assert) {
+ assert.expect(6);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="display_name"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ groupBy: ['date'],
+ intercepts: {
+ switch_view: function (ev) {
+ assert.deepEqual(_.pick(ev.data, 'res_id', 'view_type'), {
+ res_id: undefined,
+ view_type: 'form',
+ }, "should trigger an event to open the form view (twice)");
+ },
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0,
+ "quick create should be disabled when grouped on a date field");
+
+ // clicking on CREATE in control panel should not open a quick create
+ kanban.$buttons.find('.o-kanban-button-new').click();
+ assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0,
+ "should not have opened the quick create widget");
+
+ kanban.reload({groupBy: ['datetime']});
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0,
+ "quick create should be disabled when grouped on a datetime field");
+
+ // clicking on CREATE in control panel should not open a quick create
+ kanban.$buttons.find('.o-kanban-button-new').click();
+ assert.strictEqual(kanban.$('.o_kanban_quick_create').length, 0,
+ "should not have opened the quick create widget");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record feature is properly enabled/disabled at reload', function (assert) {
+ assert.expect(3);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="display_name"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ groupBy: ['foo'],
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3,
+ "quick create should be enabled when grouped on a char field");
+
+ kanban.reload({groupBy: ['date']});
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 0,
+ "quick create should now be disabled (grouped on date field)");
+
+ kanban.reload({groupBy: ['bar']});
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2,
+ "quick create should be enabled again (grouped on boolean field)");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record in grouped by char field', function (assert) {
+ assert.expect(4);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="display_name"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ groupBy: ['foo'],
+ mockRPC: function (route, args) {
+ if (args.method === 'name_create') {
+ assert.deepEqual(args.kwargs.context, {default_foo: 'yop'},
+ "should send the correct default value for foo");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3,
+ "quick create should be enabled when grouped on a char field");
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "first column should contain 1 record");
+
+ kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click();
+ kanban.$('.o_kanban_quick_create input').val('new record').trigger('input');
+ kanban.$('.o_kanban_add').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
+ "first column should now contain 2 records");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record in grouped by boolean field', function (assert) {
+ assert.expect(4);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="display_name"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ groupBy: ['bar'],
+ mockRPC: function (route, args) {
+ if (args.method === 'name_create') {
+ assert.deepEqual(args.kwargs.context, {default_bar: true},
+ "should send the correct default value for bar");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2,
+ "quick create should be enabled when grouped on a boolean field");
+ assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 3,
+ "second column (true) should contain 3 records");
+
+ kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i').click();
+ kanban.$('.o_kanban_quick_create input').val('new record').trigger('input');
+ kanban.$('.o_kanban_add').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 4,
+ "second column (true) should now contain 4 records");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record in grouped on selection field', function (assert) {
+ assert.expect(4);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test" on_create="quick_create">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="display_name"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ mockRPC: function (route, args) {
+ if (args.method === 'name_create') {
+ assert.deepEqual(args.kwargs.context, {default_state: 'abc'},
+ "should send the correct default value for bar");
+ }
+ return this._super.apply(this, arguments);
+ },
+ groupBy: ['state'],
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3,
+ "quick create should be enabled when grouped on a selection field");
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "first column (abc) should contain 1 record");
+
+ kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click();
+ kanban.$('.o_kanban_quick_create input').val('new record').trigger('input');
+ kanban.$('.o_kanban_add').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
+ "first column (abc) should contain 2 records");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record in grouped by char field (within quick_create_view)', function (assert) {
+ assert.expect(6);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban on_create="quick_create" quick_create_view="some_view_ref">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="foo"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ archs: {
+ 'partner,some_view_ref,form': '<form>' +
+ '<field name="foo"/>' +
+ '</form>',
+ },
+ groupBy: ['foo'],
+ mockRPC: function (route, args) {
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], {foo: 'yop'},
+ "should write the correct value for foo");
+ assert.deepEqual(args.kwargs.context, {default_foo: 'yop'},
+ "should send the correct default value for foo");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3,
+ "quick create should be enabled when grouped on a char field");
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "first column should contain 1 record");
+
+ kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click();
+ assert.strictEqual(kanban.$('.o_kanban_quick_create input').val(), 'yop',
+ "should have set the correct foo value by default");
+ kanban.$('.o_kanban_add').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
+ "first column should now contain 2 records");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record in grouped by boolean field (within quick_create_view)', function (assert) {
+ assert.expect(6);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban on_create="quick_create" quick_create_view="some_view_ref">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="bar"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ archs: {
+ 'partner,some_view_ref,form': '<form>' +
+ '<field name="bar"/>' +
+ '</form>',
+ },
+ groupBy: ['bar'],
+ mockRPC: function (route, args) {
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], {bar: true},
+ "should write the correct value for bar");
+ assert.deepEqual(args.kwargs.context, {default_bar: true},
+ "should send the correct default value for bar");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 2,
+ "quick create should be enabled when grouped on a boolean field");
+ assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 3,
+ "second column (true) should contain 3 records");
+
+ kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i').click();
+ assert.ok(kanban.$('.o_kanban_quick_create .o_field_boolean input').is(':checked'),
+ "should have set the correct bar value by default");
+ kanban.$('.o_kanban_add').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 4,
+ "second column (true) should now contain 4 records");
+
+ kanban.destroy();
+ });
+
+ QUnit.test('quick create record in grouped by selection field (within quick_create_view)', function (assert) {
+ assert.expect(6);
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban on_create="quick_create" quick_create_view="some_view_ref">' +
+ '<templates><t t-name="kanban-box">' +
+ '<div><field name="state"/></div>' +
+ '</t></templates>' +
+ '</kanban>',
+ archs: {
+ 'partner,some_view_ref,form': '<form>' +
+ '<field name="state"/>' +
+ '</form>',
+ },
+ groupBy: ['state'],
+ mockRPC: function (route, args) {
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], {state: 'abc'},
+ "should write the correct value for state");
+ assert.deepEqual(args.kwargs.context, {default_state: 'abc'},
+ "should send the correct default value for state");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(kanban.$('.o_kanban_header .o_kanban_quick_add i').length, 3,
+ "quick create should be enabled when grouped on a selection field");
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 1,
+ "first column (abc) should contain 1 record");
+
+ kanban.$('.o_kanban_header:first .o_kanban_quick_add i').click();
+ assert.strictEqual(kanban.$('.o_kanban_quick_create select').val(), '"abc"',
+ "should have set the correct state value by default");
+ kanban.$('.o_kanban_add').click();
+
+ assert.strictEqual(kanban.$('.o_kanban_group:first .o_kanban_record').length, 2,
+ "first column (abc) should now contain 2 records");
+
+ kanban.destroy();
+ });
+
QUnit.test('many2many_tags in kanban views', function (assert) {
assert.expect(12);
@@ -1796,6 +2231,72 @@ QUnit.module('Views', {
kanban.destroy();
});
+ QUnit.test('Do not open record when clicking on `a` with `href`', function (assert) {
+ assert.expect(5);
+
+ this.data.partner.records = [
+ { id: 1, foo: 'yop' },
+ ];
+
+ var kanban = createView({
+ View: KanbanView,
+ model: 'partner',
+ data: this.data,
+ arch: '<kanban class="o_kanban_test">' +
+ '<templates>' +
+ '<t t-name="kanban-box">' +
+ '<div class="oe_kanban_global_click">' +
+ '<field name="foo"/>' +
+ '<div>' +
+ '<a class="o_test_link" href="#">test link</a>' +
+ '</div>' +
+ '</div>' +
+ '</t>' +
+ '</templates>' +
+ '</kanban>',
+ intercepts: {
+ // when clicking on a record in kanban view,
+ // it switches to form view.
+ switch_view: function () {
+ throw new Error("should not switch view");
+ },
+ },
+ });
+
+ var $record = kanban.$('.o_kanban_record:not(.o_kanban_ghost)');
+ assert.strictEqual($record.length, 1,
+ "should display a kanban record");
+
+ var $testLink = $record.find('a');
+ assert.strictEqual($testLink.length, 1,
+ "should contain a link in the kanban record");
+ assert.ok(!!$testLink[0].href,
+ "link inside kanban record should have non-empty href");
+
+ // Mocked views prevent accessing a link with href. This is intented
+ // most of the time, but not in this test which specifically needs to
+ // let the browser access a link with href.
+ kanban.$el.off('click', 'a');
+ // Prevent the browser default behaviour when clicking on anything.
+ // This includes clicking on a `<a>` with `href`, so that it does not
+ // change the URL in the address bar.
+ // Note that we should not specify a click listener on 'a', otherwise
+ // it may influence the kanban record global click handler to not open
+ // the record.
+ $(document.body).on('click.o_test', function (ev) {
+ assert.notOk(ev.isDefaultPrevented(),
+ "should not prevented browser default behaviour beforehand");
+ assert.strictEqual(ev.target, $testLink[0],
+ "should have clicked on the test link in the kanban record");
+ ev.preventDefault();
+ });
+
+ $testLink.click();
+
+ $(document.body).off('click.o_test');
+ kanban.destroy();
+ });
+
QUnit.test('can drag and drop a record from one column to the next', function (assert) {
assert.expect(9);
@@ -2258,7 +2759,7 @@ QUnit.module('Views', {
});
QUnit.test('delete a column in grouped on m2o', function (assert) {
- assert.expect(33);
+ assert.expect(36);
testUtils.patch(KanbanRenderer, {
_renderGrouped: function () {
@@ -3224,6 +3725,7 @@ QUnit.module('Views', {
QUnit.test('resequence columns in grouped by m2o', function (assert) {
assert.expect(7);
+ this.data.product.fields.sequence = {string: "Sequence", type: "integer"};
var envIDs = [1, 3, 2, 4]; // the ids that should be in the environment during this test
var kanban = createView({
@@ -3237,12 +3739,6 @@ QUnit.module('Views', {
'</t></templates>' +
'</kanban>',
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.env.ids, envIDs,
@@ -3266,7 +3762,7 @@ QUnit.module('Views', {
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");
+ "first column should be id 5 after resequencing");
kanban.destroy();
});
@@ -4085,7 +4581,7 @@ QUnit.module('Views', {
'<div><field name="foo"/></div>' +
'</t></templates>' +
'</kanban>',
- groupBy: ['int_field'],
+ groupBy: ['foo'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
return $.when(true);
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index 63e7013c824..5a0d00b6f6d 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -3223,10 +3223,10 @@ QUnit.module('Views', {
foo: {
fields: {int_field: {string: "int_field", type: "integer", sortable: true}},
records: [
- {id: 1, int_field: 0},
- {id: 2, int_field: 1},
- {id: 3, int_field: 2},
- {id: 4, int_field: 3},
+ {id: 1, int_field: 11},
+ {id: 2, int_field: 12},
+ {id: 3, int_field: 13},
+ {id: 4, int_field: 14},
]
}
};
@@ -3245,14 +3245,15 @@ QUnit.module('Views', {
assert.deepEqual(args, {
model: "foo",
ids: [4, 3],
- offset: 2,
+ offset: 13,
field: "int_field",
});
}
if (moves === 1) {
assert.deepEqual(args, {
model: "foo",
- ids: [1, 4, 2, 3],
+ ids: [4, 2],
+ offset: 12,
field: "int_field",
});
}
@@ -3260,14 +3261,15 @@ QUnit.module('Views', {
assert.deepEqual(args, {
model: "foo",
ids: [2, 4],
- offset: 1,
+ offset: 12,
field: "int_field",
});
}
if (moves === 3) {
assert.deepEqual(args, {
model: "foo",
- ids: [1, 4, 2, 3],
+ ids: [4, 2],
+ offset: 12,
field: "int_field",
});
}
@@ -3334,7 +3336,6 @@ QUnit.module('Views', {
"should write the right field as sequence");
assert.deepEqual(args.ids, [4, 2, 3],
"should write the sequence in correct order");
- return $.when();
}
return this._super.apply(this, arguments);
},
@@ -3464,13 +3465,16 @@ QUnit.module('Views', {
'</tree>',
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
+ var _super = this._super.bind(this);
assert.strictEqual(args.offset, 1,
"should write the sequence starting from the lowest current one");
assert.strictEqual(args.field, 'int_field',
"should write the right field as sequence");
assert.deepEqual(args.ids, [4, 2, 3],
"should write the sequence in correct order");
- return $.when(def);
+ return $.when(def).then(function () {
+ return _super(route, args);
+ });
}
return this._super.apply(this, arguments);
},