diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js index 644ba8ac985..9a73ad67057 100644 --- a/addons/web/static/src/js/views/abstract_view.js +++ b/addons/web/static/src/js/views/abstract_view.js @@ -266,7 +266,7 @@ var AbstractView = Class.extend({ } defs.push(parent.loadViews( field.relation, - new Context(context, self.userContext), + new Context(context, self.userContext, self.loadParams.context), [[null, attrs.mode === 'tree' ? 'list' : attrs.mode]]) .then(function (views) { for (var viewName in views) { diff --git a/addons/web/static/src/js/views/calendar/calendar_model.js b/addons/web/static/src/js/views/calendar/calendar_model.js index c8b9fd574b2..eb6d7176884 100644 --- a/addons/web/static/src/js/views/calendar/calendar_model.js +++ b/addons/web/static/src/js/views/calendar/calendar_model.js @@ -614,7 +614,8 @@ return AbstractModel.extend({ if (this.mapping.all_day && evt[this.mapping.all_day]) { date_stop.add(1, 'days'); } - + var isAllDay = this.fields[this.mapping.date_start].type === 'date' || + this.mapping.all_day && evt[this.mapping.all_day] || false; var r = { 'record': evt, 'start': date_start, @@ -622,7 +623,7 @@ return AbstractModel.extend({ 'r_start': date_start, 'r_end': date_stop, 'title': the_title, - 'allDay': this.mapping.all_day && evt[this.mapping.all_day] || false, + 'allDay': isAllDay, 'id': evt.id, 'attendees':attendees, }; diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js index 3f97df1d4bf..eb78153265c 100644 --- a/addons/web/static/tests/helpers/mock_server.js +++ b/addons/web/static/tests/helpers/mock_server.js @@ -57,16 +57,22 @@ var MockServer = Class.extend({ * 'field_view_get' call to the server. Calls processViews() of data_manager * to mimick the real behavior of a call to loadViews(). * - * @param {string|Object} arch a string OR a parsed xml document - * @param {string} model a model name (that should be in this.data) + * @param {Object} params + * @param {string|Object} params.arch a string OR a parsed xml document + * @param {string} params.model a model name (that should be in this.data) + * @param {Object} params.toolbar the actions possible in the toolbar + * @param {Object} [params.viewOptions] the view options set in the test (optional) * @returns {Object} an object with 2 keys: arch and fields */ - fieldsViewGet: function (arch, model, toolbar) { + fieldsViewGet: function (params) { + var model = params.model; + var toolbar = params.toolbar; + var viewOptions = params.viewOptions || {}; if (!(model in this.data)) { throw new Error('Model ' + model + ' was not defined in mock server data'); } var fields = $.extend(true, {}, this.data[model].fields); - var fvg = this._fieldsViewGet(arch, model, fields); + var fvg = this._fieldsViewGet(params.arch, model, fields, viewOptions.context); var fields_views = {}; fields_views[fvg.type] = fvg; data_manager.processViews(fields_views, fields); @@ -155,10 +161,11 @@ var MockServer = Class.extend({ * @param {string|Object} arch a string OR a parsed xml document * @param {string} model a model name (that should be in this.data) * @param {Object} fields + * @param {Object} context * @returns {Object} an object with 2 keys: arch and fields (the fields * appearing in the views) */ - _fieldsViewGet: function (arch, model, fields) { + _fieldsViewGet: function (arch, model, fields, context) { var self = this; var modifiersNames = ['invisible', 'readonly', 'required']; var onchanges = this.data[model].onchanges || {}; @@ -224,7 +231,8 @@ var MockServer = Class.extend({ } _.each(modifiersNames, function (a) { if (node.attrs[a]) { - var v = pyeval.py_eval(node.attrs[a]) ? true: false; + var pyevalContext = window.py.dict.fromJSON(context || {}); + var v = pyeval.py_eval(node.attrs[a], {context: pyevalContext}) ? true: false; if (inTreeView && a === 'invisible') { modifiers['tree_invisible'] = v; } else if (v || !(a in modifiers) || !_.isArray(modifiers[a])) { @@ -252,7 +260,8 @@ var MockServer = Class.extend({ _.each(node.children, function (children) { relModel = field.relation; relFields = $.extend(true, {}, self.data[relModel].fields); - field.views[children.tag] = self._fieldsViewGet(children, relModel, relFields); + field.views[children.tag] = self._fieldsViewGet(children, relModel, + relFields, context); }); } diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js index e2007106ecd..0939b0fc196 100644 --- a/addons/web/static/tests/helpers/test_utils.js +++ b/addons/web/static/tests/helpers/test_utils.js @@ -129,7 +129,7 @@ function createAsyncView(params) { // add mock environment: mock server, session, fieldviewget, ... var mockServer = addMockEnvironment(widget, params); - var viewInfo = mockServer.fieldsViewGet(params.arch, params.model, params.toolbar); + var viewInfo = mockServer.fieldsViewGet(params); // create the view var viewOptions = { @@ -321,10 +321,17 @@ function addMockEnvironment(widget, params) { var view_type = view_descr[1]; var key = [model, view_id, view_type].join(','); var arch = params.archs[key]; + var viewParams = { + arch: arch, + model: model, + viewOptions: { + context: event.data.context.eval(), + }, + }; if (!arch) { throw new Error('No arch found for key ' + key); } - views[view_type] = mockServer.fieldsViewGet(arch, model); + views[view_type] = mockServer.fieldsViewGet(viewParams); }); event.data.on_success(views); diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js index 9f9be3a4042..f1caba9ed4a 100644 --- a/addons/web/static/tests/views/calendar_tests.js +++ b/addons/web/static/tests/views/calendar_tests.js @@ -1257,6 +1257,37 @@ QUnit.module('Views', { calendar.destroy(); $view.remove(); }); + + QUnit.test('set event as all day when field is date', function (assert) { + assert.expect(1); + + this.data.event.records[0].start_date = "2016-12-14"; + + var calendar = createView({ + View: CalendarView, + model: 'event', + data: this.data, + arch: + ''+ + ''+ + ''+ + ''+ + '', + archs: archs, + viewOptions: { + initialDate: initialDate, + }, + }); + assert.strictEqual(calendar.$('.fc-day-grid .fc-event-container').length, 1, + "should be one event in the all day row"); + calendar.destroy(); + }); }); }); diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js index e0c5c6826e7..78e4fc5dc68 100644 --- a/addons/web/static/tests/views/form_tests.js +++ b/addons/web/static/tests/views/form_tests.js @@ -3921,7 +3921,7 @@ QUnit.module('Views', { QUnit.test('*_view_ref in context are passed correctly', function (assert) { var done = assert.async(); - assert.expect(4); + assert.expect(3); createAsyncView({ View: FormView, @@ -3938,8 +3938,6 @@ QUnit.module('Views', { var context = event.data.context.eval(); assert.strictEqual(context.tree_view_ref, 'module.tree_view_ref', "context should contain tree_view_ref"); - assert.notOk('some_context' in context, - "should not send record's context to load p's fields_view"); event.data.on_success(); } }, @@ -5790,6 +5788,61 @@ QUnit.module('Views', { form.destroy(); }); + QUnit.test('process the context for inline subview', function (assert) { + assert.expect(1); + + this.data.partner.records[0].p = [2]; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '
', + res_id: 1, + viewOptions: { + context: {hide_bar: true}, + }, + }); + assert.strictEqual(form.$('.o_list_view thead tr th').length, 1, + "there should be only one column"); + form.destroy(); + }); + + QUnit.test('process the context for subview not inline', function (assert) { + assert.expect(1); + + this.data.partner.records[0].p = [2]; + + var form = createView({ + View: FormView, + model: 'partner', + data: this.data, + arch: '
' + + '' + + '', + archs: { + "partner,false,list": '' + + '' + + '' + + '', + }, + res_id: 1, + viewOptions: { + context: {hide_bar: true}, + }, + }); + assert.strictEqual(form.$('.o_list_view thead tr th').length, 1, + "there should be only one column"); + form.destroy(); + }); + QUnit.test('rainbowman attributes correctly passed on button click', function (assert) { assert.expect(1); diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js index 3e11c2f42d5..b7ebf526dcb 100644 --- a/addons/web/static/tests/views/kanban_tests.js +++ b/addons/web/static/tests/views/kanban_tests.js @@ -1697,7 +1697,7 @@ QUnit.module('Views', { kanban.destroy(); }); - QUnit.only('resequence a record twice', function (assert) { + QUnit.test('resequence a record twice', function (assert) { assert.expect(10); this.data.partner.records = []; diff --git a/addons/web/tests/test_js.py b/addons/web/tests/test_js.py index 1614be64c43..17eb5c8beb2 100644 --- a/addons/web/tests/test_js.py +++ b/addons/web/tests/test_js.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import re import odoo.tests @@ -11,3 +12,19 @@ class WebSuite(odoo.tests.HttpCase): def test_01_js(self): self.phantom_js('/web/tests?mod=web', "", "", login='admin', timeout=300) + + def test_check_suite(self): + # verify no js test is using `QUnit.only` as it forbid any other test to be executed + re_only = re.compile('QUnit\.only\(') + + # As we currently aren't in a request context, we can't render `web.layout`. + # redefinied it as a minimal proxy template. + self.env.ref('web.layout').write({'arch_db': ''}) + + for asset in self.env['ir.qweb']._get_asset_content('web.qunit_suite', options={})[0]: + filename = asset['filename'] + if not filename or asset['atype'] != 'text/javascript': + continue + with open(filename, 'r') as fp: + if re_only.search(fp.read()): + self.fail("`QUnit.only()` used in file %r" % asset['url'])