summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/fields
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-08-24 13:17:53 +0200
committerChristophe Simonis <chs@odoo.com>2017-08-24 13:17:53 +0200
commit017ee5eab376b4f09beb62812c1cbc682009ed86 (patch)
tree2af185b0604cd8ce9129c39137bbf39d21d7be89 /addons/web/static/tests/fields
parent006c16198f7f68c9dc8b895defd013f33008840a (diff)
parent877e7098719195ed2934fc9c3b5c3bd8ad8bab07 (diff)
[MERGE] forward port branch saas-17 up to 877e7098719
Diffstat (limited to 'addons/web/static/tests/fields')
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js197
-rw-r--r--addons/web/static/tests/fields/field_utils_tests.js28
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js236
3 files changed, 446 insertions, 15 deletions
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index c2ab8121c16..b533f5056d2 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -736,6 +736,31 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('char field with size attribute', function (assert) {
+ assert.expect(1);
+
+ this.data.partner.fields.foo.size = 5; // max length
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<sheet>' +
+ '<group><field name="foo"/></group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ viewOptions: {
+ mode: 'edit',
+ },
+ });
+
+ assert.strictEqual(form.$('input.o_field_widget').attr('maxlength'), '5',
+ "maxlength attribute should have been set correctly on the input");
+
+ form.destroy();
+ });
+
QUnit.test('char field in editable list view', function (assert) {
assert.expect(6);
@@ -1072,8 +1097,8 @@ QUnit.module('basic_fields', {
res_id: 1,
});
- assert.ok(form.$('div.o_field_text').length, "should have a text area");
- assert.strictEqual(form.$('div.o_field_text').text(), 'yop', 'should be "yop" in readonly');
+ assert.ok(form.$('.o_field_text').length, "should have a text area");
+ assert.strictEqual(form.$('.o_field_text').text(), 'yop', 'should be "yop" in readonly');
form.$buttons.find('.o_form_button_edit').click();
@@ -1089,7 +1114,7 @@ QUnit.module('basic_fields', {
form.$buttons.find('.o_form_button_save').click();
- assert.strictEqual(form.$('div.o_field_text').text(), 'hello world',
+ assert.strictEqual(form.$('.o_field_text').text(), 'hello world',
'should be "hello world" after save');
form.destroy();
});
@@ -1109,7 +1134,7 @@ QUnit.module('basic_fields', {
res_id: 1,
});
- var $field = form.$('div.o_field_text');
+ var $field = form.$('.o_field_text');
assert.strictEqual($field.outerHeight(), $field[0].scrollHeight,
"text field should not have a scroll bar");
@@ -1211,6 +1236,31 @@ QUnit.module('basic_fields', {
list.destroy();
});
+ // Firefox-specific
+ // Copying from <div style="white-space:pre-wrap"> does not keep line breaks
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1390115
+ QUnit.test('copying text fields in RO mode should preserve line breaks', function (assert) {
+ assert.expect(1);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="txt"/>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ });
+
+ // Copying from a div tag with white-space:pre-wrap doesn't work in Firefox
+ assert.strictEqual(form.$('[name="txt"]').prop("tagName").toLowerCase(), 'span',
+ "the field contents should be surrounded by a span tag");
+ });
+
QUnit.module('FieldBinary');
QUnit.test('binary fields are correctly rendered', function (assert) {
@@ -1563,7 +1613,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field in form view', function (assert) {
+ QUnit.test('date field in form view (with positive time zone offset)', function (assert) {
assert.expect(8);
var form = createView({
@@ -1582,7 +1632,9 @@ QUnit.module('basic_fields', {
date_format: '%m/%d/%Y',
},
session: {
- tzOffset: 120
+ getTZOffset: function () {
+ return 120; // Should be ignored by date fields
+ },
},
});
@@ -1614,6 +1666,36 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('date field in form view (with negative time zone offset)', function (assert) {
+ assert.expect(2);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners"><field name="date"/></form>',
+ res_id: 1,
+ translateParameters: { // Avoid issues due to localization formats
+ date_format: '%m/%d/%Y',
+ },
+ session: {
+ getTZOffset: function () {
+ return -120; // Should be ignored by date fields
+ },
+ },
+ });
+
+ assert.strictEqual(form.$('.o_field_date').text(), '02/03/2017',
+ 'the date should be correctly displayed in readonly');
+
+ // switch to edit mode
+ form.$buttons.find('.o_form_button_edit').click();
+ assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
+ 'the date should be correct in edit mode');
+
+ form.destroy();
+ });
+
QUnit.test('date field in editable list view', function (assert) {
assert.expect(8);
@@ -1628,7 +1710,9 @@ QUnit.module('basic_fields', {
date_format: '%m/%d/%Y',
},
session: {
- tzOffset: 0
+ getTZOffset: function () {
+ return 0;
+ },
},
});
@@ -1717,7 +1801,9 @@ QUnit.module('basic_fields', {
time_format: '%H:%M:%S',
},
session: {
- tzOffset: 120
+ getTZOffset: function () {
+ return 120;
+ },
},
});
@@ -1774,7 +1860,9 @@ QUnit.module('basic_fields', {
time_format: '%H:%M:%S',
},
session: {
- tzOffset: 120
+ getTZOffset: function () {
+ return 120;
+ },
},
});
@@ -1844,7 +1932,9 @@ QUnit.module('basic_fields', {
time_format: '%H:%M:%S',
},
session: {
- tzOffset: 120
+ getTZOffset: function () {
+ return 120;
+ },
},
});
@@ -1863,6 +1953,93 @@ QUnit.module('basic_fields', {
form.destroy();
});
+ QUnit.test('datetime field with date/datetime widget (with day change)', function (assert) {
+ assert.expect(2);
+
+ this.data.partner.records[0].p = [2];
+ this.data.partner.records[1].datetime = "2017-02-08 02:00:00"; // UTC
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<field name="p">' +
+ '<tree>' +
+ '<field name="datetime"/>' +
+ '</tree>' +
+ '<form>' +
+ '<field name="datetime" widget="date"/>' +
+ '</form>' +
+ '</field>' +
+ '</form>',
+ res_id: 1,
+ translateParameters: { // Avoid issues due to localization formats
+ date_format: '%m/%d/%Y',
+ time_format: '%H:%M:%S',
+ },
+ session: {
+ getTZOffset: function () {
+ return -240;
+ },
+ },
+ });
+
+ var expectedDateString = "02/07/2017 22:00:00"; // local time zone
+ assert.strictEqual(form.$('.o_field_widget[name=p] .o_data_cell').text(), expectedDateString,
+ 'the datetime (datetime widget) should be correctly displayed in tree view');
+
+ // switch to form view
+ form.$('.o_field_widget[name=p] .o_data_row').click();
+ assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/07/2017',
+ 'the datetime (date widget) should be correctly displayed in form view');
+
+ form.destroy();
+ });
+
+ QUnit.test('datetime field with date/datetime widget (without day change)', function (assert) {
+ assert.expect(2);
+
+ this.data.partner.records[0].p = [2];
+ this.data.partner.records[1].datetime = "2017-02-08 10:00:00"; // without timezone
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<field name="p">' +
+ '<tree>' +
+ '<field name="datetime"/>' +
+ '</tree>' +
+ '<form>' +
+ '<field name="datetime" widget="date"/>' +
+ '</form>' +
+ '</field>' +
+ '</form>',
+ res_id: 1,
+ translateParameters: { // Avoid issues due to localization formats
+ date_format: '%m/%d/%Y',
+ time_format: '%H:%M:%S',
+ },
+ session: {
+ getTZOffset: function () {
+ return -240;
+ },
+ },
+ });
+
+ var expectedDateString = "02/08/2017 06:00:00"; // with timezone
+ assert.strictEqual(form.$('.o_field_widget[name=p] .o_data_cell').text(), expectedDateString,
+ 'the datetime (datetime widget) should be correctly displayed in tree view');
+
+ // switch to form view
+ form.$('.o_field_widget[name=p] .o_data_row').click();
+ assert.strictEqual($('.modal .o_field_date[name=datetime]').text(), '02/08/2017',
+ 'the datetime (date widget) should be correctly displayed in form view');
+
+ form.destroy();
+ });
QUnit.module('FieldMonetary');
diff --git a/addons/web/static/tests/fields/field_utils_tests.js b/addons/web/static/tests/fields/field_utils_tests.js
index a49197f6e65..a0284798553 100644
--- a/addons/web/static/tests/fields/field_utils_tests.js
+++ b/addons/web/static/tests/fields/field_utils_tests.js
@@ -4,6 +4,7 @@ odoo.define('web.field_utils_tests', function (require) {
var core = require('web.core');
var session = require('web.session');
var fieldUtils = require('web.field_utils');
+var testUtils = require('web.test_utils');
QUnit.module('fields', {}, function () {
@@ -59,10 +60,35 @@ QUnit.test("format_datetime", function (assert) {
var date_string = "2009-05-04 12:34:23";
var date = fieldUtils.parse.datetime(date_string, {}, {timezone: false});
- var str = fieldUtils.format.datetime(date, {timezone: false});
+ var str = fieldUtils.format.datetime(date, {}, {timezone: false});
assert.strictEqual(str, moment(date).format("MM/DD/YYYY HH:mm:ss"));
});
+QUnit.test("format_datetime (with different timezone offset)", function (assert) {
+ assert.expect(2);
+
+ // mock the date format to avoid issues due to localisation
+ var dateFormat = core._t.database.parameters.date_format;
+ core._t.database.parameters.date_format = '%m/%d/%Y';
+ session.getTZOffset = function (date) {
+ // simulate daylight saving time
+ var startDate = new Date(2017, 2, 26);
+ var endDate = new Date(2017, 9, 29);
+ if (startDate < date && date < endDate) {
+ return 120; // UTC+2
+ } else {
+ return 60; // UTC+1
+ }
+ };
+
+ var str = fieldUtils.format.datetime(moment.utc('2017-01-01T10:00:00Z'));
+ assert.strictEqual(str, '01/01/2017 11:00:00');
+ str = fieldUtils.format.datetime(moment.utc('2017-06-01T10:00:00Z'));
+ assert.strictEqual(str, '06/01/2017 12:00:00');
+
+ core._t.database.parameters.date_format = dateFormat;
+});
+
QUnit.test("format_many2one", function (assert) {
assert.expect(2);
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index 29f8666455a..89f4601efc4 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -958,6 +958,45 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('list in form: create with one2many with many2one (version 2)', function (assert) {
+ // This test simulates the exact same scenario as the previous one,
+ // except that the value for the many2one is explicitely set to false,
+ // which is stupid, but this happens, so we have to handle it
+ assert.expect(1);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<sheet>' +
+ '<field name="p">' +
+ '<tree editable="bottom">' +
+ '<field name="display_name"/>' +
+ '<field name="trululu"/>' +
+ '</tree>' +
+ '</field>' +
+ '</sheet>' +
+ '</form>',
+ mockRPC: function (route, args) {
+ if (args.method === 'default_get') {
+ return $.when({p: [[0, 0, {display_name: 'new record', trululu: false}]]});
+ } else if (args.method === 'name_get') {
+ // This should not be called at all and thus is not accounted for
+ // in the assert.expect. If this is called, you broke this test.
+ assert.notOk(_.str.startsWith(args.args[0][0], 'virtual_'),
+ "should not call name_get for the m2o inside o2m which has no value");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual($('td.o_data_cell:first').text(), 'new record',
+ "should have created the new record in the o2m with the correct name");
+
+ form.destroy();
+ });
+
QUnit.test('list in form: default_get with x2many create', function (assert) {
assert.expect(3);
@@ -1250,6 +1289,38 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('slow create on a many2one', function (assert) {
+ assert.expect(1);
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:
+ '<form>' +
+ '<sheet>' +
+ '<field name="product_id" options="{\'quick_create\': False}"/>' +
+ '</sheet>' +
+ '</form>',
+ archs: {
+ 'product,false,form':
+ '<form>' +
+ '<field name="name"/>' +
+ '</form>',
+ },
+ });
+
+ form.$('.o_field_many2one input').focus();
+ form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout');
+
+ $('.modal .modal-footer .btn-primary').first().click();
+
+ assert.strictEqual($('.modal:visible:last .o_form_view').length, 1,
+ 'a new modal should be opened and contain a form view');
+
+ form.destroy();
+ });
+
QUnit.test('no_create option on a many2one', function (assert) {
assert.expect(1);
@@ -1732,7 +1803,9 @@ QUnit.module('relational_fields', {
'</form>',
res_id: 1,
session: {
- tzOffset: 120
+ getTZOffset: function () {
+ return 120;
+ },
},
});
assert.strictEqual(form.$('td:eq(0)').text(), "01/25/2017",
@@ -5227,6 +5300,59 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('one2many: onchange that returns unknow field in list, but not in form', function (assert) {
+ assert.expect(5);
+
+ this.data.partner.onchanges = {
+ name: function () {},
+ };
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<field name="name"/>' +
+ '<field name="p">' +
+ '<tree>' +
+ '<field name="display_name"/>' +
+ '</tree>' +
+ '<form string="Partners">' +
+ '<field name="display_name"/>' +
+ '<field name="timmy" widget="many2many_tags"/>' +
+ '</form>' +
+ '</field>' +
+ '</form>',
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange') {
+ return $.when({
+ value: {
+ p: [[5], [0, 0, {display_name: 'new', timmy: [[5], [4, 12]]}]],
+ },
+ });
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ assert.strictEqual(form.$('.o_data_row').length, 1,
+ "the one2many should contain one row");
+ assert.strictEqual(form.$('.o_field_widget[name="timmy"]').length, 0,
+ "timmy should not be displayed in the list view");
+
+ form.$('.o_data_row td:first').click(); // open the record
+
+ assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"]').length, 1,
+ "timmy should be displayed in the form view");
+ assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"] .badge').length, 1,
+ "m2mtags should contain one tag");
+ assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"] .o_badge_text').text(),
+ 'gold', "tag name should have been correctly loaded");
+
+ form.destroy();
+ });
+
+
QUnit.module('FieldMany2Many');
QUnit.test('many2many kanban: edition', function (assert) {
@@ -7214,7 +7340,7 @@ QUnit.module('relational_fields', {
"should do a do_action with correct parameters");
});
- assert.strictEqual(form.$('a.o_form_uri:contains(first record)').length, 1,
+ assert.strictEqual(form.$('a.o_form_uri:contains(xphone)').length, 1,
"should contain a link");
form.$('a.o_form_uri').click(); // click on the link in readonly mode (should trigger do_action)
@@ -7226,7 +7352,7 @@ QUnit.module('relational_fields', {
"should contain one many2one");
assert.strictEqual(form.$('.o_field_widget select').val(), "product",
"widget should contain one select with the model");
- assert.strictEqual(form.$('.o_field_widget input').val(), "first record",
+ assert.strictEqual(form.$('.o_field_widget input').val(), "xphone",
"widget should contain one input with the record");
var options = _.map(form.$('.o_field_widget select > option'), function (el) {
@@ -7251,12 +7377,114 @@ QUnit.module('relational_fields', {
$dropdown.find('li:first()').click();
form.$buttons.find('.o_form_button_save').click();
- assert.strictEqual(form.$('a.o_form_uri').length, 1,
+ assert.strictEqual(form.$('a.o_form_uri:contains(gold)').length, 1,
"should contain a link with the new value");
form.destroy();
});
+ QUnit.test('default_get and onchange with a reference field', function (assert) {
+ assert.expect(8);
+
+ this.data.partner.fields.reference.default = 'product,37';
+ this.data.partner.onchanges = {
+ int_field: function (obj) {
+ if (obj.int_field !== 0) {
+ obj.reference = 'partner_type,' + obj.int_field;
+ }
+ },
+ };
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="int_field"/>' +
+ '<field name="reference"/>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ viewOptions: {
+ mode: 'edit',
+ },
+ mockRPC: function (route, args) {
+ if (args.method === 'name_get') {
+ assert.step(args.model);
+ }
+ return this._super(route, args);
+ },
+ });
+
+ assert.verifySteps(['product'], "the first name_get should have been done");
+ assert.strictEqual(form.$('.o_field_widget[name="reference"] select').val(), "product",
+ "reference field model should be correctly set");
+ assert.strictEqual(form.$('.o_field_widget[name="reference"] input').val(), "xphone",
+ "reference field value should be correctly set");
+
+ // trigger onchange
+ form.$('.o_field_widget[name=int_field]').val(12).trigger('input');
+
+ assert.verifySteps(['product', 'partner_type'], "the second name_get should have been done");
+ assert.strictEqual(form.$('.o_field_widget[name="reference"] select').val(), "partner_type",
+ "reference field model should be correctly set");
+ assert.strictEqual(form.$('.o_field_widget[name="reference"] input').val(), "gold",
+ "reference field value should be correctly set");
+ form.destroy();
+ });
+
+ QUnit.test('widget reference on char field, reset by onchange', function (assert) {
+ assert.expect(4);
+
+ this.data.partner.records[0].foo = 'product,37';
+ this.data.partner.onchanges = {
+ int_field: function (obj) {
+ obj.foo = 'product,' + obj.int_field;
+ },
+ };
+
+ var nbNameGet = 0;
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form string="Partners">' +
+ '<sheet>' +
+ '<group>' +
+ '<field name="int_field"/>' +
+ '<field name="foo" widget="reference" readonly="1"/>' +
+ '</group>' +
+ '</sheet>' +
+ '</form>',
+ res_id: 1,
+ viewOptions: {
+ mode: 'edit',
+ },
+ mockRPC: function (route, args) {
+ if (args.model === 'product' && args.method === 'name_get') {
+ nbNameGet++;
+ }
+ return this._super(route, args);
+ },
+ });
+
+ assert.strictEqual(nbNameGet, 1,
+ "the first name_get should have been done");
+ assert.strictEqual(form.$('a[name="foo"]').text(), "xphone",
+ "foo field should be correctly set");
+
+ // trigger onchange
+ form.$('.o_field_widget[name=int_field]').val(41).trigger('input');
+
+ assert.strictEqual(nbNameGet, 2,
+ "the second name_get should have been done");
+ assert.strictEqual(form.$('a[name="foo"]').text(), "xpad",
+ "foo field should have been updated");
+ form.destroy();
+ });
+
});
});
});