diff options
Diffstat (limited to 'addons/web/static/tests')
| -rw-r--r-- | addons/web/static/tests/fields/basic_fields_tests.js | 197 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/field_utils_tests.js | 28 | ||||
| -rw-r--r-- | addons/web/static/tests/fields/relational_fields_tests.js | 236 | ||||
| -rw-r--r-- | addons/web/static/tests/helpers/test_utils.js | 7 | ||||
| -rw-r--r-- | addons/web/static/tests/views/basic_model_tests.js | 78 | ||||
| -rw-r--r-- | addons/web/static/tests/views/calendar_tests.js | 271 | ||||
| -rw-r--r-- | addons/web/static/tests/views/form_tests.js | 58 | ||||
| -rw-r--r-- | addons/web/static/tests/views/kanban_tests.js | 78 | ||||
| -rw-r--r-- | addons/web/static/tests/views/list_tests.js | 65 | ||||
| -rw-r--r-- | addons/web/static/tests/views/view_dialogs_tests.js | 31 | ||||
| -rw-r--r-- | addons/web/static/tests/widgets/data_export_tests.js | 84 |
11 files changed, 1063 insertions, 70 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(); + }); + }); }); }); diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js index fbfdb315fa4..343f04d9fad 100644 --- a/addons/web/static/tests/helpers/test_utils.js +++ b/addons/web/static/tests/helpers/test_utils.js @@ -257,8 +257,11 @@ function addMockEnvironment(widget, params) { var initialDebounce = DebouncedField.prototype.DEBOUNCE; DebouncedField.prototype.DEBOUNCE = params.fieldDebounce || 0; var initialSession, initialConfig, initialParameters; + initialSession = _.extend({}, session); + session.getTZOffset = function () { + return 0; // by default, but may be overriden in specific tests + }; if ('session' in params) { - initialSession = _.extend({}, session); _.extend(session, params.session); } if ('config' in params) { @@ -283,8 +286,8 @@ function addMockEnvironment(widget, params) { for (key in session) { delete session[key]; } - _.extend(session, initialSession); } + _.extend(session, initialSession); if ('config' in params) { for (key in config) { delete config[key]; diff --git a/addons/web/static/tests/views/basic_model_tests.js b/addons/web/static/tests/views/basic_model_tests.js index 8c23fc4f97c..318b715a504 100644 --- a/addons/web/static/tests/views/basic_model_tests.js +++ b/addons/web/static/tests/views/basic_model_tests.js @@ -1323,6 +1323,64 @@ QUnit.module('Views', { model.destroy(); }); + QUnit.test('default_get: fetch many2one with default (empty & not) inside x2manys', function (assert) { + assert.expect(4); + + this.data.partner.fields.o2m = { + string: "O2M", type: 'one2many', relation: 'partner', default: [ + [6, 0, []], + [0, 0, {category: false}], + [0, 0, {category: 12}], + ], + }; + this.data.partner.fields.category.type = 'many2one'; + + var model = createModel({ + Model: BasicModel, + data: this.data, + mockRPC: function (route, args) { + if (args.method === 'name_get' && args.model === 'partner_type') { + assert.deepEqual(args.args, [[12]], "should name_get on category 12"); + } + return this._super(route, args); + }, + }); + + var params = { + fieldNames: ['o2m'], + fields: this.data.partner.fields, + fieldsInfo: { + form: { + o2m: { + relatedFields: this.data.partner.fields, + fieldsInfo: { + list: { + category: { + relatedFields: { display_name: {} }, + }, + }, + }, + viewType: 'list', + }, + }, + }, + modelName: 'partner', + type: 'record', + viewType: 'form', + }; + + model.load(params).then(function (resultID) { + var record = model.get(resultID); + assert.strictEqual(record.data.o2m.count, 2, "o2m field should contain 2 records"); + assert.strictEqual(record.data.o2m.data[0].data.category, false, + "first category field should be empty"); + assert.strictEqual(record.data.o2m.data[1].data.category.data.display_name, "gold", + "second category field should have been correctly fetched"); + }); + + model.destroy(); + }); + QUnit.test('default_get: fetch x2manys inside x2manys', function (assert) { assert.expect(3); @@ -2007,5 +2065,25 @@ QUnit.module('Views', { model.destroy(); }); + QUnit.test('default_get with value false for a one2many', function (assert) { + assert.expect(1); + + this.data.partner.fields.product_ids.default = false; + this.params.fieldNames = ['product_ids']; + this.params.res_id = undefined; + this.params.type = 'record'; + + var model = createModel({ + Model: BasicModel, + data: this.data, + }); + + model.load(this.params).then(function (resultID) { + var record = model.get(resultID); + assert.deepEqual(record.data.product_ids.data, [], "o2m default should be []"); + }); + + model.destroy(); + }); });}); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 6aa01daac5a..9f9be3a4042 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -440,7 +440,9 @@ QUnit.module('Views', { initialDate: initialDate, }, session: { - tzOffset: 120 + getTZOffset: function () { + return 120; + }, }, mockRPC: function (route, args) { if (args.method === "create") { @@ -507,7 +509,7 @@ QUnit.module('Views', { }); QUnit.test('create event with timezone in week mode with formViewDialog', function (assert) { - assert.expect(7); + assert.expect(8); this.data.event.records = []; this.data.event.onchanges = { @@ -541,7 +543,9 @@ QUnit.module('Views', { initialDate: initialDate, }, session: { - tzOffset: 120 + getTZOffset: function () { + return 120; + }, }, mockRPC: function (route, args) { if (args.method === "create") { @@ -554,12 +558,8 @@ QUnit.module('Views', { "should send the context to create events"); } if (args.method === "write") { - assert.deepEqual(args.args[1], { - "allday": false, - "start": "2016-12-12 06:00:00", - "stop": "2016-12-12 08:00:00" - }, - "should move the event"); + assert.deepEqual(args.args[1], expectedEvent, + "should move the event"); } return this._super(route, args); }, @@ -631,17 +631,34 @@ QUnit.module('Views', { left = pos.left + 5; top = pos.top + 5; + // Mode this event to another day + var expectedEvent = { + "allday": false, + "start": "2016-12-12 06:00:00", + "stop": "2016-12-12 08:00:00" + }; testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); left = calendar.$('.fc-day:eq(1)').offset().left + 5; testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + // Move to "All day" + expectedEvent = { + "allday": true, + "start": "2016-12-12 00:00:00", + "stop": "2016-12-12 00:00:00" + }; + testUtils.triggerPositionalMouseEvent(left, top, "mousedown"); + top = calendar.$('.fc-day:eq(1)').offset().top + 5; + testUtils.triggerPositionalMouseEvent(left, top, "mousemove"); + testUtils.triggerPositionalMouseEvent(left, top, "mouseup"); + calendar.destroy(); $view.remove(); }); - QUnit.test('create all day event', function (assert) { - assert.expect(2); + QUnit.test('create all day event in week mode', function (assert) { + assert.expect(3); this.data.event.records = []; @@ -664,7 +681,9 @@ QUnit.module('Views', { initialDate: initialDate, }, session: { - tzOffset: 120 + getTZOffset: function () { + return 120; + }, }, }); @@ -690,6 +709,8 @@ QUnit.module('Views', { assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "newevent", "should display the new event with time and title"); + assert.strictEqual($newevent.parent().attr('colspan'), "2", + "should appear over two days."); assert.deepEqual($newevent.data('fcSeg').event.record, { @@ -706,6 +727,141 @@ QUnit.module('Views', { $view.remove(); }); + QUnit.test('create all day event in week mode (no quickCreate)', function (assert) { + assert.expect(1); + + this.data.event.records = []; + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar class="o_calendar_test" '+ + 'date_start="start" '+ + 'date_stop="stop" '+ + 'mode="week" '+ + 'quick_add="False" '+ + 'readonly_form_view_id="1">'+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + session: { + getTZOffset: function () { + return 120; + }, + }, + intercepts: { + do_action: function (event) { + assert.deepEqual(event.data.action.context, { + "default_name": null, + "default_start": "2016-12-14 05:00:00", + "default_stop": "2016-12-15 17:00:00", + }, + "should send the correct data to create events"); + }, + }, + }); + + var $view = $('#qunit-fixture').contents(); + $view.prependTo('body'); // => select with click position + + + var pos = calendar.$('.fc-bg td:eq(4)').offset(); + try { + testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); + } catch (e) { + calendar.destroy(); + $view.remove(); + throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); + } + pos = calendar.$('.fc-bg td:eq(5)').offset(); + testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); + testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); + + calendar.destroy(); + $view.remove(); + }); + + QUnit.test('create event in month mode', function (assert) { + assert.expect(4); + + this.data.event.records = []; + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar class="o_calendar_test" '+ + 'event_open_popup="true" '+ + 'date_start="start" '+ + 'date_stop="stop" '+ + 'mode="month" '+ + 'readonly_form_view_id="1">'+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + session: { + getTZOffset: function () { + return 120; + }, + }, + mockRPC: function (route, args) { + if (args.method === "create") { + assert.deepEqual(args.args[0], { + "name": "new event", + "start": "2016-12-14 05:00:00", + "stop": "2016-12-15 17:00:00", + }, + "should send the correct data to create events"); + } + return this._super(route, args); + }, + }); + + var $view = $('#qunit-fixture').contents(); + $view.prependTo('body'); // => select with click position + + var pos = calendar.$('.fc-bg td:eq(20)').offset(); + try { + testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousedown"); + } catch (e) { + calendar.destroy(); + $view.remove(); + throw new Error('The test fails to simulate a click in the screen. Your screen is probably too small or your dev tools is open.'); + } + pos = calendar.$('.fc-bg td:eq(21)').offset(); + testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove"); + testUtils.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup"); + + $('.modal input:first').val('new event').trigger('input'); + $('.modal button.btn:contains(Create)').trigger('click'); + var $newevent = calendar.$('.fc-event:contains(new event)'); + + assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "newevent", + "should display the new event with time and title"); + assert.strictEqual($newevent.parent().attr('colspan'), "2", + "should appear over two days."); + + assert.deepEqual($newevent.data('fcSeg').event.record, { + display_name: "new event", + start: fieldUtils.parse.datetime("2016-12-14 05:00:00", this.data.event.fields.start, {isUTC: true}), + stop: fieldUtils.parse.datetime("2016-12-15 17:00:00", this.data.event.fields.stop, {isUTC: true}), + name: "new event", + id: 1 + }, "the new record should have the utc datetime (quickCreate)"); + + calendar.destroy(); + $view.remove(); + }); + QUnit.test('use mini calendar', function (assert) { assert.expect(12); @@ -728,7 +884,9 @@ QUnit.module('Views', { initialDate: initialDate, }, session: { - tzOffset: 120 + getTZOffset: function () { + return 120; + }, }, }); @@ -866,6 +1024,62 @@ QUnit.module('Views', { assert.strictEqual($('#ui-datepicker-div:empty').length, 0, "should have a clean body"); }); + QUnit.test('create and edit event in month mode (all_day: false)', function (assert) { + assert.expect(2); + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + '<calendar class="o_calendar_test" '+ + 'string="Events" ' + + 'date_start="start" '+ + 'date_stop="stop" '+ + 'mode="month" '+ + 'readonly_form_view_id="1">'+ + '<field name="name"/>'+ + '</calendar>', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + session: { + getTZOffset: function () { + return -240; + }, + }, + }); + + // create a new event and edit it + var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)'); + testUtils.triggerMouseEvent($cell, "mousedown"); + testUtils.triggerMouseEvent($cell, "mouseup"); + $('.modal-body input:first').val('coucou').trigger('input'); + + testUtils.intercept(calendar, 'do_action', function (event) { + assert.deepEqual(event.data.action, + { + type: "ir.actions.act_window", + res_model: "event", + views: [[false, "form"]], + target: "current", + context: { + "default_name": "coucou", + "default_start": "2016-12-27 11:00:00", // 7:00 + 4h + "default_stop": "2016-12-27 23:00:00", // 19:00 + 4h + } + }, + "should open the form view with the context default values"); + }); + + $('.modal button.btn:contains(Edit)').trigger('click'); + + calendar.destroy(); + assert.strictEqual($('#ui-datepicker-div:empty').length, 0, "should have a clean body"); + }); + + QUnit.test('readonly date_start field', function (assert) { assert.expect(4); @@ -981,37 +1195,6 @@ QUnit.module('Views', { calendar.destroy(); }); - QUnit.test('ensure calendar adapts to screen size', function (assert) { - assert.expect(2); - - // We want to be able to restore changes on 'body' - var bodyStyle = $('body').attr('style'); - - // Force the view height to be smaller than the natural calendar height - // (FullCalendar requires that the height be modified on body not $target) - var height = 500; - $('body').height(height); - - var calendar = createView({ - View: CalendarView, - model: 'event', - data: this.data, - arch: '<calendar mode="week" date_start="start" />', - }); - - var $scroller = calendar.$('.fc-scroller') - assert.strictEqual($scroller.height() < height, true, - "the scroller should be smaller than the view height"); - assert.strictEqual($scroller.prop('scrollHeight') > height, true, - "the scroller should have a scrollbar"); - calendar.destroy(); - - $('body').removeAttr('style'); - if (bodyStyle) { - $('body').attr('style', bodyStyle); - } - }); - QUnit.test('ensure events are still shown if filters give an empty domain', function (assert) { assert.expect(2); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index b1ded45d9a2..c71ec8f2d93 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -2885,7 +2885,9 @@ QUnit.module('Views', { '</form>', res_id: 1, session: { - tzOffset: 120 + getTZOffset: function () { + return 120; + }, }, }); @@ -3779,6 +3781,60 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('one2manys (list editable) inside one2manys are saved correctly', function (assert) { + assert.expect(3); + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '<form string="Partners">' + + '<sheet>' + + '<field name="p">' + + '<tree>' + + '<field name="p"/>' + + '</tree>' + + '</field>' + + '</sheet>' + + '</form>', + archs: { + "partner,false,form": '<form>' + + '<field name="p">' + + '<tree editable="top">' + + '<field name="display_name"/>' + + '</tree>' + + '</field>' + + '</form>' + }, + mockRPC: function (route, args) { + if (args.method === 'create') { + assert.deepEqual(args.args[0].p, + [[0, false, { + p: [[0, false, {display_name: "xtv"}]], + }]], + "create should be called with the correct arguments"); + } + return this._super.apply(this, arguments); + }, + }); + + // add a o2m subrecord + form.$('.o_field_x2many_list_row_add a').click(); + $('.modal-body .o_field_one2many .o_field_x2many_list_row_add a').click(); + $('.modal-body input').val('xtv').trigger('input'); + $('.modal-footer button:first').click(); // save & close + assert.strictEqual($('.modal').length, 0, + "dialog should be closed"); + + var row = form.$('.o_field_one2many .o_list_view .o_data_row'); + assert.strictEqual(row.children()[0].textContent, '1 record', + "the cell should contains the number of record: 1"); + + form.$buttons.find('.o_form_button_save').click(); + + form.destroy(); + }); + QUnit.test('*_view_ref in context are passed correctly', function (assert) { var done = assert.async(); assert.expect(4); diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index be8a8a496af..84091f91a08 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -136,11 +136,12 @@ QUnit.module('Views', { }); QUnit.test('basic grouped rendering with active field', function (assert) { - assert.expect(4); + 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', @@ -152,6 +153,12 @@ QUnit.module('Views', { '<div><field name="foo"/></div>' + '</t></templates></kanban>', 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 @@ -163,6 +170,7 @@ QUnit.module('Views', { // 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"); @@ -546,8 +554,9 @@ QUnit.module('Views', { }); QUnit.test('can drag and drop a record from one column to the next', function (assert) { - assert.expect(7); + 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, @@ -569,6 +578,12 @@ QUnit.module('Views', { } 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)"); @@ -578,6 +593,7 @@ QUnit.module('Views', { 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, @@ -676,6 +692,42 @@ QUnit.module('Views', { 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: '<kanban>' + + '<field name="product_id"/>' + + '<templates><t t-name="kanban-box">' + + '<div><field name="foo"/></div>' + + '</t></templates>' + + '</kanban>', + 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); @@ -1282,8 +1334,9 @@ QUnit.module('Views', { }); QUnit.test('resequence columns in grouped by m2o', function (assert) { - assert.expect(4); + 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', @@ -1301,6 +1354,12 @@ QUnit.module('Views', { } 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'), @@ -1313,6 +1372,7 @@ QUnit.module('Views', { // 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 @@ -1441,8 +1501,9 @@ QUnit.module('Views', { }); QUnit.test('load more records in column', function (assert) { - assert.expect(9); + 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', @@ -1462,12 +1523,19 @@ QUnit.module('Views', { } 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, @@ -1476,6 +1544,8 @@ QUnit.module('Views', { 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"); diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js index 2247a64fa3c..4b33af9f0a6 100644 --- a/addons/web/static/tests/views/list_tests.js +++ b/addons/web/static/tests/views/list_tests.js @@ -1271,7 +1271,9 @@ QUnit.module('Views', { data: this.data, arch: '<tree><field name="date"/><field name="datetime"/></tree>', session: { - tzOffset: 120 + getTZOffset: function () { + return 120; + }, }, }); @@ -1322,12 +1324,13 @@ QUnit.module('Views', { }); QUnit.test('list view with nested groups', function (assert) { - assert.expect(37); + assert.expect(42); this.data.foo.records.push({id: 5, foo: "blip", int_field: -7, m2o: 1}); this.data.foo.records.push({id: 6, foo: "blip", int_field: 5, m2o: 2}); var nbRPCs = {readGroup: 0, searchRead: 0}; + var envIDs = []; // the ids that should be in the environment during this test var list = createView({ View: ListView, @@ -1352,10 +1355,14 @@ QUnit.module('Views', { return this._super.apply(this, arguments); }, intercepts: { - switch_view: function (event) { + switch_view: function (event) { assert.strictEqual(event.data.res_id, 4, "'switch_view' event has been triggered"); }, + env_updated: function (event) { + assert.deepEqual(event.data.ids, envIDs, + "should notify the environment with the correct ids"); + }, }, }); @@ -1398,6 +1405,7 @@ QUnit.module('Views', { // open subgroup nbRPCs = {readGroup: 0, searchRead: 0}; + envIDs = [4, 5]; // the opened subgroup contains these two records $openGroup.find('.o_group_header:nth(2)').click(); assert.strictEqual(nbRPCs.readGroup, 0, "should have done no read_group"); assert.strictEqual(nbRPCs.searchRead, 1, "should have done one search_read"); @@ -1414,6 +1422,7 @@ QUnit.module('Views', { // sort by int_field (ASC) and check that open groups are still open nbRPCs = {readGroup: 0, searchRead: 0}; + envIDs = [5, 4]; // order of the records changed list.$('thead th:last').click(); assert.strictEqual(nbRPCs.readGroup, 2, "should have done two read_groups"); assert.strictEqual(nbRPCs.searchRead, 1, "should have done one search_read"); @@ -1427,6 +1436,7 @@ QUnit.module('Views', { // close first level group nbRPCs = {readGroup: 0, searchRead: 0}; + envIDs = []; // the group being closed, there is no more record in the environment list.$('.o_group_header:first').click(); assert.strictEqual(nbRPCs.readGroup, 0, "should have done no read_group"); assert.strictEqual(nbRPCs.searchRead, 0, "should have done no search_read"); @@ -2519,6 +2529,55 @@ QUnit.module('Views', { list.destroy(); }); + + QUnit.test('grouped list view, indentation for empty group', function (assert) { + assert.expect(3); + + this.data.foo.fields.priority = { + string: "Priority", + type: "selection", + selection: [[1, "Low"], [2, "Medium"], [3, "High"]], + default: 1, + }; + this.data.foo.records.push({id: 5, foo: "blip", int_field: -7, m2o: 1, priority: 2}); + this.data.foo.records.push({id: 6, foo: "blip", int_field: 5, m2o: 1, priority: 3}); + + var list = createView({ + View: ListView, + model: 'foo', + data: this.data, + arch: '<tree><field name="id"/></tree>', + groupBy: ['priority', 'm2o'], + mockRPC: function (route, args) { + // Override of the read_group to display the row even if there is no record in it, + // to mock the behavihour of some fields e.g stage_id on the sale order. + if (args.method === 'read_group' && args.kwargs.groupby[0] === "m2o") { + return $.when([ + { + id: 8, + m2o:[1,"Value 1"], + m2o_count: 0 + }, { + id: 2, + m2o:[2,"Value 2"], + m2o_count: 1 + } + ]); + } + return this._super.apply(this, arguments); + }, + }); + + // open the first group + list.$('.o_group_header:first').click(); + assert.strictEqual(list.$('th.o_group_name').eq(1).children().length, 1, + "There should be an empty element creating the indentation for the subgroup."); + assert.strictEqual(list.$('th.o_group_name').eq(1).children().eq(0).hasClass('fa'), true, + "The first element of the row name should have the fa class"); + assert.strictEqual(list.$('th.o_group_name').eq(1).children().eq(0).is('span'), true, + "The first element of the row name should be a span"); + list.destroy(); + }); }); }); diff --git a/addons/web/static/tests/views/view_dialogs_tests.js b/addons/web/static/tests/views/view_dialogs_tests.js index 8c46d8fff46..43bf4ee6694 100644 --- a/addons/web/static/tests/views/view_dialogs_tests.js +++ b/addons/web/static/tests/views/view_dialogs_tests.js @@ -140,6 +140,35 @@ QUnit.module('Views', { dialog.destroy(); }); + QUnit.test('SelectCreateDialog list view in readonly', function (assert) { + assert.expect(1); + + var parent = createParent({ + data: this.data, + archs: { + 'partner,false,list': + '<tree string="Partner" editable="bottom">' + + '<field name="display_name"/>' + + '<field name="foo"/>' + + '</tree>', + 'partner,false,search': + '<search/>' + }, + }); + + var dialog = new dialogs.SelectCreateDialog(parent, { + res_model: 'partner', + }).open(); + + // click on the first row to see if the list is editable + dialog.$('.o_list_view tbody tr:first td:not(.o_list_record_selector):first').click(); + + assert.equal(dialog.$('.o_list_view tbody tr:first td:not(.o_list_record_selector):first input').length, 0, + "list view should not be editable in a SelectCreateDialog"); + + dialog.destroy(); + }); + }); -});
\ No newline at end of file +}); diff --git a/addons/web/static/tests/widgets/data_export_tests.js b/addons/web/static/tests/widgets/data_export_tests.js index 83169a64e1f..d251e3dea15 100644 --- a/addons/web/static/tests/widgets/data_export_tests.js +++ b/addons/web/static/tests/widgets/data_export_tests.js @@ -4,6 +4,7 @@ odoo.define('web.data_export_tests', function (require) { var framework = require('web.framework'); var ListView = require('web.ListView'); var testUtils = require('web.test_utils'); +var data = require('web.data'); var createView = testUtils.createView; @@ -127,6 +128,89 @@ QUnit.module('widgets', { ]); }); + QUnit.test('saving fields list when exporting data', function (assert) { + assert.expect(6); + + var create = data.DataSet.prototype.create; + + data.DataSet.prototype.create = function (data, options) { + assert.step('create'); + return $.when([]); + }; + + var list = createView({ + View: ListView, + model: 'partner', + data: this.data, + arch: '<tree><field name="foo"/></tree>', + viewOptions: { + sidebar: true, + }, + mockRPC: function (route) { + if (route === '/web/export/formats') { + return $.when([ + {tag: 'csv', label: 'CSV'}, + {tag: 'xls', label: 'Excel'}, + ]); + } + if (route === '/web/export/get_fields') { + return $.when([ + { + field_type: "one2many", + string: "Activities", + required: false, + value: "activity_ids/id", + id: "activity_ids", + params: {"model": "mail.activity", "prefix": "activity_ids", "name": "Activities"}, + relation_field: "res_id", + children: true, + }, + ]); + } + return this._super.apply(this, arguments); + }, + }); + + list.getParent().searchview = { + build_search_data: function () { + assert.step('build_search_data'); + return { + contexts: [], + domains: [], + groupbys: [], + }; + }, + }; + + // Open the export modal + list.$('thead th.o_list_record_selector input').click(); + list.sidebar.$('a:contains(Export)').click(); + assert.strictEqual($('.modal').length, 1, + "a modal dialog should be open"); + + // Select 'Activities' in fields to export + assert.strictEqual($('.modal select.o_fields_list option').length, 0, + "the fields list should be empty"); + $('.modal .o_export_tree_item:contains(Activities)').click(); + $('.modal button:contains(Add)').click(); + assert.strictEqual($('.modal select.o_fields_list option').length, 1, + "there should be one item in the fields list"); + + // Save fields list + $('.modal a:contains(Save fields list)').click(); + $('.modal .o_save_list > input').val('fields list').trigger('input'); + $('.modal .o_save_list > button').click(); + assert.verifySteps(['build_search_data', 'create'], + "create should have been called"); + + // Close the modal and destroy list + $('.modal button span:contains(Close)').click(); + list.destroy(); + + // restore create function + data.DataSet.prototype.create = create; + }); + }); }); |
