summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Schippefilt <vsc@odoo.com>2019-03-06 14:02:32 +0100
committerAaron Bohy <aab@odoo.com>2019-03-06 20:07:17 +0100
commitab56e637b7f97ddcdbcc9baea99ae097e342409c (patch)
tree4cb47da9f7ef89b19d18429220a7507470ec12a9
parenteeed894fd50e477135e1ac9a82f6e98ce063ab90 (diff)
[REF] web: adapt code after jQuery update
Part of task 1896658 Co-authored-by: Aaron Bohy <aab@odoo.com> Co-authored-by: Christophe Matthieu <chm@odoo.com> Co-authored-by: Mathieu Duckerts-Antoine <dam@odoo.com> Co-authored-by: David Monjoie <dmo@odoo.com> Co-authored-by: Martin Geubelle <mge@odoo.com> Co-authored-by: svs-odoo <svs@odoo.com> Co-authored-by: Vincent Schippefilt <vsc@odoo.com>
-rw-r--r--addons/web/doc/client_action.rst7
-rw-r--r--addons/web/static/src/js/_deprecated/data.js75
-rw-r--r--addons/web/static/src/js/apps.js113
-rw-r--r--addons/web/static/src/js/boot.js108
-rw-r--r--addons/web/static/src/js/chrome/abstract_action.js4
-rw-r--r--addons/web/static/src/js/chrome/abstract_web_client.js11
-rw-r--r--addons/web/static/src/js/chrome/action_manager.js73
-rw-r--r--addons/web/static/src/js/chrome/action_manager_act_window.js105
-rw-r--r--addons/web/static/src/js/chrome/action_manager_report.js57
-rw-r--r--addons/web/static/src/js/chrome/action_mixin.js8
-rw-r--r--addons/web/static/src/js/chrome/loading.js2
-rw-r--r--addons/web/static/src/js/chrome/menu.js12
-rw-r--r--addons/web/static/src/js/chrome/pager.js7
-rw-r--r--addons/web/static/src/js/chrome/sidebar.js2
-rw-r--r--addons/web/static/src/js/chrome/systray_menu.js9
-rw-r--r--addons/web/static/src/js/chrome/user_menu.js8
-rw-r--r--addons/web/static/src/js/chrome/web_client.js65
-rw-r--r--addons/web/static/src/js/core/ajax.js325
-rw-r--r--addons/web/static/src/js/core/concurrency.js239
-rw-r--r--addons/web/static/src/js/core/dialog.js10
-rw-r--r--addons/web/static/src/js/core/dom.js21
-rw-r--r--addons/web/static/src/js/core/misc.js4
-rw-r--r--addons/web/static/src/js/core/mixins.js31
-rw-r--r--addons/web/static/src/js/core/mvc.js11
-rw-r--r--addons/web/static/src/js/core/rpc.js2
-rw-r--r--addons/web/static/src/js/core/service_mixins.js92
-rw-r--r--addons/web/static/src/js/core/session.js68
-rw-r--r--addons/web/static/src/js/core/translation.js4
-rw-r--r--addons/web/static/src/js/core/widget.js34
-rw-r--r--addons/web/static/src/js/fields/abstract_field.js49
-rw-r--r--addons/web/static/src/js/fields/basic_fields.js23
-rw-r--r--addons/web/static/src/js/fields/field_registry.js2
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js257
-rw-r--r--addons/web/static/src/js/fields/upgrade_fields.js2
-rw-r--r--addons/web/static/src/js/public/public_root.js14
-rw-r--r--addons/web/static/src/js/public/public_widget.js6
-rw-r--r--addons/web/static/src/js/report/client_action.js4
-rw-r--r--addons/web/static/src/js/services/ajax_service.js25
-rw-r--r--addons/web/static/src/js/services/core.js12
-rw-r--r--addons/web/static/src/js/services/crash_manager.js2
-rw-r--r--addons/web/static/src/js/services/data_manager.js16
-rw-r--r--addons/web/static/src/js/services/report_service.js2
-rw-r--r--addons/web/static/src/js/tools/debug_manager.js13
-rw-r--r--addons/web/static/src/js/tools/test_menus.js109
-rw-r--r--addons/web/static/src/js/views/abstract_controller.js75
-rw-r--r--addons/web/static/src/js/views/abstract_model.js2
-rw-r--r--addons/web/static/src/js/views/abstract_renderer.js14
-rw-r--r--addons/web/static/src/js/views/abstract_view.js7
-rw-r--r--addons/web/static/src/js/views/basic/basic_controller.js112
-rw-r--r--addons/web/static/src/js/views/basic/basic_model.js417
-rw-r--r--addons/web/static/src/js/views/basic/basic_renderer.js63
-rw-r--r--addons/web/static/src/js/views/basic/basic_view.js4
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_controller.js12
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_model.js49
-rw-r--r--addons/web/static/src/js/views/calendar/calendar_renderer.js46
-rw-r--r--addons/web/static/src/js/views/control_panel/control_panel_controller.js6
-rw-r--r--addons/web/static/src/js/views/control_panel/control_panel_model.js14
-rw-r--r--addons/web/static/src/js/views/control_panel/control_panel_renderer.js14
-rw-r--r--addons/web/static/src/js/views/control_panel/search/filter_menu.js4
-rw-r--r--addons/web/static/src/js/views/control_panel/search/search_bar.js19
-rw-r--r--addons/web/static/src/js/views/control_panel/search/search_bar_autocomplete_sources.js24
-rw-r--r--addons/web/static/src/js/views/control_panel/search/search_filters.js8
-rw-r--r--addons/web/static/src/js/views/field_manager_mixin.js16
-rw-r--r--addons/web/static/src/js/views/form/form_controller.js51
-rw-r--r--addons/web/static/src/js/views/form/form_renderer.js119
-rw-r--r--addons/web/static/src/js/views/form/form_view.js4
-rw-r--r--addons/web/static/src/js/views/graph/graph_model.js10
-rw-r--r--addons/web/static/src/js/views/graph/graph_renderer.js2
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_column.js13
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_controller.js39
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_model.js33
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_record.js49
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_record_quick_create.js21
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_renderer.js62
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js53
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_view.js2
-rw-r--r--addons/web/static/src/js/views/kanban/quick_create_form_view.js2
-rw-r--r--addons/web/static/src/js/views/kanban/search_panel.js30
-rw-r--r--addons/web/static/src/js/views/list/list_controller.js49
-rw-r--r--addons/web/static/src/js/views/list/list_editable_renderer.js122
-rw-r--r--addons/web/static/src/js/views/list/list_renderer.js92
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_model.js23
-rw-r--r--addons/web/static/src/js/views/pivot/pivot_renderer.js2
-rw-r--r--addons/web/static/src/js/views/standalone_field_manager_mixin.js2
-rw-r--r--addons/web/static/src/js/views/view_dialogs.js19
-rw-r--r--addons/web/static/src/js/views/view_utils.js2
-rw-r--r--addons/web/static/src/js/widgets/attach_document.js41
-rw-r--r--addons/web/static/src/js/widgets/change_password.js4
-rw-r--r--addons/web/static/src/js/widgets/data_export.js38
-rw-r--r--addons/web/static/src/js/widgets/domain_selector.js25
-rw-r--r--addons/web/static/src/js/widgets/domain_selector_dialog.js4
-rw-r--r--addons/web/static/src/js/widgets/iframe_widget.js2
-rw-r--r--addons/web/static/src/js/widgets/model_field_selector.js24
-rw-r--r--addons/web/static/src/js/widgets/name_and_signature.js10
-rw-r--r--addons/web/static/src/js/widgets/pie_chart.js2
-rw-r--r--addons/web/static/src/js/widgets/switch_company_menu.js12
-rw-r--r--addons/web/static/tests/chrome/action_manager_mobile_tests.js22
-rw-r--r--addons/web/static/tests/chrome/action_manager_tests.js1072
-rw-r--r--addons/web/static/tests/chrome/keyboard_navigation_mixin_tests.js16
-rw-r--r--addons/web/static/tests/chrome/pager_tests.js36
-rw-r--r--addons/web/static/tests/chrome/user_menu_tests.js4
-rw-r--r--addons/web/static/tests/core/concurrency_tests.js533
-rw-r--r--addons/web/static/tests/core/dom_tests.js6
-rw-r--r--addons/web/static/tests/core/mixins_tests.js6
-rw-r--r--addons/web/static/tests/core/widget_tests.js99
-rw-r--r--addons/web/static/tests/fields/basic_fields_mobile_tests.js28
-rw-r--r--addons/web/static/tests/fields/basic_fields_tests.js1187
-rw-r--r--addons/web/static/tests/fields/relational_fields/field_many2many_tests.js233
-rw-r--r--addons/web/static/tests/fields/relational_fields/field_many2one_tests.js1080
-rw-r--r--addons/web/static/tests/fields/relational_fields/field_one2many_tests.js2021
-rw-r--r--addons/web/static/tests/fields/relational_fields_mobile_tests.js12
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js749
-rw-r--r--addons/web/static/tests/fields/special_fields.js29
-rw-r--r--addons/web/static/tests/fields/upgrade_fields_tests.js10
-rw-r--r--addons/web/static/tests/helpers/mock_server.js71
-rw-r--r--addons/web/static/tests/helpers/qunit_asserts.js17
-rw-r--r--addons/web/static/tests/helpers/qunit_config.js58
-rw-r--r--addons/web/static/tests/helpers/test_utils.js85
-rw-r--r--addons/web/static/tests/helpers/test_utils_create.js94
-rw-r--r--addons/web/static/tests/helpers/test_utils_dom.js78
-rw-r--r--addons/web/static/tests/helpers/test_utils_fields.js102
-rw-r--r--addons/web/static/tests/helpers/test_utils_file.js35
-rw-r--r--addons/web/static/tests/helpers/test_utils_form.js10
-rw-r--r--addons/web/static/tests/helpers/test_utils_graph.js2
-rw-r--r--addons/web/static/tests/helpers/test_utils_kanban.js15
-rw-r--r--addons/web/static/tests/helpers/test_utils_mock.js31
-rw-r--r--addons/web/static/tests/helpers/test_utils_modal.js2
-rw-r--r--addons/web/static/tests/helpers/test_utils_pivot.js6
-rw-r--r--addons/web/static/tests/qweb_tests.js26
-rw-r--r--addons/web/static/tests/services/notification_service_tests.js126
-rw-r--r--addons/web/static/tests/tools/debug_manager_tests.js32
-rw-r--r--addons/web/static/tests/views/abstract_controller_tests.js151
-rw-r--r--addons/web/static/tests/views/abstract_view_banner_tests.js6
-rw-r--r--addons/web/static/tests/views/abstract_view_tests.js60
-rw-r--r--addons/web/static/tests/views/basic_model_tests.js3035
-rw-r--r--addons/web/static/tests/views/calendar_mobile_tests.js6
-rw-r--r--addons/web/static/tests/views/calendar_tests.js652
-rw-r--r--addons/web/static/tests/views/control_panel_tests.js12
-rw-r--r--addons/web/static/tests/views/form_tests.js1893
-rw-r--r--addons/web/static/tests/views/graph_tests.js173
-rw-r--r--addons/web/static/tests/views/kanban_mobile_tests.js30
-rw-r--r--addons/web/static/tests/views/kanban_model_tests.js33
-rw-r--r--addons/web/static/tests/views/kanban_tests.js1216
-rw-r--r--addons/web/static/tests/views/list_tests.js1099
-rw-r--r--addons/web/static/tests/views/mobile_control_panel_tests.js12
-rw-r--r--addons/web/static/tests/views/pivot_tests.js439
-rw-r--r--addons/web/static/tests/views/qweb_tests.js21
-rw-r--r--addons/web/static/tests/views/search_filter_menu_tests.js109
-rw-r--r--addons/web/static/tests/views/search_groupby_menu_tests.js54
-rw-r--r--addons/web/static/tests/views/search_panel_tests.js258
-rw-r--r--addons/web/static/tests/views/search_view_tests.js431
-rw-r--r--addons/web/static/tests/views/view_dialogs_tests.js116
-rw-r--r--addons/web/static/tests/widgets/data_export_tests.js50
-rw-r--r--addons/web/static/tests/widgets/domain_selector_tests.js43
-rw-r--r--addons/web/static/tests/widgets/dropdown_menu_tests.js60
-rw-r--r--addons/web/static/tests/widgets/model_field_selector_tests.js40
156 files changed, 11217 insertions, 10627 deletions
diff --git a/addons/web/doc/client_action.rst b/addons/web/doc/client_action.rst
index 9b729e228a6..4852400df10 100644
--- a/addons/web/doc/client_action.rst
+++ b/addons/web/doc/client_action.rst
@@ -83,18 +83,19 @@ method.
As required by :js:class:`~openerp.web.Widget`'s contract, if
:js:func:`~openerp.web.Widget.start()` executes any asynchronous
- code it should return a ``$.Deferred`` so callers know when it's
+ code it should return a ``Promise`` so callers know when it's
ready for interaction.
.. code-block:: javascript
start: function () {
- return $.when(
+ return Promise.all([
this._super(),
// Simply read the res.widget object this action should display
new instance.web.Model('res.widget').call(
'read', [[this.widget_id], ['title']])
- .then(this.proxy('on_widget_loaded'));
+ .then(this.proxy('on_widget_loaded')
+ ]);
}
The client action can then behave exactly as it wishes to within its
diff --git a/addons/web/static/src/js/_deprecated/data.js b/addons/web/static/src/js/_deprecated/data.js
index 984f0bbaddb..acac959fcc8 100644
--- a/addons/web/static/src/js/_deprecated/data.js
+++ b/addons/web/static/src/js/_deprecated/data.js
@@ -101,7 +101,7 @@ var Query = Class.extend({
* Fetches the first record matching the query, or null
*
* @param {Object} [options] additional options for the rpc() method
- * @returns {jQuery.Deferred<Object|null>}
+ * @returns {Promise<Object|null>}
*/
first: function (options) {
var self = this;
@@ -115,7 +115,7 @@ var Query = Class.extend({
* Fetches all records matching the query
*
* @param {Object} [options] additional options for the rpc() method
- * @returns {jQuery.Deferred<Array<>>}
+ * @returns {Promise<Array<>>}
*/
all: function (options) {
return this._execute(options);
@@ -123,10 +123,10 @@ var Query = Class.extend({
/**
* Fetches the number of records matching the query in the database
*
- * @returns {jQuery.Deferred<Number>}
+ * @returns {Promise<Number>}
*/
count: function () {
- if (this._count !== undefined) { return $.when(this._count); }
+ if (this._count !== undefined) { return Promise.resolve(this._count); }
return this._model.call(
'search_count', [this._filter], {
context: this._model.context(this._context)});
@@ -367,11 +367,12 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* @param {Array} ids identifiers of the records to read
* @param {Array} [fields] fields to read and return, by default all fields are returned
* @param {Object} [options]
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
read_ids: function (ids, fields, options) {
- if (_.isEmpty(ids))
- return $.Deferred().resolve([]);
+ if (_.isEmpty(ids)) {
+ return Promise.resolve([]);
+ }
options = options || {};
var method = 'read';
@@ -405,7 +406,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* @params {Object} [options]
* @param {Number} [options.offset=0] The index from which selected records should be returned
* @param {Number} [options.limit=null] The maximum number of records to return
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
read_slice: function (fields, options) {
var self = this;
@@ -414,21 +415,23 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
.limit(options.limit || false)
.offset(options.offset || 0)
.all();
- return this.orderer.add(query).done(function (records) {
+ var prom = this.orderer.add(query);
+ prom.then(function (records) {
self.ids = _(records).pluck('id');
});
+ return prom;
},
/**
* Reads the current dataset record (from its index)
*
* @params {Array} [fields] fields to read and return, by default all fields are returned
* @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
read_index: function (fields, options) {
options = options || {};
return this.read_ids([this.ids[this.index]], fields, options).then(function (records) {
- if (_.isEmpty(records)) { return $.Deferred().reject().promise(); }
+ if (_.isEmpty(records)) { return Promise.reject(); }
return records[0];
});
},
@@ -437,7 +440,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
*
* @param {Array} [fields] fields to get default values for, by default all defaults are read
* @param {Object} [options.context] context data to add to the request payload, on top of the DataSet's own context
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
default_get: function (fields, options) {
options = options || {};
@@ -451,15 +454,17 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* @param {Object} options Dictionary that can contain the following keys:
* - readonly_fields: Values from readonly fields that were updated by
* on_changes. Only used by the BufferedDataSet to make the o2m work correctly.
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
create: function (data, options) {
var self = this;
- return this._model.call('create', [data], {
+ var prom = this._model.call('create', [data], {
context: this.get_context()
- }).done(function () {
+ });
+ prom.then(function () {
self.trigger('dataset_changed', data, options);
});
+ return prom;
},
/**
* Saves the provided data in an existing db record
@@ -470,16 +475,18 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* - context: The context to use in the server-side call.
* - readonly_fields: Values from readonly fields that were updated by
* on_changes. Only used by the BufferedDataSet to make the o2m work correctly.
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
write: function (id, data, options) {
options = options || {};
var self = this;
- return this._model.call('write', [[id], data], {
+ var prom = this._model.call('write', [[id], data], {
context: this.get_context(options.context)
- }).done(function () {
+ });
+ prom.then(function () {
self.trigger('dataset_changed', id, data, options);
});
+ return prom;
},
/**
* Deletes an existing record from the database
@@ -488,11 +495,13 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
*/
unlink: function (ids) {
var self = this;
- return this._model.call('unlink', [ids], {
+ var prom = this._model.call('unlink', [ids], {
context: this.get_context()
- }).done(function () {
+ });
+ prom.then(function () {
self.trigger('dataset_changed', ids);
});
+ return prom;
},
/**
* Calls an arbitrary RPC method
@@ -501,7 +510,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* @param {Array} [args] arguments to pass to the method
* @param {Function} callback
* @param {Function} error_callback
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
call: function (method, args) {
return this._model.call(method, args);
@@ -511,7 +520,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
*
* @param {String} method
* @param {Array} [args]
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
call_button: function (method, args) {
return this._model.call_button(method, args);
@@ -520,7 +529,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* Fetches the "readable name" for records, based on intrinsic rules
*
* @param {Array} ids
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
name_get: function (ids) {
return this._model.call('name_get', [ids], {context: this.get_context()});
@@ -532,7 +541,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* @param {String} [operator='ilike'] matching operator to use with the provided name value
* @param {Number} [limit=0] maximum number of matches to return
* @param {Function} callback function to call with name_search result
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
name_search: function (name, domain, operator, limit) {
return this._model.call('name_search', {
@@ -603,7 +612,7 @@ var DataSet = Class.extend(mixins.PropertiesMixin, {
* Resequence records.
*
* @param {Array} ids identifiers of the records to resequence
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
resequence: function (ids, options) {
options = options || {};
@@ -643,7 +652,7 @@ var DataSetStatic = DataSet.extend({
unlink: function (ids) {
this.set_ids(_.without.apply(null, [this.ids].concat(ids)));
this.trigger('unlink', ids);
- return $.Deferred().resolve({result: true});
+ return Promise.resolve({result: true});
},
});
@@ -674,7 +683,7 @@ var DataSetSearch = DataSet.extend({
* @param {Array} [options.domain] domain data to add to the request payload, ANDed with the dataset's domain
* @param {Number} [options.offset=0] The index from which selected records should be returned
* @param {Number} [options.limit=null] The maximum number of records to return
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
read_slice: function (fields, options) {
options = options || {};
@@ -686,11 +695,13 @@ var DataSetSearch = DataSet.extend({
.limit(options.limit || false);
q = q.order_by.apply(q, this._sort);
- return this.orderer.add(q.all()).done(function (records) {
+ var prom = this.orderer.add(q.all());
+ prom.then(function (records) {
// FIXME: not sure about that one, *could* have discarded count
- q.count().done(function (count) { self._length = count; });
+ q.count().then(function (count) { self._length = count; });
self.ids = _(records).pluck('id');
});
+ return prom;
},
get_domain: function (other_domain) {
return this._model.domain(other_domain);
@@ -717,10 +728,12 @@ var DataSetSearch = DataSet.extend({
},
unlink: function (ids, callback, error_callback) {
var self = this;
- return this._super(ids).done(function () {
+ var prom = this._super(ids);
+ prom.then(function () {
self.remove_ids( ids);
self.trigger("dataset_changed", ids, callback, error_callback);
});
+ return prom;
},
size: function () {
if (this._length !== null) {
@@ -801,7 +814,7 @@ var Model = Class.extend({
* @param {Array} [args] positipyEvalonal arguments
* @param {Object} [kwargs] keyword arguments
* @param {Object} [options] additional options for the rpc() method
- * @returns {jQuery.Deferred<>} call result
+ * @returns {Promise<>} call result
*/
call: function (method, args, kwargs, options) {
args = args || [];
diff --git a/addons/web/static/src/js/apps.js b/addons/web/static/src/js/apps.js
index aadcc700984..739317337ba 100644
--- a/addons/web/static/src/js/apps.js
+++ b/addons/web/static/src/js/apps.js
@@ -22,20 +22,21 @@ var Apps = AbstractAction.extend({
},
get_client: function() {
- // return the client via a deferred, resolved or rejected depending if
+ // return the client via a promise, resolved or rejected depending if
// the remote host is available or not.
var check_client_available = function(client) {
- var d = $.Deferred();
var i = new Image();
- i.onerror = function() {
- d.reject(client);
- };
- i.onload = function() {
- d.resolve(client);
- };
+ var def = new Promise(function (resolve, reject) {
+ i.onerror = function() {
+ reject(client);
+ };
+ i.onload = function() {
+ resolve(client);
+ };
+ });
var ts = new Date().getTime();
i.src = _.str.sprintf('%s/web/static/src/img/sep-a.gif?%s', client.origin, ts);
- return d.promise();
+ return def;
};
if (apps_client) {
return check_client_available(apps_client);
@@ -105,58 +106,56 @@ var Apps = AbstractAction.extend({
start: function() {
var self = this;
- var def = $.Deferred();
- self.get_client().then(function(client) {
- self.client = client;
-
- var qs = {db: client.dbname};
- if (session.debug) {
- qs.debug = session.debug;
- }
- var u = $.param.querystring(client.origin + "/apps/embed/client", qs);
- var css = {width: '100%', height: '750px'};
- self.$ifr = $('<iframe>').attr('src', u);
-
- self.uniq = _.uniqueId('apps');
- $(window).on("message." + self.uniq, self.proxy('_on_message'));
-
- self.on('message:ready', self, function(m) {
- var w = this.$ifr[0].contentWindow;
- var act = {
- type: 'ir.actions.client',
- tag: this.remote_action_tag,
- params: _.extend({}, this.params, {
- db: session.db,
- origin: session.origin,
- })
- };
- w.postMessage({type:'action', action: act}, client.origin);
- });
+ return new Promise(function (resolve, reject) {
+ self.get_client().then(function (client) {
+ self.client = client;
+
+ var qs = {db: client.dbname};
+ if (session.debug) {
+ qs.debug = session.debug;
+ }
+ var u = $.param.querystring(client.origin + "/apps/embed/client", qs);
+ var css = {width: '100%', height: '750px'};
+ self.$ifr = $('<iframe>').attr('src', u);
+
+ self.uniq = _.uniqueId('apps');
+ $(window).on("message." + self.uniq, self.proxy('_on_message'));
+
+ self.on('message:ready', self, function(m) {
+ var w = this.$ifr[0].contentWindow;
+ var act = {
+ type: 'ir.actions.client',
+ tag: this.remote_action_tag,
+ params: _.extend({}, this.params, {
+ db: session.db,
+ origin: session.origin,
+ })
+ };
+ w.postMessage({type:'action', action: act}, client.origin);
+ });
- self.on('message:set_height', self, function(m) {
- this.$ifr.height(m.height);
- });
+ self.on('message:set_height', self, function(m) {
+ this.$ifr.height(m.height);
+ });
- self.on('message:blockUI', self, function() { framework.blockUI(); });
- self.on('message:unblockUI', self, function() { framework.unblockUI(); });
- self.on('message:warn', self, function(m) {self.do_warn(m.title, m.message, m.sticky); });
-
- self.$ifr.appendTo(self.$('.o_content')).css(css).addClass('apps-client');
-
- def.resolve();
- }, function() {
- self.do_warn(_t('Odoo Apps will be available soon'), _t('Showing locally available modules'), true);
- return self._rpc({
- route: '/web/action/load',
- params: {action_id: self.failback_action_id},
- }).then(function(action) {
- return self.do_action(action);
- }).always(function () {
- def.reject();
+ self.on('message:blockUI', self, function() { framework.blockUI(); });
+ self.on('message:unblockUI', self, function() { framework.unblockUI(); });
+ self.on('message:warn', self, function(m) {self.do_warn(m.title, m.message, m.sticky); });
+
+ self.$ifr.appendTo(self.$('.o_content')).css(css).addClass('apps-client');
+
+ resolve();
+ }, function() {
+ self.do_warn(_t('Odoo Apps will be available soon'), _t('Showing locally available modules'), true);
+ return self._rpc({
+ route: '/web/action/load',
+ params: {action_id: self.failback_action_id},
+ }).then(function(action) {
+ return self.do_action(action);
+ }).then(reject, reject);
});
});
- return def;
- },
+ }
});
var AppsUpdates = Apps.extend({
diff --git a/addons/web/static/src/js/boot.js b/addons/web/static/src/js/boot.js
index 994b945b1d3..cf1cbaba180 100644
--- a/addons/web/static/src/js/boot.js
+++ b/addons/web/static/src/js/boot.js
@@ -6,8 +6,8 @@
* @name openerp
* @namespace openerp
*
- * Each module can return a deferred. In that case, the module is marked as loaded
- * only when the deferred is resolved, and its value is equal to the resolved value.
+ * Each module can return a promise. In that case, the module is marked as loaded
+ * only when the promise is resolved, and its value is equal to the resolved value.
* The module can be rejected (unloaded). This will be logged in the console as info.
*
* logs:
@@ -17,7 +17,7 @@
* Failed modules:
* A javascript error is detected
* Rejected modules:
- * The module returns a rejected deferred. It (and its dependent modules)
+ * The module returns a rejected promise. It (and its dependent modules)
* is not loaded.
* Rejected linked modules:
* Modules who depend on a rejected module
@@ -27,14 +27,14 @@
* Non loaded or failed module informations for debugging
*/
-(function() {
+(function () {
"use strict";
var jobs = [];
var factories = Object.create(null);
var job_names = [];
var job_deps = [];
- var job_deferred = [];
+ var job_promise = [];
var services = Object.create({});
@@ -45,15 +45,20 @@
var debug = ($.deparam($.param.querystring()).debug !== undefined);
var odoo = window.odoo = window.odoo || {};
+ var didLogInfoResolve;
+ var didLogInfoPromise = new Promise(function (resolve) {
+ didLogInfoResolve = resolve;
+ });
+
_.extend(odoo, {
testing: typeof QUnit === "object",
debug: debug,
remaining_jobs: jobs,
__DEBUG__: {
- didLogInfo: $.Deferred(),
+ didLogInfo: didLogInfoPromise,
get_dependencies: function (name, transitive) {
- var deps = name instanceof Array ? name: [name],
+ var deps = name instanceof Array ? name : [name],
changed;
do {
changed = false;
@@ -67,26 +72,26 @@
return deps;
},
get_dependents: function (name) {
- return _.pluck(_.where(job_deps, {from: name}), 'to');
+ return _.pluck(_.where(job_deps, { from: name }), 'to');
},
get_waited_jobs: function () {
- return _.uniq(_.map(jobs, function(job) {return job.name;}));
+ return _.uniq(_.map(jobs, function (job) { return job.name; }));
},
get_missing_jobs: function () {
var self = this;
var waited = this.get_waited_jobs();
var missing = [];
- _.each(waited, function(job) {
- _.each(self.get_dependencies(job), function(job) {
+ _.each(waited, function (job) {
+ _.each(self.get_dependencies(job), function (job) {
if (!(job in self.services)) {
missing.push(job);
}
});
});
- return _.filter(_.difference(_.uniq(missing), waited), function (job) {return !job.error;});
+ return _.filter(_.difference(_.uniq(missing), waited), function (job) { return !job.error; });
},
get_failed_jobs: function () {
- return _.filter(jobs, function (job) {return !!job.error;});
+ return _.filter(jobs, function (job) { return !!job.error; });
},
factories: factories,
services: services,
@@ -109,10 +114,10 @@
if (odoo.debug) {
if (!(deps instanceof Array)) {
- throw new Error ('Dependencies should be defined by an array', deps);
+ throw new Error('Dependencies should be defined by an array', deps);
}
if (typeof factory !== 'function') {
- throw new Error ('Factory should be defined by a function', factory);
+ throw new Error('Factory should be defined by a function', factory);
}
if (typeof name !== 'string') {
throw new Error("Invalid name definition (should be a string", name);
@@ -133,7 +138,7 @@
job_names.push(name);
_.each(deps, function (dep) {
- job_deps.push({from:dep, to:name});
+ job_deps.push({ from: dep, to: name });
});
this.process_jobs(jobs, services);
@@ -149,7 +154,7 @@
var job;
var jobdep;
- for (var k=0; k<jobs.length; k++) {
+ for (var k = 0; k < jobs.length; k++) {
debug_jobs[jobs[k].name] = job = {
dependencies: jobs[k].deps,
dependents: odoo.__DEBUG__.get_dependents(jobs[k].name),
@@ -162,10 +167,10 @@
job.rejected = jobs[k].rejected;
rejected.push(job.name);
}
- var deps = odoo.__DEBUG__.get_dependencies( job.name );
- for (var i=0; i<deps.length; i++) {
+ var deps = odoo.__DEBUG__.get_dependencies(job.name);
+ for (var i = 0; i < deps.length; i++) {
if (job.name !== deps[i] && !(deps[i] in services)) {
- jobdep = debug_jobs[deps[i]] || (deps[i] in factories && _.find(jobs, function (job) { return job.name === deps[i];}));
+ jobdep = debug_jobs[deps[i]] || (deps[i] in factories && _.find(jobs, function (job) { return job.name === deps[i]; }));
if (jobdep && jobdep.rejected) {
if (!job.rejected) {
job.rejected = [];
@@ -212,48 +217,49 @@
missing: missing,
failed: _.pluck(failed, 'name'),
};
- odoo.__DEBUG__.didLogInfo.resolve();
+ didLogInfoResolve();
},
process_jobs: function (jobs, services) {
var job;
- function process_job (job) {
+ function process_job(job) {
var require = make_require(job);
var job_exec;
- var def = $.Deferred();
- try {
- job_exec = job.factory.call(null, require);
- jobs.splice(jobs.indexOf(job), 1);
- job_deferred.push(def);
- } catch (e) {
- job.error = e;
- console.error('Error while loading ' + job.name);
- console.error(e.stack);
- }
- if (!job.error) {
- $.when(job_exec).then(
- function (data) {
- services[job.name] = data;
- def.resolve();
- odoo.process_jobs(jobs, services);
- }, function (e) {
- job.rejected = e || true;
- jobs.push(job);
- def.resolve();
- }
- );
- }
+ var def = new Promise(function (resolve) {
+ try {
+ job_exec = job.factory.call(null, require);
+ jobs.splice(jobs.indexOf(job), 1);
+ } catch (e) {
+ job.error = e;
+ console.error('Error while loading ' + job.name);
+ console.error(e.stack);
+ }
+ if (!job.error) {
+ Promise.resolve(job_exec).then(
+ function (data) {
+ services[job.name] = data;
+ resolve();
+ odoo.process_jobs(jobs, services);
+ }).guardedCatch(function (e) {
+ job.rejected = e || true;
+ jobs.push(job);
+ resolve();
+ }
+ );
+ }
+ });
+ job_promise.push(def);
}
- function is_ready (job) {
+ function is_ready(job) {
return !job.error && !job.rejected && _.every(job.factory.deps, function (name) { return name in services; });
}
- function make_require (job) {
+ function make_require(job) {
var deps = _.pick(services, job.deps);
- function require (name) {
+ function require(name) {
if (!(name in deps)) {
console.error('Undefined dependency: ', name);
} else {
@@ -278,9 +284,9 @@
// automatically log errors detected when loading modules
var log_when_loaded = function () {
_.delay(function () {
- var len = job_deferred.length;
- $.when.apply($, job_deferred).then(function () {
- if (len === job_deferred.length) {
+ var len = job_promise.length;
+ Promise.all(job_promise).then(function () {
+ if (len === job_promise.length) {
odoo.log();
} else {
log_when_loaded();
diff --git a/addons/web/static/src/js/chrome/abstract_action.js b/addons/web/static/src/js/chrome/abstract_action.js
index a5f98434ddb..1b258ccc6f6 100644
--- a/addons/web/static/src/js/chrome/abstract_action.js
+++ b/addons/web/static/src/js/chrome/abstract_action.js
@@ -104,7 +104,7 @@ var AbstractAction = Widget.extend(ActionMixin, {
};
});
}
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
var controlPanelView = new self.config.ControlPanelView(params);
return controlPanelView.getController(self).then(function (controlPanel) {
self._controlPanel = controlPanel;
@@ -112,7 +112,7 @@ var AbstractAction = Widget.extend(ActionMixin, {
});
});
}
- return $.when();
+ return Promise.resolve();
},
/**
* @override
diff --git a/addons/web/static/src/js/chrome/abstract_web_client.js b/addons/web/static/src/js/chrome/abstract_web_client.js
index 7082f26e69d..68ac157868d 100644
--- a/addons/web/static/src/js/chrome/abstract_web_client.js
+++ b/addons/web/static/src/js/chrome/abstract_web_client.js
@@ -78,7 +78,7 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
if (event.data.on_success) {
event.data.on_success(result);
}
- }).fail(function (result) {
+ }).guardedCatch(function (result) {
if (event.data.on_fail) {
event.data.on_fail(result);
}
@@ -116,17 +116,17 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
.then(function () {
self.$el.toggleClass('o_rtl', _t.database.parameters.direction === "rtl");
self.bind_events();
- return $.when(
+ return Promise.all([
self.set_action_manager(),
self.set_loading()
- );
+ ]);
}).then(function () {
if (session.session_is_valid()) {
return self.show_application();
} else {
// database manager needs the webclient to keep going even
// though it has no valid session
- return $.when();
+ return Promise.resolve();
}
}).then(function () {
// Listen to 'scroll' event and propagate it on main bus
@@ -145,12 +145,13 @@ var AbstractWebClient = Widget.extend(ServiceProviderMixin, KeyboardNavigationMi
this.$el.on('mouseenter', '.oe_systray > div:not([data-toggle=tooltip])', function () {
$(this).attr('data-toggle', 'tooltip').tooltip().trigger('mouseenter');
});
+ // TODO: this handler seems useless since 11.0, should be removed
this.$el.on('click', '.oe_dropdown_toggle', function (ev) {
ev.preventDefault();
var $toggle = $(this);
var doc_width = $(document).width();
var $menu = $toggle.siblings('.oe_dropdown_menu');
- $menu = $menu.size() >= 1 ? $menu : $toggle.find('.oe_dropdown_menu');
+ $menu = $menu.length >= 1 ? $menu : $toggle.find('.oe_dropdown_menu');
var state = $menu.is('.oe_opened');
setTimeout(function () {
// Do not alter propagation
diff --git a/addons/web/static/src/js/chrome/action_manager.js b/addons/web/static/src/js/chrome/action_manager.js
index 107c6e314eb..0537b45deb5 100644
--- a/addons/web/static/src/js/chrome/action_manager.js
+++ b/addons/web/static/src/js/chrome/action_manager.js
@@ -92,7 +92,7 @@ var ActionManager = Widget.extend({
* will be restored. It ensures that the current controller can be left (for
* instance, that it has no unsaved changes).
*
- * @returns {Deferred} resolved if the current controller can be left,
+ * @returns {Promise} resolved if the current controller can be left,
* rejected otherwise.
*/
clearUncommittedChanges: function () {
@@ -100,7 +100,7 @@ var ActionManager = Widget.extend({
if (currentController) {
return currentController.widget.canBeRemoved();
}
- return $.when();
+ return Promise.resolve();
},
/**
* This is the entry point to execute Odoo actions, given as an ID in
@@ -123,7 +123,7 @@ var ActionManager = Widget.extend({
* is useful when we come from a loadState())
* @param {boolean} [options.replace_last_action=false] set to true to
* replace last part of the breadcrumbs with the action
- * @return {$.Deferred<Object>} resolved with the action when the action is
+ * @return {Promise<Object>} resolved with the action when the action is
* loaded and appended to the DOM ; rejected if the action can't be
* executed (e.g. if doAction has been called to execute another action
* before this one was complete).
@@ -155,7 +155,7 @@ var ActionManager = Widget.extend({
});
}
- return this.dp.add($.when(def)).then(function () {
+ return this.dp.add(Promise.resolve(def)).then(function () {
// action.target 'main' is equivalent to 'current' except that it
// also clears the breadcrumbs
options.clear_breadcrumbs = action.target === 'main' ||
@@ -211,12 +211,12 @@ var ActionManager = Widget.extend({
* @param {Object} state
* @param {integer|string} [state.action] the action to execute (given its
* id or tag for client actions)
- * @returns {Deferred} resolved when the UI has been updated
+ * @returns {Promise} resolved when the UI has been updated
*/
loadState: function (state) {
var action;
if (!state.action) {
- return $.when();
+ return Promise.resolve();
}
if (_.isString(state.action) && core.action_registry.contains(state.action)) {
action = {
@@ -299,7 +299,7 @@ var ActionManager = Widget.extend({
* @param {string} [action.target="current"] set to "new" to render the
* controller in a dialog
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the controller is started and appended
+ * @returns {Promise} resolved when the controller is started and appended
*/
_executeAction: function (action, options) {
var self = this;
@@ -338,7 +338,7 @@ var ActionManager = Widget.extend({
return action;
})
- .fail(function () {
+ .guardedCatch(function () {
self._removeAction(action.jsID);
});
},
@@ -349,7 +349,7 @@ var ActionManager = Widget.extend({
* @private
* @param {Object} action
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the controller is rendered inside a
+ * @returns {Promise} resolved when the controller is rendered inside a
* dialog appended to the DOM
*/
_executeActionInDialog: function (action, options) {
@@ -401,7 +401,7 @@ var ActionManager = Widget.extend({
return action;
});
- }).fail(function () {
+ }).guardedCatch(function () {
self._removeAction(action.jsID);
});
},
@@ -412,14 +412,14 @@ var ActionManager = Widget.extend({
* @param {Object} action the description of the action to execute
* @param {string} action.tag the key of the action in the action_registry
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the client action has been executed
+ * @returns {Promise} resolved when the client action has been executed
*/
_executeClientAction: function (action, options) {
var self = this;
var ClientAction = core.action_registry.get(action.tag);
if (!ClientAction) {
console.error("Could not find client action " + action.tag, action);
- return $.Deferred().reject();
+ return Promise.reject();
}
if (!(ClientAction.prototype instanceof AbstractAction)) {
console.warn('The client action ' + action.tag + ' should be an instance of AbstractAction!');
@@ -431,7 +431,7 @@ var ActionManager = Widget.extend({
if (next) {
return this.doAction(next, options);
}
- return $.when();
+ return Promise.resolve();
}
var controllerID = _.uniqueId('controller_');
@@ -449,12 +449,14 @@ var ActionManager = Widget.extend({
};
this.controllers[controllerID] = controller;
action.controllerID = controllerID;
- return this._executeAction(action, options).done(function () {
+ var prom = this._executeAction(action, options);
+ prom.then(function () {
// AAB: this should be done automatically in AbstractAction, so that
// it can be overriden by actions that have specific stuff to push
// (e.g. Discuss, Views)
self._pushState(controllerID, {});
});
+ return prom;
},
/**
* Executes actions of type 'ir.actions.act_window_close', i.e. closes the
@@ -469,7 +471,7 @@ var ActionManager = Widget.extend({
* @param {Object} [action.effect] effect to show up, e.g. rainbow man.
* @param {Object} [action.infos] infos on performing the close action.
* Useful for providing some context for the `on_close` handler.
- * @returns {Deferred} resolved immediately
+ * @returns {Promise} resolved immediately
*/
_executeCloseAction: function (action, options) {
var result;
@@ -484,7 +486,7 @@ var ActionManager = Widget.extend({
this.trigger_up('show_effect', action.effect);
}
- return $.when(result);
+ return Promise.resolve(result);
},
/**
* Executes actions of type 'ir.actions.server'.
@@ -494,7 +496,7 @@ var ActionManager = Widget.extend({
* @param {integer} action.id the db ID of the action to execute
* @param {Object} [action.context]
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the action has been executed
+ * @returns {Promise} resolved when the action has been executed
*/
_executeServerAction: function (action, options) {
var self = this;
@@ -520,7 +522,7 @@ var ActionManager = Widget.extend({
* @param {string} [action.target] set to 'self' to redirect in the current page,
* redirects to a new page by default
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the redirection is done (immediately
+ * @returns {Promise} resolved when the redirection is done (immediately
* when redirecting to a new page)
*/
_executeURLAction: function (action, options) {
@@ -531,7 +533,7 @@ var ActionManager = Widget.extend({
if (action.target === 'self') {
framework.redirect(url);
- return $.Deferred();
+ return Promise.resolve();
} else {
var w = window.open(url, '_blank');
if (!w || w.closed || typeof w.closed === 'undefined') {
@@ -544,7 +546,7 @@ var ActionManager = Widget.extend({
options.on_close();
- return $.when();
+ return Promise.resolve();
},
/**
* Returns a description of the controllers in the given controller stack.
@@ -653,14 +655,14 @@ var ActionManager = Widget.extend({
* @param {Object} action
* @param {string} action.type
* @param {Object} options
- * @returns {Deferred} resolved when the action has been executed ; rejected
+ * @returns {Promise} resolved when the action has been executed ; rejected
* if the type of action isn't supported, or if the action can't be
* executed
*/
_handleAction: function (action, options) {
if (!action.type) {
console.error("No type for action", action);
- return $.Deferred().reject();
+ return Promise.reject();
}
switch (action.type) {
case 'ir.actions.act_url':
@@ -674,7 +676,7 @@ var ActionManager = Widget.extend({
default:
console.error("The ActionManager can't handle actions of type " +
action.type, action);
- return $.Deferred().reject();
+ return Promise.reject();
}
},
/**
@@ -749,16 +751,17 @@ var ActionManager = Widget.extend({
* @private
* @param {integer|string} action's ID or xml ID
* @param {Object} context
- * @returns {Deferred<Object>} resolved with the description of the action
+ * @returns {Promise<Object>} resolved with the description of the action
*/
_loadAction: function (actionID, context) {
- var def = $.Deferred();
- this.trigger_up('load_action', {
- actionID: actionID,
- context: context,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('load_action', {
+ actionID: actionID,
+ context: context,
+ on_success: resolve,
+ });
});
- return def;
},
/**
* Preprocesses the action before it is handled by the ActionManager
@@ -815,20 +818,20 @@ var ActionManager = Widget.extend({
*
* @private
* @param {string} controllerID
- * @returns {Deferred} resolved when the controller has been restored
+ * @returns {Promise} resolved when the controller has been restored
*/
_restoreController: function (controllerID) {
var self = this;
var controller = this.controllers[controllerID];
// AAB: AbstractAction should define a proper hook to execute code when
- // it is restored (other than do_show), and it should return a deferred
+ // it is restored (other than do_show), and it should return a promise
var action = this.actions[controller.actionID];
var def;
if (action.on_reverse_breadcrumb) {
def = action.on_reverse_breadcrumb();
}
- return $.when(def).then(function () {
- return $.when(controller.widget.do_show()).then(function () {
+ return Promise.resolve(def).then(function () {
+ return Promise.resolve(controller.widget.do_show()).then(function () {
var index = _.indexOf(self.controllerStack, controllerID);
self._pushController(controller, index);
});
@@ -844,7 +847,7 @@ var ActionManager = Widget.extend({
*
* @private
* @param {Object} controller
- * @returns {Deferred<Object>} resolved with the controller when it is ready
+ * @returns {Promise<Object>} resolved with the controller when it is ready
*/
_startController: function (controller) {
var fragment = document.createDocumentFragment();
diff --git a/addons/web/static/src/js/chrome/action_manager_act_window.js b/addons/web/static/src/js/chrome/action_manager_act_window.js
index 106f9f2aa47..d00b3a49eb2 100644
--- a/addons/web/static/src/js/chrome/action_manager_act_window.js
+++ b/addons/web/static/src/js/chrome/action_manager_act_window.js
@@ -144,7 +144,7 @@ ActionManager.include({
* @param {integer} [options.index=0] the controller's index in the stack
* @param {boolean} [options.lazy=false] set to true to differ the
* initialization of the controller's widget
- * @returns {Deferred<Object>} resolved with the created controller
+ * @returns {Promise<Object>} resolved with the created controller
*/
_createViewController: function (action, viewType, viewOptions, options) {
var self = this;
@@ -153,7 +153,7 @@ ActionManager.include({
// the requested view type isn't specified in the action (e.g.
// action with list view only, user clicks on a row in the list, it
// tries to switch to form view)
- return $.Deferred().reject();
+ return Promise.reject();
}
options = options || {};
@@ -186,26 +186,31 @@ ActionManager.include({
// communication with trigger_up
controllerID: controllerID,
});
+ var rejection;
var view = new viewDescr.Widget(viewDescr.fieldsView, viewOptions);
- var def = $.Deferred();
- action.controllers[viewType] = def;
- view.getController(this).then(function (widget) {
- if (def.state() === 'rejected') {
- // the deferred has been rejected meanwhile, meaning that
- // the action has been removed, so simply destroy the widget
- widget.destroy();
- } else {
- controller.widget = widget;
- def.resolve(controller);
- }
- }).fail(def.reject.bind(def));
- def.fail(function () {
+ var def = new Promise(function (resolve, reject) {
+ rejection = reject;
+ view.getController(self).then(function (widget) {
+ if (def.rejected) {
+ // the promise has been rejected meanwhile, meaning that
+ // the action has been removed, so simply destroy the widget
+ widget.destroy();
+ } else {
+ controller.widget = widget;
+ resolve(controller);
+ }
+ }).guardedCatch(reject);
+ });
+ // Need to define an reject property to call it into _destroyWindowAction
+ def.reject = rejection;
+ def.guardedCatch(function () {
+ def.rejected = true;
delete self.controllers[controllerID];
});
+ action.controllers[viewType] = def;
} else {
- action.controllers[viewType] = $.Deferred().resolve(controller);
+ action.controllers[viewType] = Promise.resolve(controller);
}
-
return action.controllers[viewType];
},
/**
@@ -217,18 +222,22 @@ ActionManager.include({
*/
_destroyWindowAction: function (action) {
var self = this;
- _.each(action.controllers, function (controllerDef) {
+ for (var c in action.controllers) {
+ var controllerDef = action.controllers[c];
controllerDef.then(function (controller) {
delete self.controllers[controller.jsID];
if (controller.widget) {
controller.widget.destroy();
}
});
- // reject the deferred if it is not yet resolved, so that the
- // controller is correctly destroyed as soon as it is ready, and
- // its reference is removed
- controllerDef.reject();
- });
+ // If controllerDef is not resolved yet, reject it so that the
+ // controller will be correctly destroyed as soon as it'll be ready,
+ // and its reference will be removed. Lazy-loaded controllers do
+ // not have a reject function on their promise
+ if (controllerDef.reject) {
+ controllerDef.reject();
+ }
+ }
},
/**
* Executes actions of type 'ir.actions.act_window'.
@@ -239,13 +248,13 @@ ActionManager.include({
* @param {Object} options @see doAction for details
* @param {integer} [options.resID] the current res ID
* @param {string} [options.viewType] the view to open
- * @returns {Deferred} resolved when the action is appended to the DOM
+ * @returns {Promise} resolved when the action is appended to the DOM
*/
_executeWindowAction: function (action, options) {
var self = this;
return this.dp.add(this._loadViews(action)).then(function (fieldsViews) {
var views = self._generateActionViews(action, fieldsViews);
- action._views = action.views; // save the initial attribute
+ action._views = action.views; // save the initial attribute
action.views = views;
action.controlPanelFieldsView = fieldsViews.search;
action.controllers = {};
@@ -285,7 +294,7 @@ ActionManager.include({
self.controllerStack.push(lazyLoadedController.jsID);
});
}
- return self.dp.add($.when(lazyViewDef))
+ return self.dp.add(Promise.resolve(lazyViewDef))
.then(function () {
var viewOptions = {
controllerState: options.controllerState,
@@ -300,7 +309,7 @@ ActionManager.include({
action.controllerID = controller.jsID;
return self._executeAction(action, options);
})
- .fail(self._destroyWindowAction.bind(self, action));
+ .guardedCatch(self._destroyWindowAction.bind(self, action));
});
},
/**
@@ -389,7 +398,7 @@ ActionManager.include({
*
* @private
* @param {Object} action
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadViews: function (action) {
var inDialog = action.target === 'new';
@@ -443,11 +452,11 @@ ActionManager.include({
return this.clearUncommittedChanges().then(function () {
// AAB: this will be done directly in AbstractAction's restore
// function
- var def;
+ var def = Promise.resolve();
if (action.on_reverse_breadcrumb) {
def = action.on_reverse_breadcrumb();
}
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
return self._switchController(action, controller.viewType);
});
});
@@ -461,14 +470,14 @@ ActionManager.include({
* @private
* @param {Object} controller the controller to switch to
* @param {Object} [viewOptions]
- * @return {Deferred} resolved when the new controller is in the DOM
+ * @return {Promise} resolved when the new controller is in the DOM
*/
_switchController: function (action, viewType, viewOptions) {
var self = this;
var view = _.findWhere(action.views, {type: viewType});
if (!view) {
// can't switch to an unknown view
- return $.Deferred().reject();
+ return Promise.reject();
}
var currentController = this.getCurrentController();
var index;
@@ -519,28 +528,30 @@ ActionManager.include({
};
var controllerDef = action.controllers[viewType];
- if (!controllerDef || controllerDef.state() === 'rejected') {
- // if the controllerDef is rejected, it probably means that the js
- // code or the requests made to the server crashed. In that case,
- // if we reuse the same deferred, then the switch to the view is
- // definitely blocked. We want to use a new controller, even though
- // it is very likely that it will recrash again. At least, it will
- // give more feedback to the user, and it could happen that one
- // record crashes, but not another.
- controllerDef = newController();
- } else {
+ if (controllerDef) {
controllerDef = controllerDef.then(function (controller) {
if (!controller.widget) {
// lazy loaded -> load it now (with same jsID)
return newController(controller.jsID);
} else {
- return $.when(controller.widget.willRestore()).then(function () {
+ return Promise.resolve(controller.widget.willRestore()).then(function () {
return controller.widget.reload(viewOptions).then(function () {
return controller;
});
});
}
+ }, function () {
+ // if the controllerDef is rejected, it probably means that the js
+ // code or the requests made to the server crashed. In that case,
+ // if we reuse the same promise, then the switch to the view is
+ // definitely blocked. We want to use a new controller, even though
+ // it is very likely that it will recrash again. At least, it will
+ // give more feedback to the user, and it could happen that one
+ // record crashes, but not another.
+ return newController();
});
+ } else {
+ controllerDef = newController();
}
return this.dp.add(controllerDef).then(function (controller) {
@@ -577,11 +588,11 @@ ActionManager.include({
var env = ev.data.env;
var context = new Context(env.context, actionData.context || {});
var recordID = env.currentID || null; // pyUtils handles null value, not undefined
- var def = $.Deferred();
+ var def;
// determine the action to execute according to the actionData
if (actionData.special) {
- def = $.when({type: 'ir.actions.act_window_close', infos: 'special'});
+ def = Promise.resolve({type: 'ir.actions.act_window_close', infos: 'special'});
} else if (actionData.type === 'object') {
// call a Python Object method, which may return an action to execute
var args = recordID ? [[recordID]] : [env.resIDs];
@@ -611,13 +622,15 @@ ActionManager.include({
active_ids: env.resIDs,
active_id: recordID,
}));
+ } else {
+ def = new Promise(function () {});
}
// use the DropPrevious to prevent from executing the handler if another
// request (doAction, switchView...) has been done meanwhile ; execute
// the fail handler if the 'call_button' or 'loadAction' failed but not
// if the request failed due to the DropPrevious,
- def.fail(ev.data.on_fail);
+ def.guardedCatch(ev.data.on_fail);
this.dp.add(def).then(function (action) {
// show effect if button have effect attribute
// rainbowman can be displayed from two places: from attribute on a button or from python
diff --git a/addons/web/static/src/js/chrome/action_manager_report.js b/addons/web/static/src/js/chrome/action_manager_report.js
index 51922cd719f..30bac14006d 100644
--- a/addons/web/static/src/js/chrome/action_manager_report.js
+++ b/addons/web/static/src/js/chrome/action_manager_report.js
@@ -40,35 +40,36 @@ ActionManager.include({
* report generation and download.
*
* @param {string} url
- * @returns {Deferred} resolved when the report has been downloaded ;
+ * @returns {Promise} resolved when the report has been downloaded ;
* rejected if something went wrong during the report generation
*/
_downloadReport: function (url) {
+ var self = this;
framework.blockUI();
- var def = $.Deferred();
- var type = 'qweb-' + url.split('/')[2];
- var blocked = !session.get_file({
- url: '/report/download',
- data: {
- data: JSON.stringify([url, type]),
- },
- success: def.resolve.bind(def),
- error: function () {
- crash_manager.rpc_error.apply(crash_manager, arguments);
- def.reject();
- },
- complete: framework.unblockUI,
+ return new Promise(function (resolve, reject) {
+ var type = 'qweb-' + url.split('/')[2];
+ var blocked = !session.get_file({
+ url: '/report/download',
+ data: {
+ data: JSON.stringify([url, type]),
+ },
+ success: resolve,
+ error: function () {
+ crash_manager.rpc_error.apply(crash_manager, arguments);
+ reject();
+ },
+ complete: framework.unblockUI,
+ });
+ if (blocked) {
+ // AAB: this check should be done in get_file service directly,
+ // should not be the concern of the caller (and that way, get_file
+ // could return a promise)
+ var message = _t('A popup window with your report was blocked. You ' +
+ 'may need to change your browser settings to allow ' +
+ 'popup windows for this page.');
+ self.do_warn(_t('Warning'), message, true);
+ }
});
- if (blocked) {
- // AAB: this check should be done in get_file service directly,
- // should not be the concern of the caller (and that way, get_file
- // could return a deferred)
- var message = _t('A popup window with your report was blocked. You ' +
- 'may need to change your browser settings to allow ' +
- 'popup windows for this page.');
- this.do_warn(_t('Warning'), message, true);
- }
- return def;
},
/**
@@ -77,7 +78,7 @@ ActionManager.include({
* @private
* @param {Object} action the description of the action to execute
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the action has been executed
+ * @returns {Promise} resolved when the action has been executed
*/
_triggerDownload: function (action, options, type){
var self = this;
@@ -97,7 +98,7 @@ ActionManager.include({
* @private
* @param {Object} action the description of the action to execute
* @param {Object} options @see doAction for details
- * @returns {Deferred} resolved when the action has been executed
+ * @returns {Promise} resolved when the action has been executed
*/
_executeReportAction: function (action, options) {
var self = this;
@@ -125,7 +126,7 @@ ActionManager.include({
} else {
console.error("The ActionManager can't handle reports of type " +
action.report_type, action);
- return $.Deferred().reject();
+ return Promise.reject();
}
},
/**
@@ -135,7 +136,7 @@ ActionManager.include({
*
* @param {Object} action
* @param {Object} options
- * @returns {Deferred} resolved when the client action has been executed
+ * @returns {Promise} resolved when the client action has been executed
*/
_executeReportClientAction: function (action, options) {
var urls = this._makeReportUrls(action);
diff --git a/addons/web/static/src/js/chrome/action_mixin.js b/addons/web/static/src/js/chrome/action_mixin.js
index 92d6716a7c0..02345e7e969 100644
--- a/addons/web/static/src/js/chrome/action_mixin.js
+++ b/addons/web/static/src/js/chrome/action_mixin.js
@@ -75,7 +75,7 @@ var ActionMixin = {
* Called by the action manager when action is restored (typically, when the
* user clicks on the action in the breadcrumb)
*
- * @returns {Deferred|undefined}
+ * @returns {Promise|undefined}
*/
willRestore: function () {},
@@ -89,14 +89,14 @@ var ActionMixin = {
* example, if the user has edited a form, maybe we should ask him if we
* can discard all his changes when we switch to another action. In that
* case, the action manager will call this method. If the returned
- * deferred is succesfully resolved, then we can destroy the current action,
+ * promise is succesfully resolved, then we can destroy the current action,
* otherwise, we need to stop.
*
- * @returns {Deferred} resolved if the action can be removed, rejected
+ * @returns {Promise} resolved if the action can be removed, rejected
* otherwise
*/
canBeRemoved: function () {
- return $.when();
+ return Promise.resolve();
},
/**
* This function is called when the current state of the action
diff --git a/addons/web/static/src/js/chrome/loading.js b/addons/web/static/src/js/chrome/loading.js
index 6c7f102231b..865aa081bf0 100644
--- a/addons/web/static/src/js/chrome/loading.js
+++ b/addons/web/static/src/js/chrome/loading.js
@@ -26,6 +26,8 @@ var Loading = Widget.extend({
this._super(parent);
this.count = 0;
this.blocked_ui = false;
+ },
+ start: function() {
core.bus.on('rpc_request', this, this.request_call);
core.bus.on("rpc_response", this, this.response_call);
core.bus.on("rpc_response_failed", this, this.response_call);
diff --git a/addons/web/static/src/js/chrome/menu.js b/addons/web/static/src/js/chrome/menu.js
index 8722724c9a6..552dfce811c 100644
--- a/addons/web/static/src/js/chrome/menu.js
+++ b/addons/web/static/src/js/chrome/menu.js
@@ -64,20 +64,22 @@ var Menu = Widget.extend({
// Apps Menu
this._appsMenu = new AppsMenu(self, this.menu_data);
- this._appsMenu.appendTo(this.$menu_apps);
+ var appsMenuProm = this._appsMenu.appendTo(this.$menu_apps);
// Systray Menu
this.systray_menu = new SystrayMenu(this);
- this.systray_menu.attachTo(this.$('.o_menu_systray'));
-
- dom.initAutoMoreMenu(this.$section_placeholder, {
+ var systrayMenuProm = this.systray_menu.attachTo(this.$('.o_menu_systray')).then(function() {
+ dom.initAutoMoreMenu(self.$section_placeholder, {
maxWidth: function () {
return self.$el.width() - (self.$menu_apps.outerWidth(true) + self.$menu_brand_placeholder.outerWidth(true) + self.systray_menu.$el.outerWidth(true));
},
sizeClass: 'SM',
+ });
});
- return this._super.apply(this, arguments);
+
+
+ return Promise.all([this._super.apply(this, arguments), appsMenuProm, systrayMenuProm]);
},
change_menu_section: function (primary_menu_id) {
if (!this.$menu_sections[primary_menu_id]) {
diff --git a/addons/web/static/src/js/chrome/pager.js b/addons/web/static/src/js/chrome/pager.js
index c7f22a6f2c9..86700d93374 100644
--- a/addons/web/static/src/js/chrome/pager.js
+++ b/addons/web/static/src/js/chrome/pager.js
@@ -28,7 +28,7 @@ var Pager = Widget.extend({
* @param {boolean} [options.can_edit] editable feature of the pager
* @param {boolean} [options.single_page_hidden] (not) to display the pager
* if only one page
- * @param {function} [options.validate] callback returning a Deferred to
+ * @param {function} [options.validate] callback returning a Promise to
* validate changes
*/
init: function (parent, size, current_min, limit, options) {
@@ -46,7 +46,7 @@ var Pager = Widget.extend({
can_edit: true, // editable
single_page_hidden: false, // displayed even if there is a single page
validate: function() {
- return $.Deferred().resolve();
+ return Promise.resolve();
},
withAccessKey: true, // can be disabled, for example, for x2m widgets
});
@@ -55,7 +55,7 @@ var Pager = Widget.extend({
/**
* Renders the pager
*
- * @returns {jQuery.Deferred}
+ * @returns {Promise}
*/
start: function () {
this.$value = this.$('.o_pager_value');
@@ -216,7 +216,6 @@ var Pager = Widget.extend({
}
self.trigger('pager_changed', _.clone(self.state));
}
- }).always(function() {
// Render the pager's new state (removes the input)
self._render();
});
diff --git a/addons/web/static/src/js/chrome/sidebar.js b/addons/web/static/src/js/chrome/sidebar.js
index 5cf6005a788..b7883cbb0f7 100644
--- a/addons/web/static/src/js/chrome/sidebar.js
+++ b/addons/web/static/src/js/chrome/sidebar.js
@@ -153,7 +153,7 @@ var Sidebar = Widget.extend({
action_id: item.action.id,
context: context,
},
- }).done(function (result) {
+ }).then(function (result) {
result.context = new Context(
result.context || {}, activeIdsContext)
.set_eval_context(context);
diff --git a/addons/web/static/src/js/chrome/systray_menu.js b/addons/web/static/src/js/chrome/systray_menu.js
index 24fd02a3736..fd214c0b650 100644
--- a/addons/web/static/src/js/chrome/systray_menu.js
+++ b/addons/web/static/src/js/chrome/systray_menu.js
@@ -16,20 +16,19 @@ var SystrayMenu = Widget.extend({
this._super(parent);
this.items = [];
this.widgets = [];
- this.load = $.Deferred();
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
var self = this;
self._super.apply(this, arguments);
self._loadItems();
- $.when.apply($, self.items).always(function () {
- self.load.resolve();
+
+ return new Promise(function (resolve, reject) {
+ Promise.all(self.items).then(resolve).guardedCatch(resolve);
});
- return self.load;
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/chrome/user_menu.js b/addons/web/static/src/js/chrome/user_menu.js
index a066b661fb2..2cc39b4d6bd 100644
--- a/addons/web/static/src/js/chrome/user_menu.js
+++ b/addons/web/static/src/js/chrome/user_menu.js
@@ -22,7 +22,7 @@ var UserMenu = Widget.extend({
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
var self = this;
@@ -36,7 +36,7 @@ var UserMenu = Widget.extend({
var $avatar = self.$('.oe_topbar_avatar');
if (!session.uid) {
$avatar.attr('src', $avatar.data('default-src'));
- return $.when();
+ return Promise.resolve();
}
var topbar_name = session.name;
if (session.debug) {
@@ -67,7 +67,7 @@ var UserMenu = Widget.extend({
.then(function (url) {
framework.redirect(url);
})
- .fail(function (result, ev){
+ .guardedCatch(function (result, ev){
ev.preventDefault();
framework.redirect('https://accounts.odoo.com/account');
});
@@ -100,7 +100,7 @@ var UserMenu = Widget.extend({
model: "res.users",
method: "action_get"
})
- .done(function (result) {
+ .then(function (result) {
result.res_id = session.uid;
self.do_action(result);
});
diff --git a/addons/web/static/src/js/chrome/web_client.js b/addons/web/static/src/js/chrome/web_client.js
index 0688adc362f..392d534f372 100644
--- a/addons/web/static/src/js/chrome/web_client.js
+++ b/addons/web/static/src/js/chrome/web_client.js
@@ -111,7 +111,7 @@ return AbstractWebClient.extend({
instanciate_menu_widgets: function () {
var self = this;
- var defs = [];
+ var proms = [];
return this.load_menus().then(function (menuData) {
self.menu_data = menuData;
@@ -122,8 +122,8 @@ return AbstractWebClient.extend({
self.menu.destroy();
}
self.menu = new Menu(self, menuData);
- defs.push(self.menu.prependTo(self.$el));
- return $.when.apply($, defs);
+ proms.push(self.menu.prependTo(self.$el));
+ return Promise.all(proms);
});
},
@@ -133,7 +133,7 @@ return AbstractWebClient.extend({
on_hashchange: function (event) {
if (this._ignore_hashchange) {
this._ignore_hashchange = false;
- return $.when();
+ return Promise.resolve();
}
var self = this;
@@ -181,48 +181,51 @@ return AbstractWebClient.extend({
return this.menu_dm.add(data_manager.load_action(ev.data.action_id))
.then(function (result) {
return self.action_mutex.exec(function () {
- var completed = $.Deferred();
- var options = _.extend({}, ev.data.options, {
- clear_breadcrumbs: true,
- action_menu_id: ev.data.menu_id,
- });
- $.when(self._openMenu(result, options)).fail(function () {
- completed.resolve();
- }).done(function () {
- self._on_app_clicked_done(ev)
- .then(completed.resolve.bind(completed))
- .fail(completed.reject.bind(completed));
+ var completed = new Promise(function (resolve, reject) {
+ var options = _.extend({}, ev.data.options, {
+ clear_breadcrumbs: true,
+ action_menu_id: ev.data.menu_id,
+ });
+
+ Promise.resolve(self._openMenu(result, options))
+ .then(function() {
+ self._on_app_clicked_done(ev)
+ .then(resolve)
+ .guardedCatch(reject);
+ }).guardedCatch(function() {
+ resolve();
+ });
+ setTimeout(function () {
+ resolve();
+ }, 2000);
});
- setTimeout(function () {
- completed.resolve();
- }, 2000);
return completed;
});
});
},
_on_app_clicked_done: function (ev) {
core.bus.trigger('change_menu_section', ev.data.menu_id);
- return $.Deferred().resolve();
+ return Promise.resolve();
},
on_menu_clicked: function (ev) {
var self = this;
return this.menu_dm.add(data_manager.load_action(ev.data.action_id))
.then(function (result) {
- return self.action_mutex.exec(function () {
- var completed = $.Deferred();
- $.when(self._openMenu(result, {
- clear_breadcrumbs: true,
- })).always(function () {
- completed.resolve();
- });
+ self.$el.removeClass('o_mobile_menu_opened');
- setTimeout(function () {
- completed.resolve();
- }, 2000);
+ return self.action_mutex.exec(function () {
+ var completed = new Promise(function (resolve, reject) {
+ Promise.resolve(self._openMenu(result, {
+ clear_breadcrumbs: true,
+ })).then(resolve).guardedCatch(reject);
+ setTimeout(function () {
+ resolve();
+ }, 2000);
+ });
return completed;
});
- }).always(function () {
+ }).guardedCatch(function () {
self.$el.removeClass('o_mobile_menu_opened');
});
},
@@ -233,7 +236,7 @@ return AbstractWebClient.extend({
* @private
* @param {Object} action
* @param {Object} options
- * @returns {Deferred}
+ * @returns {Promise}
*/
_openMenu: function (action, options) {
return this.do_action(action, options);
diff --git a/addons/web/static/src/js/core/ajax.js b/addons/web/static/src/js/core/ajax.js
index 509126498bc..8e7216c7b00 100644
--- a/addons/web/static/src/js/core/ajax.js
+++ b/addons/web/static/src/js/core/ajax.js
@@ -3,22 +3,19 @@ odoo.define('web.ajax', function (require) {
var config = require('web.config');
var core = require('web.core');
-var utils = require('web.utils');
var time = require('web.time');
var download = require('web.download');
var contentdisposition = require('web.contentdisposition');
var _t = core._t;
-function genericJsonRpc (fct_name, params, settings, fct) {
+function _genericJsonRpc (fct_name, params, settings, fct) {
var shadow = settings.shadow || false;
delete settings.shadow;
if (!shadow) {
core.bus.trigger('rpc_request');
}
- var deferred = $.Deferred();
-
var data = {
jsonrpc: "2.0",
method: fct_name,
@@ -26,7 +23,7 @@ function genericJsonRpc (fct_name, params, settings, fct) {
id: Math.floor(Math.random() * 1000 * 1000 * 1000)
};
var xhr = fct(data);
- var result = xhr.pipe(function(result) {
+ var result = xhr.then(function(result) {
core.bus.trigger('rpc:result', data, result);
if (result.error !== undefined) {
if (result.error.data.arguments[0] !== "bus.Bus not available in test mode") {
@@ -36,65 +33,86 @@ function genericJsonRpc (fct_name, params, settings, fct) {
console.error("Server application error", JSON.stringify(result.error));
}
}
- return $.Deferred().reject("server", result.error);
+ return Promise.reject({type: "server", error: result.error});
} else {
return result.result;
}
}, function() {
//console.error("JsonRPC communication error", _.toArray(arguments));
- var def = $.Deferred();
- return def.reject.apply(def, ["communication"].concat(_.toArray(arguments)));
+ var reason = {
+ type: 'communication',
+ error: arguments[0],
+ textStatus: arguments[1],
+ errorThrown: arguments[2],
+ };
+ return Promise.reject(reason);
});
- deferred.abort = function () {
- deferred.reject({message: "XmlHttpRequestError abort"}, $.Event('abort'));
- if (xhr.abort) {
- xhr.abort();
- }
- };
- result.then(function (result) {
- if (!shadow) {
- core.bus.trigger('rpc_response');
- }
- deferred.resolve(result);
- }, function (type, error, textStatus, errorThrown) {
- if (type === "server") {
+ var rejection;
+ var promise = new Promise(function (resolve, reject) {
+ rejection = reject;
+
+ result.then(function (result) {
if (!shadow) {
core.bus.trigger('rpc_response');
}
- if (error.code === 100) {
- core.bus.trigger('invalidate_session');
- }
- deferred.reject(error, $.Event());
- } else {
- if (!shadow) {
- core.bus.trigger('rpc_response_failed');
+ resolve(result);
+ }, function (reason) {
+ var type = reason.type;
+ var error = reason.error;
+ var textStatus = reason.textStatus;
+ var errorThrown = reason.errorThrown;
+ if (type === "server") {
+ if (!shadow) {
+ core.bus.trigger('rpc_response');
+ }
+ if (error.code === 100) {
+ core.bus.trigger('invalidate_session');
+ }
+ reject({message: error, event: $.Event()});
+ } else {
+ if (!shadow) {
+ core.bus.trigger('rpc_response_failed');
+ }
+ var nerror = {
+ code: -32098,
+ message: "XmlHttpRequestError " + errorThrown,
+ data: {
+ type: "xhr"+textStatus,
+ debug: error.responseText,
+ objects: [error, errorThrown]
+ },
+ };
+ reject({message: nerror, event: $.Event()});
}
- var nerror = {
- code: -32098,
- message: "XmlHttpRequestError " + errorThrown,
- data: {
- type: "xhr"+textStatus,
- debug: error.responseText,
- objects: [error, errorThrown]
- },
- };
- deferred.reject(nerror, $.Event());
- }
+ });
});
- deferred.fail(function () { // Allow deferred user to disable rpc_error call in fail
- deferred.fail(function (error, event) {
- if (!event.isDefaultPrevented()) {
- core.bus.trigger('rpc_error', error, event);
- }
+
+ // FIXME: jsonp?
+ promise.abort = function () {
+ rejection({
+ message: "XmlHttpRequestError abort",
+ event: $.Event('abort')
});
+ if (xhr.abort) {
+ xhr.abort();
+ }
+ };
+ promise.guardedCatch(function (reason) { // Allow promise user to disable rpc_error call in case of failure
+ setTimeout(function () {
+ // we want to execute this handler after all others (hence
+ // setTimeout) to let the other handlers prevent the event
+ if (!reason.event.isDefaultPrevented()) {
+ core.bus.trigger('rpc_error', reason.message, reason.event);
+ }
+ }, 0);
});
- return deferred;
-}
+ return promise;
+};
function jsonRpc(url, fct_name, params, settings) {
settings = settings || {};
- return genericJsonRpc(fct_name, params, settings, function(data) {
+ return _genericJsonRpc(fct_name, params, settings, function(data) {
return $.ajax(url, _.extend({}, settings, {
url: url,
dataType: 'json',
@@ -110,19 +128,6 @@ function rpc(url, params, settings) {
return jsonRpc(url, 'call', params, settings);
}
-// helper
-function realSetTimeout (fct, millis) {
- var finished = new Date().getTime() + millis;
- var wait = function() {
- var current = new Date().getTime();
- if (current < finished) {
- setTimeout(wait, finished - current);
- } else {
- fct();
- }
- };
- setTimeout(wait, millis);
-}
/**
* Load css asynchronously: fetch it from the url parameter and add a link tag
@@ -131,26 +136,27 @@ function realSetTimeout (fct, millis) {
* immediately.
*
* @param {String} url of the css to be fetched
- * @returns {Deferred} resolved when the css has been loaded.
+ * @returns {Promise} resolved when the css has been loaded.
*/
var loadCSS = (function () {
- var urlDefs = Object.create(null);
+ var urlDefs = {};
return function loadCSS(url) {
if (url in urlDefs) {
// nothing to do here
} else if ($('link[href="' + url + '"]').length) {
- // the link is already in the DOM, the deferred can be resolved
- urlDefs[url] = $.when();
+ // the link is already in the DOM, the promise can be resolved
+ urlDefs[url] = Promise.resolve();
} else {
var $link = $('<link>', {
'href': url,
'rel': 'stylesheet',
'type': 'text/css'
});
- urlDefs[url] = $.Deferred();
- $link.on('load', function () {
- urlDefs[url].resolve();
+ urlDefs[url] = new Promise(function (resolve, reject) {
+ $link.on('load', function () {
+ resolve();
+ });
});
$('head').append($link);
}
@@ -159,44 +165,45 @@ var loadCSS = (function () {
})();
var loadJS = (function () {
- var urls = [];
- var defs = [];
+ var dependenciesPromise = {};
var load = function loadJS(url) {
// Check the DOM to see if a script with the specified url is already there
var alreadyRequired = ($('script[src="' + url + '"]').length > 0);
- // If loadJS was already called with the same URL, it will have a registered deferred indicating if
- // the script has been fully loaded. If not, the deferred has to be initialized. This is initialized
- // as already resolved if the script was already there without the need of loadJS.
- var index = _.indexOf(urls, url);
- if (index < 0) {
- urls.push(url);
- index = defs.push(alreadyRequired ? $.when() : $.Deferred()) - 1;
+ // If loadJS was already called with the same URL, it will have a registered promise indicating if
+ // the script has been fully loaded. If not, the promise has to be initialized.
+ // This is initialized as already resolved if the script was already there without the need of loadJS.
+ if (url in dependenciesPromise) {
+ return dependenciesPromise[url];
}
+ var scriptLoadedPromise = new Promise(function (resolve, reject) {
+ if (alreadyRequired) {
+ resolve();
+ } else {
+ // Get the script associated promise and returns it after initializing the script if needed. The
+ // promise is marked to be resolved on script load and rejected on script error.
+ var script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.src = url;
+ script.onload = script.onreadystatechange = function() {
+ if ((script.readyState && script.readyState !== "loaded" && script.readyState !== "complete") || script.onload_done) {
+ return;
+ }
+ script.onload_done = true;
+ resolve(url);
+ };
+ script.onerror = function () {
+ console.error("Error loading file", script.src);
+ reject(url);
+ };
+ var head = document.head || document.getElementsByTagName('head')[0];
+ head.appendChild(script);
+ }
+ });
- // Get the script associated deferred and returns it after initializing the script if needed. The
- // deferred is marked to be resolved on script load and rejected on script error.
- var def = defs[index];
- if (!alreadyRequired) {
- var script = document.createElement('script');
- script.type = 'text/javascript';
- script.src = url;
- script.onload = script.onreadystatechange = function() {
- if ((script.readyState && script.readyState !== "loaded" && script.readyState !== "complete") || script.onload_done) {
- return;
- }
- script.onload_done = true;
- def.resolve(url);
- };
- script.onerror = function () {
- console.error("Error loading file", script.src);
- def.reject(url);
- };
- var head = document.head || document.getElementsByTagName('head')[0];
- head.appendChild(script);
- }
- return def;
+ dependenciesPromise[url] = scriptLoadedPromise;
+ return scriptLoadedPromise;
};
return load;
@@ -308,22 +315,6 @@ function get_file(options) {
}
function post (controller_url, data) {
-
- var progressHandler = function (deferred) {
- return function (state) {
- if(state.lengthComputable) {
- deferred.notify({
- h_loaded: utils.human_size(state.loaded),
- h_total : utils.human_size(state.total),
- loaded : state.loaded,
- total : state.total,
- pcent : Math.round((state.loaded/state.total)*100)
- });
- }
- };
- };
-
- var Def = $.Deferred();
var postData = new FormData();
$.each(data, function(i,val) {
@@ -333,25 +324,20 @@ function post (controller_url, data) {
postData.append('csrf_token', core.csrf_token);
}
- var xhr = new XMLHttpRequest();
- if(xhr.upload) xhr.upload.addEventListener('progress', progressHandler(Def), false);
-
- var ajaxDef = $.ajax(controller_url, {
- xhr: function() {return xhr;},
- data: postData,
- processData: false,
- contentType: false,
- type: 'POST'
- }).then(function (data) {Def.resolve(data);})
- .fail(function (data) {Def.reject(data);});
-
- return Def;
+ return new Promise(function (resolve, reject) {
+ $.ajax(controller_url, {
+ data: postData,
+ processData: false,
+ contentType: false,
+ type: 'POST'
+ }).then(resolve).fail(reject);
+ });
}
/**
* Loads an XML file according to the given URL and adds its associated qweb
* templates to the given qweb engine. The function can also be used to get
- * the deferred which indicates when all the calls to the function are finished.
+ * the promise which indicates when all the calls to the function are finished.
*
* Note: "all the calls" = the calls that happened before the current no-args
* one + the calls that will happen after but when the previous ones are not
@@ -359,8 +345,8 @@ function post (controller_url, data) {
*
* @param {string} [url] - an URL where to find qweb templates
* @param {QWeb} [qweb] - the engine to which the templates need to be added
- * @returns {Deferred}
- * If no argument is given to the function, the deferred's state
+ * @returns {Promise}
+ * If no argument is given to the function, the promise's state
* indicates if "all the calls" are finished (see main description).
* Otherwise, it indicates when the templates associated to the given
* url have been loaded.
@@ -369,63 +355,64 @@ var loadXML = (function () {
// Some "static" variables associated to the loadXML function
var isLoading = false;
var loadingsData = [];
- var allLoadingsDef = $.when();
var seenURLs = [];
return function (url, qweb) {
- // If no argument, simply returns the deferred which indicates when
+ function _load() {
+ isLoading = true;
+ if (loadingsData.length) {
+ // There is something to load, load it, resolve the associated
+ // promise then start loading the next one
+ var loadingData = loadingsData[0];
+ loadingData.qweb.add_template(loadingData.url, function () {
+ // Remove from array only now so that multiple calls to
+ // loadXML with the same URL returns the right promise
+ loadingsData.shift();
+ loadingData.resolve();
+ _load();
+ });
+ } else {
+ // There is nothing to load anymore, so resolve the
+ // "all the calls" promise
+ isLoading = false;
+ }
+ }
+
+ // If no argument, simply returns the promise which indicates when
// "all the calls" are finished
if (!url || !qweb) {
- return allLoadingsDef;
+ return Promise.resolve();
}
// If the given URL has already been seen, do nothing but returning the
- // associated deferred
+ // associated promise
if (_.contains(seenURLs, url)) {
var oldLoadingData = _.findWhere(loadingsData, {url: url});
- return oldLoadingData ? oldLoadingData.def : $.when();
+ return oldLoadingData ? oldLoadingData.def : Promise.resolve();
}
seenURLs.push(url);
+
// Add the information about the new data to load: the url, the qweb
- // engine and the associated deferred
+ // engine and the associated promise
var newLoadingData = {
url: url,
qweb: qweb,
- def: $.Deferred(),
};
+ newLoadingData.def = new Promise(function (resolve, reject) {
+ newLoadingData.resolve = resolve;
+ newLoadingData.reject = reject;
+ });
loadingsData.push(newLoadingData);
// If not already started, start the loading loop (reinitialize the
- // "all the calls" deferred to an unresolved state)
+ // "all the calls" promise to an unresolved state)
if (!isLoading) {
- allLoadingsDef = $.Deferred();
_load();
}
- // Return the deferred associated to the new given URL
+ // Return the promise associated to the new given URL
return newLoadingData.def;
-
- function _load() {
- isLoading = true;
- if (loadingsData.length) {
- // There is something to load, load it, resolve the associated
- // deferred then start loading the next one
- var loadingData = loadingsData[0];
- loadingData.qweb.add_template(loadingData.url, function () {
- // Remove from array only now so that multiple calls to
- // loadXML with the same URL returns the right deferred
- loadingsData.shift();
- loadingData.def.resolve();
- _load();
- });
- } else {
- // There is nothing to load anymore, so resolve the
- // "all the calls" deferred
- isLoading = false;
- allLoadingsDef.resolve();
- }
- }
};
})();
@@ -444,7 +431,7 @@ var loadAsset = (function () {
var load = function loadAsset(xmlId) {
if (cache[xmlId]) {
- return $.when(cache[xmlId]);
+ return Promise.resolve(cache[xmlId]);
}
var params = {
args: [xmlId, {
@@ -493,22 +480,20 @@ var loadAsset = (function () {
* @param {Array<string>} [libs.assetLibs=[]] A list of xmlId. The loaded template
* contains the script and link to be loaded
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
function loadLibs (libs) {
var defs = [];
- _.each(libs.jsLibs || [], function (urls) {
- defs.push($.when.apply($, defs).then(function () {
+ (libs.jsLibs || []).forEach(function (urls) {
+ defs.push(Promise.all(defs).then(function () {
if (typeof(urls) === 'string') {
return ajax.loadJS(urls);
} else {
- return $.when.apply($, _.map(urls, function (url) {
- return ajax.loadJS(url);
- }));
+ return Promise.all(urls.map(ajax.loadJS));
}
}));
});
- _.each(libs.cssLibs || [], function (url) {
+ (libs.cssLibs || []).forEach(function (url) {
defs.push(ajax.loadCSS(url));
});
_.each(libs.assetLibs || [], function (xmlId) {
@@ -516,7 +501,7 @@ function loadLibs (libs) {
return loadLibs(asset);
}));
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
}
var ajax = {
diff --git a/addons/web/static/src/js/core/concurrency.js b/addons/web/static/src/js/core/concurrency.js
index 6eeebe7ff58..716abafa919 100644
--- a/addons/web/static/src/js/core/concurrency.js
+++ b/addons/web/static/src/js/core/concurrency.js
@@ -8,7 +8,7 @@ odoo.define('web.concurrency', function (require) {
* everything concurrency related in Odoo.
*
* The basic concurrency primitives in Odoo JS are the callback, and the
- * promises. Promises (deferred) are more composable, so we usually use them
+ * promises. Promises (promise) are more composable, so we usually use them
* whenever possible. We use the jQuery implementation.
*
* Those functions are really nothing special, but are simply the result of how
@@ -19,54 +19,15 @@ var Class = require('web.Class');
return {
/**
- * The jquery implementation for $.when has a (most of the time) useful
- * property: it is synchronous, if the deferred is resolved immediately.
- *
- * This means that when we execute $.when(def), then all registered
- * callbacks will be executed before the next line is executed. This is
- * useful quite often, but in some rare cases, we might want to force an
- * async behavior. This is the purpose of this function, which simply adds a
- * setTimeout before resolving the deferred.
- *
- * @returns {Deferred}
- */
- asyncWhen: function () {
- var async = false;
- var def = $.Deferred();
- $.when.apply($, arguments).done(function() {
- var args = arguments;
- var action = function() {
- def.resolve.apply(def, args);
- };
- if (async) {
- action();
- } else {
- setTimeout(action, 0);
- }
- }).fail(function() {
- var args = arguments;
- var action = function() {
- def.reject.apply(def, args);
- };
- if (async) {
- action();
- } else {
- setTimeout(action, 0);
- }
- });
- async = true;
- return def;
- },
- /**
- * Returns a deferred resolved after 'wait' milliseconds
+ * Returns a promise resolved after 'wait' milliseconds
*
* @param {int} [wait=0] the delay in ms
- * @return {Deferred}
+ * @return {Promise}
*/
delay: function (wait) {
- var def = $.Deferred();
- setTimeout(def.resolve, wait);
- return def;
+ return new Promise(function (resolve) {
+ setTimeout(resolve, wait);
+ });
},
/**
* The DropMisordered abstraction is useful for situations where you have
@@ -93,27 +54,27 @@ return {
this.failMisordered = failMisordered || false;
},
/**
- * Adds a deferred (usually an async request) to the sequencer
+ * Adds a promise (usually an async request) to the sequencer
*
- * @param {Deferred} deferred to ensure add
- * @returns {Deferred}
+ * @param {Promise} promise to ensure add
+ * @returns {Promise}
*/
- add: function (deferred) {
- var res = $.Deferred();
-
- var self = this, seq = this.lsn++;
- deferred.done(function () {
- if (seq > self.rsn) {
- self.rsn = seq;
- res.resolve.apply(res, arguments);
- } else if (self.failMisordered) {
- res.reject();
- }
- }).fail(function () {
- res.reject.apply(res, arguments);
+ add: function (promise) {
+ var self = this;
+ var seq = this.lsn++;
+ var res = new Promise(function (resolve, reject) {
+ promise.then(function (result) {
+ if (seq > self.rsn) {
+ self.rsn = seq;
+ resolve(result);
+ } else if (self.failMisordered) {
+ reject();
+ }
+ }).guardedCatch(function (result) {
+ reject(result);
+ });
});
-
- return res.promise();
+ return res;
},
}),
/**
@@ -152,17 +113,26 @@ return {
*/
DropPrevious: Class.extend({
/**
- * Registers a new deferred and rejects the previous one
+ * Registers a new promise and rejects the previous one
*
- * @param {Deferred} deferred the new deferred
+ * @param {Promise} promise the new promise
* @returns {Promise}
*/
- add: function (deferred) {
- if (this.current_def) { this.current_def.reject(); }
- var res = $.Deferred();
- deferred.then(res.resolve, res.reject);
- this.current_def = res;
- return res.promise();
+ add: function (promise) {
+ if (this.currentDef) {
+ this.currentDef.reject();
+ }
+ var rejection;
+ var res = new Promise(function (resolve, reject) {
+ rejection = reject;
+ promise.then(resolve).catch(function (reason) {
+ reject(reason);
+ });
+ });
+
+ this.currentDef = res;
+ this.currentDef.reject = rejection;
+ return res;
}
}),
/**
@@ -171,7 +141,7 @@ return {
* state and cause some corrupted state.
*
* Imagine that we have a function to fetch some data _load(), which returns
- * a deferred which resolves to something useful. Now, we have some code
+ * a promise which resolves to something useful. Now, we have some code
* looking like this::
*
* return this._load().then(function (result) {
@@ -200,37 +170,51 @@ return {
*/
Mutex: Class.extend({
init: function () {
- this.def = $.Deferred().resolve();
- this.unlockedDef = undefined;
+ this.lock = Promise.resolve();
+ this.queueSize = 0;
+ this.unlockedProm = undefined;
+ this._unlock = undefined;
},
/**
* Add a computation to the queue, it will be executed as soon as the
* previous computations are completed.
*
- * @param {function} action a function which may return a deferred
- * @returns {Deferred}
+ * @param {function} action a function which may return a Promise
+ * @returns {Promise}
*/
exec: function (action) {
var self = this;
- var current = this.def;
- var next = this.def = $.Deferred();
- this.unlockedDef = this.unlockedDef || $.Deferred();
- return current.then(function() {
- return $.when(action()).always(function () {
- next.resolve();
- if (self.def.state() === 'resolved' && self.unlockedDef) {
- self.unlockedDef.resolve();
- self.unlockedDef = undefined;
- }
+ var currentLock = this.lock;
+ var result;
+ this.queueSize++;
+ this.unlockedProm = this.unlockedProm || new Promise(function (resolve) {
+ self._unlock = resolve;
+ });
+ this.lock = new Promise(function (unlockCurrent) {
+ currentLock.then(function () {
+ result = action();
+ var always = function (returnedResult) {
+ unlockCurrent();
+ self.queueSize--;
+ if (self.queueSize === 0) {
+ self.unlockedProm = undefined;
+ self._unlock();
+ }
+ return returnedResult;
+ };
+ Promise.resolve(result).then(always).guardedCatch(always);
});
});
+ return this.lock.then(function () {
+ return result;
+ });
},
/**
* @returns {Promise} resolved as soon as the Mutex is unlocked
* (directly if it is currently idle)
*/
getUnlockedDef: function () {
- return $.when(this.unlockedDef);
+ return this.unlockedProm || Promise.resolve();
},
}),
/**
@@ -253,65 +237,86 @@ return {
*
* A MutexedDropPrevious has to be a class, and not a function, because we
* have to keep track of some internal state. The exec function takes as
- * argument an action (and not a deferred as DropPrevious for example)
+ * argument an action (and not a promise as DropPrevious for example)
* because it's the MutexedDropPrevious role to trigger the RPC call that
- * returns a deferred when it's time.
+ * returns a promise when it's time.
*/
MutexedDropPrevious: Class.extend({
init: function () {
- this.currentDef = null;
this.locked = false;
+ this.currentProm = null;
this.pendingAction = null;
- this.pendingDef = null;
+ this.pendingProm = null;
},
/**
- * @param {function} action a function which may return a deferred
- * @returns {Deferred}
+ * @param {function} action a function which may return a promise
+ * @returns {Promise}
*/
exec: function (action) {
var self = this;
+ var resolution;
+ var rejection;
if (this.locked) {
this.pendingAction = action;
- var oldPendingDef = this.pendingDef;
- var pendingDef = this.pendingDef = $.Deferred();
- if (oldPendingDef) {
- oldPendingDef.reject();
- }
- this.currentDef.reject();
- return pendingDef.promise();
+ var oldPendingDef = this.pendingProm;
+
+ this.pendingProm = new Promise(function (resolve, reject) {
+ resolution = resolve;
+ rejection = reject;
+ if (oldPendingDef) {
+ oldPendingDef.reject();
+ }
+ self.currentProm.reject();
+ });
+ this.pendingProm.resolve = resolution;
+ this.pendingProm.reject = rejection;
+ return this.pendingProm;
} else {
this.locked = true;
- this.currentDef = $.Deferred();
- $.when(action())
- .then(this.currentDef.resolve.bind(this.currentDef))
- .fail(this.currentDef.reject.bind(this.currentDef))
- .always(function () {
+ this.currentProm = new Promise(function (resolve, reject) {
+ resolution = resolve;
+ rejection = reject;
+ function unlock() {
self.locked = false;
if (self.pendingAction) {
var action = self.pendingAction;
+ var prom = self.pendingProm;
self.pendingAction = null;
+ self.pendingProm = null;
self.exec(action)
- .then(self.pendingDef.resolve.bind(self.pendingDef))
- .fail(self.pendingDef.reject.bind(self.pendingDef));
+ .then(prom.resolve)
+ .guardedCatch(prom.reject);
}
+ }
+ Promise.resolve(action())
+ .then(function (result) {
+ resolve(result);
+ unlock();
+ })
+ .guardedCatch(function (reason) {
+ reject(reason);
+ unlock();
+ });
});
- return this.currentDef.promise();
+ this.currentProm.resolve = resolution;
+ this.currentProm.reject = rejection;
+ return this.currentProm;
}
- },
+ }
}),
/**
- * Rejects a deferred as soon as a reference deferred is either resolved or
+ * Rejects a promise as soon as a reference promise is either resolved or
* rejected
*
- * @param {Deferred} [target_def] the deferred to potentially reject
- * @param {Deferred} [reference_def] the reference target
- * @returns {Deferred}
+ * @param {Promise} [target_def] the promise to potentially reject
+ * @param {Promise} [reference_def] the reference target
+ * @returns {Promise}
*/
rejectAfter: function (target_def, reference_def) {
- var res = $.Deferred();
- target_def.then(res.resolve, res.reject);
- reference_def.always(res.reject);
- return res.promise();
+ return new Promise(function (resolve, reject) {
+ target_def.then(resolve).guardedCatch(reject);
+ reference_def.then(reject).guardedCatch(reject);
+ });
}
};
diff --git a/addons/web/static/src/js/core/dialog.js b/addons/web/static/src/js/core/dialog.js
index 83eded92c8a..8630b6b9364 100644
--- a/addons/web/static/src/js/core/dialog.js
+++ b/addons/web/static/src/js/core/dialog.js
@@ -52,9 +52,11 @@ var Dialog = Widget.extend({
* (use this for non-editor frontend features)
*/
init: function (parent, options) {
+ var self = this;
this._super(parent);
- this._opened = $.Deferred();
-
+ this._opened = new Promise(function (resolve) {
+ self._openedResolver = resolve;
+ });
options = _.defaults(options || {}, {
title: _t('Odoo'), subtitle: '',
size: 'large',
@@ -140,7 +142,7 @@ var Dialog = Widget.extend({
def = buttonData.click.call(self, e);
}
if (buttonData.close) {
- $.when(def).always(self.close.bind(self));
+ Promise.resolve(def).then(self.close.bind(self)).guardedCatch(self.close.bind(self));
}
});
if (self.technical) {
@@ -185,7 +187,7 @@ var Dialog = Widget.extend({
self.$modal.attr('open', true);
self.$modal.removeAttr("aria-hidden");
self.$modal.modal('show');
- self._opened.resolve();
+ self._openedResolver();
if (options && options.shouldFocusButtons) {
self._onFocusControlButton();
}
diff --git a/addons/web/static/src/js/core/dom.js b/addons/web/static/src/js/core/dom.js
index b8a5b8be3a4..3faa5977c8c 100644
--- a/addons/web/static/src/js/core/dom.js
+++ b/addons/web/static/src/js/core/dom.js
@@ -1,11 +1,10 @@
odoo.define('web.dom_ready', function (require) {
'use strict';
-var def = $.Deferred();
-$(def.resolve.bind(def));
-return def;
+ return new Promise(function (resolve, reject) {
+ $(resolve);
+ });
});
-
//==============================================================================
odoo.define('web.dom', function (require) {
@@ -33,7 +32,7 @@ var _t = core._t;
* that on_attach_callback() will be called on each w with arguments args
*/
function _notify(content, callbacks) {
- _.each(callbacks, function (c) {
+ callbacks.forEach(function (c) {
if (c.widget && c.widget.on_attach_callback) {
c.widget.on_attach_callback(c.callback_args);
}
@@ -170,14 +169,14 @@ var dom = {
* @return {jQuery} the detached elements
*/
detach: function (to_detach, options) {
- _.each(to_detach, function (d) {
+ to_detach.forEach( function (d) {
if (d.widget.on_detach_callback) {
d.widget.on_detach_callback(d.callback_args);
}
});
var $to_detach = options && options.$to_detach;
if (!$to_detach) {
- $to_detach = $(_.map(to_detach, function (d) {
+ $to_detach = $(to_detach.map(function (d) {
return d.widget.el;
}));
}
@@ -229,7 +228,7 @@ var dom = {
* @param {function|boolean} stopPropagation
*/
makeAsyncHandler: function (fct, preventDefault, stopPropagation) {
- // Create a deferred indicating if a previous call to this handler is
+ // Create a promise indicating if a previous call to this handler is
// still pending.
var def = $.when();
@@ -284,11 +283,13 @@ var dom = {
// a 'real' debounce creation useless. Also, during the debouncing
// part, the button is disabled without any visual effect.
$button.addClass('o_debounce_disabled');
- $.when(dom.DEBOUNCE && concurrency.delay(dom.DEBOUNCE)).then(function () {
+ Promise.resolve(dom.DEBOUNCE && concurrency.delay(dom.DEBOUNCE)).then(function () {
$button.addClass('disabled').prop('disabled', true);
$button.removeClass('o_debounce_disabled');
- return $.when(result).always(function () {
+ return Promise.resolve(result).then(function () {
+ $button.removeClass('disabled').prop('disabled', false);
+ }).guardedCatch(function () {
$button.removeClass('disabled').prop('disabled', false);
});
});
diff --git a/addons/web/static/src/js/core/misc.js b/addons/web/static/src/js/core/misc.js
index cd9a73ef22b..39fd8021071 100644
--- a/addons/web/static/src/js/core/misc.js
+++ b/addons/web/static/src/js/core/misc.js
@@ -114,7 +114,7 @@ function redirect (url, wait) {
};
var wait_server = function() {
- ajax.rpc("/web/webclient/version_info", {}).done(load).fail(function() {
+ ajax.rpc("/web/webclient/version_info", {}).then(load).guardedCatch(function () {
setTimeout(wait_server, 250);
});
};
@@ -172,7 +172,7 @@ core.action_registry.add("login", login);
function logout() {
redirect('/web/session/logout');
- return $.Deferred();
+ return new Promise();
}
core.action_registry.add("logout", logout);
diff --git a/addons/web/static/src/js/core/mixins.js b/addons/web/static/src/js/core/mixins.js
index e29c97ea086..228ac2d68dd 100644
--- a/addons/web/static/src/js/core/mixins.js
+++ b/addons/web/static/src/js/core/mixins.js
@@ -62,37 +62,36 @@ var ParentedMixin = {
* Utility method to only execute asynchronous actions if the current
* object has not been destroyed.
*
- * @param {$.Deferred} promise The promise representing the asynchronous
+ * @param {Promise} promise The promise representing the asynchronous
* action.
- * @param {bool} [reject=false] If true, the returned promise will be
+ * @param {bool} [shouldReject=false] If true, the returned promise will be
* rejected with no arguments if the current
* object is destroyed. If false, the
* returned promise will never be resolved
* or rejected.
- * @returns {$.Deferred} A promise that will mirror the given promise if
+ * @returns {Promise} A promise that will mirror the given promise if
* everything goes fine but will either be rejected
* with no arguments or never resolved if the
* current object is destroyed.
*/
- alive: function (promise, reject) {
+ alive: function (promise, shouldReject) {
var self = this;
- return $.Deferred(function (def) {
- promise.then(function () {
+
+ return new Promise(function (resolve, reject) {
+ promise.then(function (result) {
if (!self.isDestroyed()) {
- def.resolve.apply(def, arguments);
+ resolve(result);
+ } else if (shouldReject) {
+ reject();
}
- }, function () {
+ }).guardedCatch(function (reason) {
if (!self.isDestroyed()) {
- def.reject.apply(def, arguments);
- }
- }).always(function () {
- if (reject) {
- // noop if def already resolved or rejected
- def.reject();
+ reject(reason);
+ } else if (shouldReject) {
+ reject();
}
- // otherwise leave promise in limbo
});
- }).promise();
+ });
},
/**
* Inform the object it should destroy itself, releasing any
diff --git a/addons/web/static/src/js/core/mvc.js b/addons/web/static/src/js/core/mvc.js
index cdef88c4211..6e0e4267caa 100644
--- a/addons/web/static/src/js/core/mvc.js
+++ b/addons/web/static/src/js/core/mvc.js
@@ -76,7 +76,7 @@ var Model = Class.extend(mixins.EventDispatcherMixin, ServicesMixin, {
* @returns {Promise} The promise resolves to some kind of handle
*/
load: function () {
- return $.when();
+ return Promise.resolve();
},
});
@@ -119,9 +119,9 @@ var Controller = Widget.extend({
* @returns {Promise}
*/
start: function () {
- return $.when(
- this._super.apply(this, arguments),
- this._startRenderer()
+ return Promise.all(
+ [this._super.apply(this, arguments),
+ this._startRenderer()]
);
},
@@ -177,7 +177,8 @@ var Factory = Class.extend({
getController: function (parent) {
var self = this;
var model = this.getModel(parent);
- return $.when(this._loadData(model), ajax.loadLibs(this)).then(function (state) {
+ return Promise.all([this._loadData(model), ajax.loadLibs(this)]).then(function (result) {
+ var state = result[0];
var renderer = self.getRenderer(parent, state);
var Controller = self.Controller || self.config.Controller;
var controllerParams = _.extend({
diff --git a/addons/web/static/src/js/core/rpc.js b/addons/web/static/src/js/core/rpc.js
index cc56cb74ebb..21ec43e3d95 100644
--- a/addons/web/static/src/js/core/rpc.js
+++ b/addons/web/static/src/js/core/rpc.js
@@ -11,7 +11,7 @@ return {
*
* @param {Object} params @see buildQuery for a description
* @param {Object} options
- * @returns {Deferred<any>}
+ * @returns {Promise<any>}
*/
query: function (params, options) {
var query = this.buildQuery(params);
diff --git a/addons/web/static/src/js/core/service_mixins.js b/addons/web/static/src/js/core/service_mixins.js
index e8088d45cb5..4f296b6bb90 100644
--- a/addons/web/static/src/js/core/service_mixins.js
+++ b/addons/web/static/src/js/core/service_mixins.js
@@ -124,7 +124,7 @@ var ServicesMixin = {
return result;
},
/**
- * Builds and executes RPC query. Returns a deferred's promise resolved with
+ * Builds and executes RPC query. Returns a promise resolved with
* the RPC result.
*
* @param {string} params either a route or a model
@@ -133,11 +133,17 @@ var ServicesMixin = {
*/
_rpc: function (params, options) {
var query = rpc.buildQuery(params);
- var def = this.call('ajax', 'rpc', query.route, query.params, options, this) || $.Deferred();
- var promise = def.promise();
- var abort = (def.abort ? def.abort : def.reject) || function () {};
- promise.abort = abort.bind(def);
- return promise;
+ var prom = this.call('ajax', 'rpc', query.route, query.params, options, this);
+ if (!prom) {
+ prom = new Promise(function () {});
+ prom.abort = function () {};
+ }
+ var abort = prom.abort ? prom.abort : prom.reject;
+ if (!abort) {
+ throw new Error("a rpc promise should always have a reject function");
+ }
+ prom.abort = abort.bind(prom);
+ return prom;
},
loadFieldView: function (modelName, context, view_id, view_type, options) {
return this.loadViews(modelName, context, [[view_id, view_type]], options).then(function (result) {
@@ -145,41 +151,45 @@ var ServicesMixin = {
});
},
loadViews: function (modelName, context, views, options) {
- var def = $.Deferred();
- this.trigger_up('load_views', {
- modelName: modelName,
- context: context,
- views: views,
- options: options,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve) {
+ self.trigger_up('load_views', {
+ modelName: modelName,
+ context: context,
+ views: views,
+ options: options,
+ on_success: resolve,
+ });
});
- return def;
},
loadFilters: function (modelName, actionId, context) {
- var def = $.Deferred();
- this.trigger_up('load_filters', {
- modelName: modelName,
- actionId: actionId,
- context: context,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('load_filters', {
+ modelName: modelName,
+ actionId: actionId,
+ context: context,
+ on_success: resolve,
+ });
});
- return def;
},
createFilter: function (filter) {
- var def = $.Deferred();
- this.trigger_up('create_filter', {
- filter: filter,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('create_filter', {
+ filter: filter,
+ on_success: resolve,
+ });
});
- return def;
},
deleteFilter: function (filterId) {
- var def = $.Deferred();
- this.trigger_up('delete_filter', {
- filterId: filterId,
- on_success: def.resolve.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('delete_filter', {
+ filterId: filterId,
+ on_success: resolve,
+ });
});
- return def;
},
// Session stuff
getSession: function () {
@@ -195,22 +205,22 @@ var ServicesMixin = {
* Informs the action manager to do an action. This supposes that the action
* manager can be found amongst the ancestors of the current widget.
* If that's not the case this method will simply return an unresolved
- * deferred.
+ * promise.
*
* @param {any} action
* @param {any} options
- * @returns {Deferred}
+ * @returns {Promise}
*/
do_action: function (action, options) {
- var def = $.Deferred();
-
- this.trigger_up('do_action', {
- action: action,
- options: options,
- on_success: function (result) { def.resolve(result); },
- on_fail: function (result) { def.reject(result); },
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ self.trigger_up('do_action', {
+ action: action,
+ options: options,
+ on_success: resolve,
+ on_fail: reject,
+ });
});
- return def;
},
do_notify: function (title, message, sticky, className) {
return this.call('notification', 'notify', {title: title, message: message, sticky: sticky, className: className});
diff --git a/addons/web/static/src/js/core/session.js b/addons/web/static/src/js/core/session.js
index 14886591d7b..2874a2ea559 100644
--- a/addons/web/static/src/js/core/session.js
+++ b/addons/web/static/src/js/core/session.js
@@ -84,27 +84,27 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
*/
session_init: function () {
var self = this;
- var def = this.session_reload();
+ var prom = this.session_reload();
if (this.is_frontend) {
- return def.then(function () {
+ return prom.then(function () {
return self.load_translations();
});
}
- return def.then(function () {
+ return prom.then(function () {
var modules = self.module_list.join(',');
- var deferred = self.load_qweb(modules);
+ var promise = self.load_qweb(modules);
if (self.session_is_valid()) {
- return deferred.then(function () { return self.load_modules(); });
+ return promise.then(function () { return self.load_modules(); });
}
- return $.when(
- deferred,
+ return Promise.all([
+ promise,
self.rpc('/web/webclient/bootstrap_translations', {mods: self.module_list})
.then(function (trans) {
_t.database.set_bundle(trans);
})
- );
+ ]);
});
},
session_is_valid: function () {
@@ -119,7 +119,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
*/
session_authenticate: function () {
var self = this;
- return $.when(this._session_authenticate.apply(this, arguments)).then(function () {
+ return Promise.resolve(this._session_authenticate.apply(this, arguments)).then(function () {
return self.load_modules();
});
},
@@ -131,7 +131,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
var params = {db: db, login: login, password: password};
return this.rpc("/web/session/authenticate", params).then(function (result) {
if (!result.uid) {
- return $.Deferred().reject();
+ return Promise.reject();
}
_.extend(self, result);
});
@@ -142,7 +142,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
},
user_has_group: function (group) {
if (!this.uid) {
- return $.when(false);
+ return Promise.resolve(false);
}
var def = this._groups_def[group];
if (!def) {
@@ -196,22 +196,24 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
var to_load = _.difference(modules, self.module_list).join(',');
this.module_list = all_modules;
- var loaded = $.when(self.load_translations());
+ var loaded = Promise.resolve(self.load_translations());
var locale = "/web/webclient/locale/" + self.user_context.lang || 'en_US';
var file_list = [ locale ];
if(to_load.length) {
- loaded = $.when(
+ loaded = Promise.all([
loaded,
- self.rpc('/web/webclient/csslist', {mods: to_load}).done(self.load_css.bind(self)),
+ self.rpc('/web/webclient/csslist', {mods: to_load})
+ .then(self.load_css.bind(self)),
self.load_qweb(to_load),
- self.rpc('/web/webclient/jslist', {mods: to_load}).done(function (files) {
- file_list = file_list.concat(files);
- })
- );
+ self.rpc('/web/webclient/jslist', {mods: to_load})
+ .then(function (files) {
+ file_list = file_list.concat(files);
+ })
+ ]);
}
return loaded.then(function () {
return self.load_js(file_list);
- }).done(function () {
+ }).then(function () {
self.on_modules_loaded();
self.trigger('module_loaded');
});
@@ -227,24 +229,24 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
},
load_js: function (files) {
var self = this;
- var d = $.Deferred();
- if (files.length !== 0) {
- var file = files.shift();
- var url = self.url(file, null);
- ajax.loadJS(url).done(d.resolve);
- } else {
- d.resolve();
- }
- return d;
+ return new Promise(function (resolve, reject) {
+ if (files.length !== 0) {
+ var file = files.shift();
+ var url = self.url(file, null);
+ ajax.loadJS(url).then(resolve);
+ } else {
+ resolve();
+ }
+ });
},
load_qweb: function (mods) {
- this.qweb_mutex.exec(function () {
+ var lock = this.qweb_mutex.exec(function () {
return $.get('/web/webclient/qweb?mods=' + mods).then(function (doc) {
if (!doc) { return; }
qweb.add_template(doc);
});
});
- return this.qweb_mutex.def;
+ return lock;
},
on_modules_loaded: function () {
var openerp = window.openerp;
@@ -276,12 +278,12 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
* (re)loads the content of a session: db name, username, user id, session
* context and status of the support contract
*
- * @returns {$.Deferred} deferred indicating the session is done reloading
+ * @returns {Promise} promise indicating the session is done reloading
*/
session_reload: function () {
var result = _.extend({}, window.odoo.session_info);
_.extend(this, result);
- return $.when();
+ return Promise.resolve();
},
/**
* Executes an RPC call, registering the provided callbacks.
@@ -293,7 +295,7 @@ var Session = core.Class.extend(mixins.EventDispatcherMixin, {
* @param {String} url RPC endpoint
* @param {Object} params call parameters
* @param {Object} options additional options for rpc call
- * @returns {jQuery.Deferred} jquery-provided ajax deferred
+ * @returns {Promise}
*/
rpc: function (url, params, options) {
var self = this;
diff --git a/addons/web/static/src/js/core/translation.js b/addons/web/static/src/js/core/translation.js
index 76493fdb432..83c556c3c37 100644
--- a/addons/web/static/src/js/core/translation.js
+++ b/addons/web/static/src/js/core/translation.js
@@ -58,14 +58,14 @@ var TranslationDataBase = Class.extend(/** @lends instance.TranslationDataBase#
@param {Object} [lang] lang The language. If not specified it will default to the language
of the current user.
@param {string} [url='/web/webclient/translations']
- @returns {jQuery.Deferred}
+ @returns {Promise}
*/
load_translations: function(session, modules, lang, url) {
var self = this;
return session.rpc(url || '/web/webclient/translations', {
"mods": modules || null,
"lang": lang || null
- }).done(function(trans) {
+ }).then(function (trans) {
self.set_bundle(trans);
});
}
diff --git a/addons/web/static/src/js/core/widget.js b/addons/web/static/src/js/core/widget.js
index d3b9cc1033c..0de8c6aa1cd 100644
--- a/addons/web/static/src/js/core/widget.js
+++ b/addons/web/static/src/js/core/widget.js
@@ -31,7 +31,7 @@ var ServicesMixin = require('web.ServicesMixin');
* },
* willStart: function () {
* // async work that need to be done before the widget is ready
- * // this method should return a deferred
+ * // this method should return a promise
* },
* start: function() {
* // stuff you want to make after the rendering, `this.$el` holds a correct value
@@ -135,45 +135,47 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Method called between @see init and @see start. Performs asynchronous
* calls required by the rendering and the start method.
*
- * This method should return a Deferred which is resolved when start can be
+ * This method should return a Promose which is resolved when start can be
* executed.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
willStart: function () {
- var defs = [];
+ var proms = [];
if (this.xmlDependencies) {
- defs.push.apply(defs, _.map(this.xmlDependencies, function (xmlPath) {
+ proms.push.apply(proms, _.map(this.xmlDependencies, function (xmlPath) {
return ajax.loadXML(xmlPath, core.qweb);
}));
}
if (this.jsLibs || this.cssLibs || this.assetLibs) {
- defs.push(ajax.loadLibs(this));
+ proms.push(ajax.loadLibs(this));
}
- return $.when.apply($, defs);
+ return Promise.all(proms);
},
/**
* Method called after rendering. Mostly used to bind actions, perform
* asynchronous calls, etc...
*
* By convention, this method should return an object that can be passed to
- * $.when() to inform the caller when this widget has been initialized.
+ * Promise.resolve() to inform the caller when this widget has been initialized.
*
* Note that, for historic reasons, many widgets still do work in the start
* method that would be more suited to the willStart method.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
- return $.when();
+ return Promise.resolve();
},
/**
* Destroys the current widget, also destroys all its children before
* destroying itself.
*/
destroy: function () {
- _.invoke(this.getChildren(), 'destroy');
- if(this.$el) {
+ this.getChildren().forEach(function (child) {
+ child.destroy();
+ });
+ if (this.$el) {
this.$el.remove();
}
mixins.PropertiesMixin.destroy.call(this);
@@ -187,6 +189,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Renders the current widget and appends it to the given jQuery object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
appendTo: function (target) {
var self = this;
@@ -198,6 +201,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Attach the current widget to a dom element
*
* @param {jQuery} target
+ * @returns {Promise}
*/
attachTo: function (target) {
var self = this;
@@ -234,6 +238,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
insertAfter: function (target) {
var self = this;
@@ -246,6 +251,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
insertBefore: function (target) {
var self = this;
@@ -257,6 +263,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Renders the current widget and prepends it to the given jQuery object.
*
* @param {jQuery} target
+ * @returns {Promise}
*/
prependTo: function (target) {
var self = this;
@@ -282,6 +289,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* Renders the current widget and replaces the given jQuery object.
*
* @param target A jQuery object or a Widget instance.
+ * @returns {Promise}
*/
replace: function (target) {
return this._widgetRenderAndInsert(_.bind(function (t) {
@@ -415,7 +423,7 @@ var Widget = core.Class.extend(mixins.PropertiesMixin, ServicesMixin, {
* @private
* @param {function: jQuery -> any} insertion
* @param {jQuery} target
- * @returns {Deferred}
+ * @returns {Promise}
*/
_widgetRenderAndInsert: function (insertion, target) {
var self = this;
diff --git a/addons/web/static/src/js/fields/abstract_field.js b/addons/web/static/src/js/fields/abstract_field.js
index edc7c03ac02..822c90c31f4 100644
--- a/addons/web/static/src/js/fields/abstract_field.js
+++ b/addons/web/static/src/js/fields/abstract_field.js
@@ -184,7 +184,7 @@ var AbstractField = Widget.extend({
* When a field widget is appended to the DOM, its start method is called,
* and will automatically call render. Most widgets should not override this.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
var self = this;
@@ -236,7 +236,7 @@ var AbstractField = Widget.extend({
* if the value changed but was not notified.
*
* @abstract
- * @returns {Deferred|undefined}
+ * @returns {Promise|undefined}
*/
commitChanges: function () {},
/**
@@ -290,12 +290,12 @@ var AbstractField = Widget.extend({
* is optional, and may be used by a widget to share information from the
* moment a field change event is triggered to the moment a reset
* operation is applied.
- * @returns {Deferred} A Deferred, which resolves when the widget rendering
+ * @returns {Promise} A promise, which resolves when the widget rendering
* is complete
*/
reset: function (record, event) {
this._reset(record, event);
- return this._render() || $.when();
+ return this._render() || Promise.resolve();
},
/**
* Remove the invalid class on a field
@@ -396,7 +396,7 @@ var AbstractField = Widget.extend({
* synchronous.
*
* @private
- * @returns {Deferred|undefined}
+ * @returns {Promise|undefined}
*/
_render: function () {
if (this.attrs.decorations) {
@@ -413,7 +413,7 @@ var AbstractField = Widget.extend({
* concrete widget.
*
* @private
- * @returns {Deferred|undefined}
+ * @returns {Promise|undefined}
*/
_renderEdit: function () {
},
@@ -422,7 +422,7 @@ var AbstractField = Widget.extend({
* the concrete widget.
*
* @private
- * @returns {Deferred|undefined}
+ * @returns {Promise|undefined}
*/
_renderReadonly: function () {
},
@@ -457,13 +457,13 @@ var AbstractField = Widget.extend({
* will not notify and not trigger the onchange, even though it was changed.
* @param {boolean} [options.forceChange=false] if true, the change event will be
* triggered even if the new value is the same as the old one
- * @returns {Deferred}
+ * @returns {Promise}
*/
_setValue: function (value, options) {
// we try to avoid doing useless work, if the value given has not
// changed. Note that we compare the unparsed values.
if (this.lastSetValue === value || (this.value === false && value === '')) {
- return $.when();
+ return Promise.resolve();
}
this.lastSetValue = value;
try {
@@ -472,25 +472,26 @@ var AbstractField = Widget.extend({
} catch (e) {
this._isValid = false;
this.trigger_up('set_dirty', {dataPointID: this.dataPointID});
- return $.Deferred().reject();
+ return Promise.reject({message: "Value set is not valid"});
}
if (!(options && options.forceChange) && this._isSameValue(value)) {
- return $.when();
+ return Promise.resolve();
}
- var def = $.Deferred();
- var changes = {};
- changes[this.name] = value;
- this.trigger_up('field_changed', {
- dataPointID: this.dataPointID,
- changes: changes,
- viewType: this.viewType,
- doNotSetDirty: options && options.doNotSetDirty,
- notifyChange: !options || options.notifyChange !== false,
- allowWarning: options && options.allowWarning,
- onSuccess: def.resolve.bind(def),
- onFailure: def.reject.bind(def),
+ var self = this;
+ return new Promise(function (resolve, reject) {
+ var changes = {};
+ changes[self.name] = value;
+ self.trigger_up('field_changed', {
+ dataPointID: self.dataPointID,
+ changes: changes,
+ viewType: self.viewType,
+ doNotSetDirty: options && options.doNotSetDirty,
+ notifyChange: !options || options.notifyChange !== false,
+ allowWarning: options && options.allowWarning,
+ onSuccess: resolve,
+ onFailure: reject,
+ });
});
- return def;
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/fields/basic_fields.js b/addons/web/static/src/js/fields/basic_fields.js
index c6df3885a86..a87ff3e4436 100644
--- a/addons/web/static/src/js/fields/basic_fields.js
+++ b/addons/web/static/src/js/fields/basic_fields.js
@@ -213,7 +213,7 @@ var InputField = DebouncedField.extend({
// sure they are recomputed.
this._applyDecorations();
}
- return $.when();
+ return Promise.resolve();
} else {
return this._render();
}
@@ -486,8 +486,6 @@ var LinkButton = AbstractField.extend({
});
-
-
var FieldDate = InputField.extend({
className: "o_field_date",
tagName: "span",
@@ -513,7 +511,7 @@ var FieldDate = InputField.extend({
*/
start: function () {
var self = this;
- var def;
+ var prom;
if (this.mode === 'edit') {
this.datewidget = this._makeDatePicker();
this.datewidget.on('datetime_changed', this, function () {
@@ -522,13 +520,13 @@ var FieldDate = InputField.extend({
this._setValue(value);
}
});
- def = this.datewidget.appendTo('<div>').done(function () {
+ prom = this.datewidget.appendTo('<div>').then(function () {
self.datewidget.$el.addClass(self.$el.attr('class'));
self._prepareInput(self.datewidget.$input);
self._replaceElement(self.datewidget.$el);
});
}
- return $.when(def, this._super.apply(this, arguments));
+ return Promise.resolve(prom).then(this._super.bind(this));
},
//--------------------------------------------------------------------------
@@ -728,7 +726,7 @@ var FieldMonetary = InputField.extend({
this.$el.empty();
// Prepare and add the input
- this._prepareInput(this.$input).appendTo(this.$el);
+ var def = this._prepareInput(this.$input).appendTo(this.$el);
if (this.currency) {
// Prepare and add the currency symbol
@@ -739,6 +737,7 @@ var FieldMonetary = InputField.extend({
this.$el.prepend($currencySymbol);
}
}
+ return def;
},
/**
* @override
@@ -1136,7 +1135,7 @@ var FieldText = InputField.extend(TranslatableFieldMixin, {
*/
reset: function () {
var self = this;
- return $.when(this._super.apply(this, arguments)).then(function () {
+ return Promise.resolve(this._super.apply(this, arguments)).then(function () {
if (self.mode === 'edit') {
self.$input.trigger('change');
}
@@ -2568,7 +2567,7 @@ var JournalDashboardGraph = AbstractField.extend({
if (this._isInDOM) {
return this._renderInDOM();
}
- return $.when();
+ return Promise.resolve();
},
/**
* Render the widget. This function assumes that it is attached to the DOM.
@@ -2743,13 +2742,13 @@ var FieldDomain = AbstractField.extend({
/**
* @private
* @override _render from AbstractField
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
// If there is no model, only change the non-domain-selector content
if (!this._domainModel) {
this._replaceContent();
- return $.when();
+ return Promise.resolve();
}
// Convert char value to array value
@@ -2901,7 +2900,7 @@ var AceEditor = DebouncedField.extend({
/**
* @override start from AbstractField (Widget)
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this._startAce(this.$('.ace-view-editor')[0]);
diff --git a/addons/web/static/src/js/fields/field_registry.js b/addons/web/static/src/js/fields/field_registry.js
index 35d10c5a5e4..0e0ba3dc117 100644
--- a/addons/web/static/src/js/fields/field_registry.js
+++ b/addons/web/static/src/js/fields/field_registry.js
@@ -6,7 +6,7 @@ var Registry = require('web.Registry');
return new Registry();
});
-odoo.define('web._field_registry', function(require) {
+odoo.define('web._field_registry', function (require) {
"use strict";
var AbstractField = require('web.AbstractField');
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index bd46faf1e08..469cedb8ff1 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -171,11 +171,11 @@ var FieldMany2One = AbstractField.extend({
* is saved.
*
* @override
- * @returns {Deferred} resolved as soon as there is no longer record being
+ * @returns {Promise} resolved as soon as there is no longer record being
* (quick) created
*/
commitChanges: function () {
- return $.when(this.createDef);
+ return Promise.resolve(this.createDef);
},
/**
* @override
@@ -208,7 +208,7 @@ var FieldMany2One = AbstractField.extend({
this.isDirty = false;
}
if (this.isDirty) {
- return $.when();
+ return Promise.resolve();
} else {
return this._render();
}
@@ -257,9 +257,9 @@ var FieldMany2One = AbstractField.extend({
if (!source.validation || source.validation.call(self, req.term)) {
source.loading = true;
- // Wrap the returned value of the source.method with $.when.
+ // Wrap the returned value of the source.method with a promise
// So event if the returned value is not async, it will work
- $.when(source.method.call(self, req.term)).then(function (results) {
+ Promise.resolve(source.method.call(self, req.term)).then(function (results) {
source.results = results;
source.loading = false;
resp(self._concatenateAutocompleteResults());
@@ -366,49 +366,55 @@ var FieldMany2One = AbstractField.extend({
/**
* @private
* @param {string} name
- * @returns {Deferred} resolved after the name_create or when the slowcreate
+ * @returns {Promise} resolved after the name_create or when the slowcreate
* modal is closed.
*/
_quickCreate: function (name) {
var self = this;
- var def = $.Deferred();
- this.createDef = this.createDef || $.Deferred();
- // called when the record has been quick created, or when the dialog has
- // been closed (in the case of a 'slow' create), meaning that the job is
- // done
- var createDone = function () {
- def.resolve();
- self.createDef.resolve();
- self.createDef = undefined;
- };
- // called if the quick create is disabled on this many2one, or if the
- // quick creation failed (probably because there are mandatory fields on
- // the model)
- var slowCreate = function () {
- var dialog = self._searchCreatePopup("form", false, self._createContext(name));
- dialog.on('closed', self, createDone);
- };
- if (this.nodeOptions.quick_create) {
- var nameCreateDef = this._rpc({
- model: this.field.relation,
- method: 'name_create',
- args: [name],
- context: this.record.getContext(this.recordParams),
- }).fail(function (error, ev) {
- ev.preventDefault();
- slowCreate();
+ var createDone;
+
+ var def = new Promise(function (resolve, reject) {
+ self.createDef = new Promise(function (innerResolve) {
+ // called when the record has been quick created, or when the dialog has
+ // been closed (in the case of a 'slow' create), meaning that the job is
+ // done
+ createDone = function () {
+ innerResolve();
+ resolve();
+ self.createDef = undefined;
+ };
});
- this.dp.add(nameCreateDef)
- .then(function (result) {
- if (self.mode === "edit") {
- self.reinitialize({id: result[0], display_name: result[1]});
- }
- createDone();
- })
- .fail(def.reject.bind(def));
- } else {
- slowCreate();
- }
+
+ // called if the quick create is disabled on this many2one, or if the
+ // quick creation failed (probably because there are mandatory fields on
+ // the model)
+ var slowCreate = function () {
+ var dialog = self._searchCreatePopup("form", false, self._createContext(name));
+ dialog.on('closed', self, createDone);
+ };
+ if (self.nodeOptions.quick_create) {
+ var nameCreateDef = self._rpc({
+ model: self.field.relation,
+ method: 'name_create',
+ args: [name],
+ context: self.record.getContext(self.recordParams),
+ }).guardedCatch(function (reason) {
+ reason.event.preventDefault();
+ slowCreate();
+ });
+ self.dp.add(nameCreateDef)
+ .then(function (result) {
+ if (self.mode === "edit") {
+ self.reinitialize({id: result[0], display_name: result[1]});
+ }
+ createDone();
+ })
+ .guardedCatch(reject);
+ } else {
+ slowCreate();
+ }
+ });
+
return def;
},
/**
@@ -456,35 +462,32 @@ var FieldMany2One = AbstractField.extend({
*
* @private
* @param {string} search_val
- * @returns {Deferred}
+ * @returns {Promise}
*/
_search: function (search_val) {
var self = this;
- var def = $.Deferred();
- this.orderer.add(def);
-
- var context = this.record.getContext(this.recordParams);
- var domain = this.record.getDomain(this.recordParams);
+ var def = new Promise(function (resolve, reject) {
+ var context = self.record.getContext(self.recordParams);
+ var domain = self.record.getDomain(self.recordParams);
- // Add the additionalContext
- _.extend(context, this.additionalContext);
+ // Add the additionalContext
+ _.extend(context, self.additionalContext);
- var blacklisted_ids = this._getSearchBlacklist();
- if (blacklisted_ids.length > 0) {
- domain.push(['id', 'not in', blacklisted_ids]);
- }
+ var blacklisted_ids = self._getSearchBlacklist();
+ if (blacklisted_ids.length > 0) {
+ domain.push(['id', 'not in', blacklisted_ids]);
+ }
- this._rpc({
- model: this.field.relation,
- method: "name_search",
- kwargs: {
- name: search_val,
- args: domain,
- operator: "ilike",
- limit: this.limit + 1,
- context: context,
- }})
- .then(function (result) {
+ self._rpc({
+ model: self.field.relation,
+ method: "name_search",
+ kwargs: {
+ name: search_val,
+ args: domain,
+ operator: "ilike",
+ limit: self.limit + 1,
+ context: context,
+ }}).then(function (result) {
// possible selections for the m2o
var values = _.map(result, function (x) {
x[1] = self._getDisplayName(x[1]);
@@ -516,7 +519,7 @@ var FieldMany2One = AbstractField.extend({
},
});
}
- $.when(prom).then(function (results) {
+ Promise.resolve(prom).then(function (results) {
var dynamicFilters;
if (results) {
var ids = _.map(results, function (x) {
@@ -563,9 +566,10 @@ var FieldMany2One = AbstractField.extend({
});
}
- def.resolve(values);
+ resolve(values);
});
-
+ });
+ this.orderer.add(def);
return def;
},
/**
@@ -670,8 +674,9 @@ var FieldMany2One = AbstractField.extend({
readonly: !self.can_write,
on_saved: function (record, changed) {
if (changed) {
- self._setValue(self.value.data, {forceChange: true});
- self.trigger_up('reload', {db_id: self.value.id});
+ self._setValue(self.value.data, {forceChange: true}).then(function() {
+ self.trigger_up('reload', {db_id: self.value.id});
+ });
}
},
}).open();
@@ -868,14 +873,14 @@ var FieldX2Many = AbstractField.extend({
* user if he wants to discard it if necessary.
*
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
commitChanges: function () {
var self = this;
var inEditionRecordID =
- this.renderer
- && this.renderer.viewType === "list"
- && this.renderer.getEditableRecordID();
+ this.renderer &&
+ this.renderer.viewType === "list" &&
+ this.renderer.getEditableRecordID();
if (inEditionRecordID) {
return this.renderer.commitChanges(inEditionRecordID).then(function () {
return self._saveLine(inEditionRecordID);
@@ -894,7 +899,7 @@ var FieldX2Many = AbstractField.extend({
* @param {Object} record
* @param {OdooEvent} [ev] an event that triggered the reset action
* @param {Boolean} [fieldChanged] if true, the widget field has changed
- * @returns {Deferred}
+ * @returns {Promise}
*/
reset: function (record, ev, fieldChanged) {
// If 'fieldChanged' is false, it means that the reset was triggered by
@@ -904,7 +909,7 @@ var FieldX2Many = AbstractField.extend({
if (!fieldChanged) {
var newEval = this._evalColumnInvisibleFields();
if (_.isEqual(this.currentColInvisibleFields, newEval)) {
- return $.when();
+ return Promise.resolve();
}
} else if (ev && ev.target === this && ev.data.changes && this.view.arch.tag === 'tree') {
var command = ev.data.changes[this.name];
@@ -994,17 +999,20 @@ var FieldX2Many = AbstractField.extend({
*
* @override
* @private
- * @returns {Deferred|undefined}
+ * @returns {Promise|undefined}
*/
_render: function () {
+ var self = this;
if (!this.view) {
return this._super();
}
if (this.renderer) {
this.currentColInvisibleFields = this._evalColumnInvisibleFields();
- this.renderer.updateState(this.value, {'columnInvisibleFields': this.currentColInvisibleFields});
- this.pager.updateState({ size: this.value.count });
- return $.when();
+ return this.renderer.updateState(this.value, {
+ columnInvisibleFields: this.currentColInvisibleFields,
+ }).then(function () {
+ self.pager.updateState({ size: self.value.count });
+ });
}
var arch = this.view.arch;
var viewType;
@@ -1050,11 +1058,11 @@ var FieldX2Many = AbstractField.extend({
* Prepends the control panel's $el to this widget's $el.
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderControlPanel: function () {
if (!this.view) {
- return $.when();
+ return Promise.resolve();
}
var self = this;
var defs = [];
@@ -1072,7 +1080,7 @@ var FieldX2Many = AbstractField.extend({
validate: function () {
var isList = self.view.arch.tag === 'tree';
// TODO: we should have some common method in the basic renderer...
- return isList ? self.renderer.unselectRow() : $.when();
+ return isList ? self.renderer.unselectRow() : Promise.resolve();
},
});
this.pager.on('pager_changed', this, function (new_state) {
@@ -1089,7 +1097,7 @@ var FieldX2Many = AbstractField.extend({
this._renderButtons();
defs.push(this.pager.appendTo($('<div>'))); // start the pager
defs.push(cpDef);
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
self._controlPanel.updateContents({
cp_content: {
$buttons: self.$buttons,
@@ -1123,24 +1131,24 @@ var FieldX2Many = AbstractField.extend({
*
* @private
* @param {string} recordID
- * @returns {Deferred} resolved if the line was properly saved or discarded.
+ * @returns {Promise} resolved if the line was properly saved or discarded.
* rejected if the line could not be saved and the user
* did not agree to discard.
*/
_saveLine: function (recordID) {
var self = this;
- var def = $.Deferred();
- var fieldNames = this.renderer.canBeSaved(recordID);
- if (fieldNames.length) {
- this.trigger_up('discard_changes', {
- recordID: recordID,
- onSuccess: def.resolve.bind(def),
- onFailure: def.reject.bind(def),
- });
- } else {
- this.renderer.setRowMode(recordID, 'readonly').done(def.resolve.bind(def));
- }
- return def.then(function () {
+ return new Promise(function (resolve, reject) {
+ var fieldNames = self.renderer.canBeSaved(recordID);
+ if (fieldNames.length) {
+ self.trigger_up('discard_changes', {
+ recordID: recordID,
+ onSuccess: resolve,
+ onFailure: reject,
+ });
+ } else {
+ self.renderer.setRowMode(recordID, 'readonly').then(resolve);
+ }
+ }).then(function () {
self.pager.updateState({ size: self.value.count });
var newEval = self._evalColumnInvisibleFields();
if (!_.isEqual(self.currentColInvisibleFields, newEval)) {
@@ -1233,7 +1241,7 @@ var FieldX2Many = AbstractField.extend({
this.trigger_up('edited_list', { id: this.value.id });
var editedRecord = this.value.data[ev.data.index];
this.renderer.setRowMode(editedRecord.id, 'edit')
- .done(ev.data.onSuccess);
+ .then(ev.data.onSuccess);
},
/**
* Updates the given record with the changes.
@@ -1260,11 +1268,11 @@ var FieldX2Many = AbstractField.extend({
operation: 'UPDATE',
id: ev.data.dataPointID,
data: changes,
- }).done(function () {
+ }).then(function () {
if (ev.data.onSuccess) {
ev.data.onSuccess();
}
- }).fail(function () {
+ }).guardedCatch(function () {
if (ev.data.onFailure) {
ev.data.onFailure();
}
@@ -1332,8 +1340,8 @@ var FieldX2Many = AbstractField.extend({
self.trigger_up('mutexify', {
action: function () {
return self._saveLine(ev.data.recordID)
- .done(ev.data.onSuccess)
- .fail(ev.data.onFailure);
+ .then(ev.data.onSuccess)
+ .guardedCatch(ev.data.onFailure);
},
});
});
@@ -1361,18 +1369,20 @@ var FieldX2Many = AbstractField.extend({
notifyChange: false,
});
});
- $.when.apply($, defs).then(function () {
+ Promise.all(defs).then(function () {
+ function always() {
+ self.trigger_up('toggle_column_order', {
+ id: self.value.id,
+ name: event.data.handleField,
+ });
+ }
+
// trigger only once the onchange for parent record
self._setValue({
operation: 'UPDATE',
id: rowID,
data: _.object([event.data.handleField], [event.data.offset + rowIDs.length]),
- }).always(function () {
- self.trigger_up('toggle_column_order', {
- id: self.value.id,
- name: event.data.handleField,
- });
- });
+ }).then(always).guardedCatch(always);
});
},
/**
@@ -1418,7 +1428,7 @@ var FieldOne2Many = FieldX2Many.extend({
* @override
* @param {Object} record
* @param {OdooEvent} [ev] an event that triggered the reset action
- * @returns {Deferred}
+ * @returns {Promise}
*/
reset: function (record, ev) {
var self = this;
@@ -1527,13 +1537,16 @@ var FieldOne2Many = FieldX2Many.extend({
context: data.context,
}, {
allowWarning: data.allowWarning
- }).always(function () {
+ }).then(function () {
self.creatingRecord = false;
- }).done(function (){
+ }).then(function (){
if (data.onSuccess){
data.onSuccess();
}
- });
+ }).guardedCatch(function() {
+ self.creatingRecord = false;
+ })
+ ;
}
} else {
this._openFormDialog({
@@ -1646,8 +1659,10 @@ var FieldMany2Many = FieldX2Many.extend({
domain: this.record.getDomain(this.recordParams),
fields_view: this.attrs.views && this.attrs.views.form,
on_saved: function () {
- self._setValue({operation: 'TRIGGER_ONCHANGE'}, {forceChange: true});
- self.trigger_up('reload', {db_id: ev.data.id});
+ self._setValue({operation: 'TRIGGER_ONCHANGE'}, {forceChange: true})
+ .then(function () {
+ self.trigger_up('reload', {db_id: ev.data.id});
+ });
},
on_remove: function () {
self._setValue({operation: 'FORGET', ids: [ev.data.id]});
@@ -1918,10 +1933,12 @@ var FieldMany2ManyTags = AbstractField.extend({
* @override
*/
reset: function (record, event) {
- this._super.apply(this, arguments);
- if (event && event.target === this) {
- this.activate();
- }
+ var self = this;
+ return this._super.apply(this, arguments).then(function(){
+ if (event && event.target === self) {
+ self.activate();
+ }
+ });
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/fields/upgrade_fields.js b/addons/web/static/src/js/fields/upgrade_fields.js
index dd91ca2efc2..8dd1f9d3ae8 100644
--- a/addons/web/static/src/js/fields/upgrade_fields.js
+++ b/addons/web/static/src/js/fields/upgrade_fields.js
@@ -34,7 +34,7 @@ var AbstractFieldUpgrade = {
* Redirects the user to the odoo-enterprise/uprade page
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmUpgrade: function () {
return this._rpc({
diff --git a/addons/web/static/src/js/public/public_root.js b/addons/web/static/src/js/public/public_root.js
index 7c508bd9192..97448408282 100644
--- a/addons/web/static/src/js/public/public_root.js
+++ b/addons/web/static/src/js/public/public_root.js
@@ -49,11 +49,11 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
*/
willStart: function () {
// TODO would be even greater to wait for localeDef only when necessary
- return $.when(
+ return Promise.all([
this._super.apply(this, arguments),
session.is_bound,
localeDef
- );
+ ]);
},
/**
* @override
@@ -82,7 +82,7 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
$('input, textarea').placeholder();
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
//--------------------------------------------------------------------------
@@ -193,9 +193,9 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
self.publicWidgets.push(widget);
return widget.attachTo($(el));
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Destroys all registered widget instances. Website would need this before
@@ -259,8 +259,8 @@ var PublicRoot = publicWidget.RootWidget.extend(ServiceProviderMixin, {
*/
_onWidgetsStartRequest: function (ev) {
this._startWidgets(ev.data.$target, ev.data.options)
- .done(ev.data.onSuccess)
- .fail(ev.data.onFailure);
+ .then(ev.data.onSuccess)
+ .guardedCatch(ev.data.onFailure);
},
/**
* Called when the root is notified that the public widgets have to be
diff --git a/addons/web/static/src/js/public/public_widget.js b/addons/web/static/src/js/public/public_widget.js
index ec9c50ad9a8..79382e117d8 100644
--- a/addons/web/static/src/js/public/public_widget.js
+++ b/addons/web/static/src/js/public/public_widget.js
@@ -43,7 +43,7 @@ var RootWidget = Widget.extend({
defs.push(this._attachComponents());
this._listenToUpdates = true;
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
//--------------------------------------------------------------------------
@@ -71,7 +71,7 @@ var RootWidget = Widget.extend({
self._widgets.push(w);
return w.attachTo(element);
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Instantiates the child widgets that need to be according to the linked
@@ -88,7 +88,7 @@ var RootWidget = Widget.extend({
var defs = _.map(childInfos, function (childInfo) {
return self._attachComponent(childInfo, $from);
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Returns the `RootWidgetRegistry` instance that is linked to this
diff --git a/addons/web/static/src/js/report/client_action.js b/addons/web/static/src/js/report/client_action.js
index 099ee77a527..c8b5621e6de 100644
--- a/addons/web/static/src/js/report/client_action.js
+++ b/addons/web/static/src/js/report/client_action.js
@@ -37,7 +37,7 @@ var ReportAction = AbstractAction.extend({
start: function () {
var self = this;
this.iframe = this.$('iframe')[0];
- return $.when(this._super.apply(this, arguments), session.is_bound).then(function () {
+ return Promise.all([this._super.apply(this, arguments), session.is_bound]).then(function () {
var web_base_url = session['web.base.url'];
var trusted_host = utils.get_host_from_url(web_base_url);
var trusted_protocol = utils.get_protocol_from_url(web_base_url);
@@ -105,7 +105,7 @@ var ReportAction = AbstractAction.extend({
/**
* Helper allowing to send a message to the `this.el` iframe's window and
- * seting the `targetOrigin` as `this.trusted_origin` (which is the
+ * seting the `targetOrigin` as `this.trusted_origin` (which is the
* `web.base.url` ir.config_parameter key) - in other word, only when using
* this method we only send the message to a trusted domain.
*/
diff --git a/addons/web/static/src/js/services/ajax_service.js b/addons/web/static/src/js/services/ajax_service.js
index 0cecaae9da3..cb83dd9d553 100644
--- a/addons/web/static/src/js/services/ajax_service.js
+++ b/addons/web/static/src/js/services/ajax_service.js
@@ -7,19 +7,20 @@ var session = require('web.session');
var AjaxService = AbstractService.extend({
rpc: function (route, args, options, target) {
- var def = $.Deferred();
- var promise = def.promise();
- var xhrDef = session.rpc(route, args, options);
- promise.abort = xhrDef.abort.bind(xhrDef);
- xhrDef.then(function () {
- if (!target.isDestroyed()) {
- def.resolve.apply(def, arguments);
- }
- }).fail(function () {
- if (!target.isDestroyed()) {
- def.reject.apply(def, arguments);
- }
+ var rpcPromise;
+ var promise = new Promise(function (resolve, reject) {
+ rpcPromise = session.rpc(route, args, options);
+ rpcPromise.then(function (result) {
+ if (!target.isDestroyed()) {
+ resolve(result);
+ }
+ }).guardedCatch(function (reason) {
+ if (!target.isDestroyed()) {
+ reject(reason);
+ }
+ });
});
+ promise.abort = rpcPromise.abort.bind(rpcPromise);
return promise;
},
});
diff --git a/addons/web/static/src/js/services/core.js b/addons/web/static/src/js/services/core.js
index 3d6cfc4e684..ee37479e217 100644
--- a/addons/web/static/src/js/services/core.js
+++ b/addons/web/static/src/js/services/core.js
@@ -13,15 +13,15 @@ var translation = require('web.translation');
*
* @type Boolean
*/
-var bus = new Bus ();
+var bus = new Bus();
-_.each('click,dblclick,keydown,keypress,keyup'.split(','), function(evtype) {
- $('html').on(evtype, function(ev) {
+_.each('click,dblclick,keydown,keypress,keyup'.split(','), function (evtype) {
+ $('html').on(evtype, function (ev) {
bus.trigger(evtype, ev);
});
});
-_.each('resize,scroll'.split(','), function(evtype) {
- $(window).on(evtype, function(ev) {
+_.each('resize,scroll'.split(','), function (evtype) {
+ $(window).on(evtype, function (ev) {
bus.trigger(evtype, ev);
});
});
@@ -37,7 +37,7 @@ return {
_lt: translation._lt,
// registries
- action_registry : new Registry(),
+ action_registry: new Registry(),
crash_registry: new Registry(),
serviceRegistry: new Registry(),
/**
diff --git a/addons/web/static/src/js/services/crash_manager.js b/addons/web/static/src/js/services/crash_manager.js
index db88d688505..a29e21ca8ca 100644
--- a/addons/web/static/src/js/services/crash_manager.js
+++ b/addons/web/static/src/js/services/crash_manager.js
@@ -65,7 +65,7 @@ var CrashManager = core.Class.extend({
ajax.jsonRpc('/web/webclient/version_info', 'call', {}, {shadow:true}).then(function () {
core.bus.trigger('connection_restored');
self.isConnected = true;
- }).fail(function () {
+ }).guardedCatch(function () {
// exponential backoff, with some jitter
delay = (delay * 1.5) + 500*Math.random();
setTimeout(checkConnection, delay);
diff --git a/addons/web/static/src/js/services/data_manager.js b/addons/web/static/src/js/services/data_manager.js
index 348054691bc..b2f6ef1feb1 100644
--- a/addons/web/static/src/js/services/data_manager.js
+++ b/addons/web/static/src/js/services/data_manager.js
@@ -33,7 +33,7 @@ return core.Class.extend({
*
* @param {int|string} [action_id] the action id or xmlid
* @param {Object} [additional_context] used to load the action
- * @return {Deferred} resolved with the action whose id or xmlid is action_id
+ * @return {Promise} resolved with the action whose id or xmlid is action_id
*/
load_action: function (action_id, additional_context) {
var self = this;
@@ -69,7 +69,7 @@ return core.Class.extend({
* - options.load_filters: whether or not to load the filters,
* - options.action_id: the action_id (required to load filters),
* - options.toolbar: whether or not a toolbar will be displayed,
- * @return {Deferred} resolved with the requested views information
+ * @return {Promise} resolved with the requested views information
*/
load_views: function (params, options) {
var self = this;
@@ -108,12 +108,12 @@ return core.Class.extend({
var fvg = result.fields_views[view_descr[1]];
fvg.viewFields = fvg.fields;
fvg.fields = result.fields;
- self._cache.fields_views[fv_key] = $.when(fvg);
+ self._cache.fields_views[fv_key] = Promise.resolve(fvg);
});
// Insert filters, if any, into the filters cache
if (result.filters) {
- self._cache.filters[filters_key] = $.when(result.filters);
+ self._cache.filters[filters_key] = Promise.resolve(result.filters);
}
return result.fields_views;
@@ -130,7 +130,7 @@ return core.Class.extend({
* @param {string} params.modelName
* @param {Object} params.context
* @param {integer} params.actionId
- * @return {Deferred} resolved with the requested filters
+ * @return {Promise} resolved with the requested filters
*/
load_filters: function (params) {
var key = this._gen_key(params.modelName, params.actionId);
@@ -143,7 +143,7 @@ return core.Class.extend({
},
model: 'ir.filters',
method: 'get_filters',
- }).fail(this._invalidate.bind(this, this._cache.filters, key));
+ }).guardedCatch(this._invalidate.bind(this, this._cache.filters, key));
}
return this._cache.filters[key];
},
@@ -152,7 +152,7 @@ return core.Class.extend({
* Calls 'create_or_replace' on 'ir_filters'.
*
* @param {Object} [filter] the filter description
- * @return {Deferred} resolved with the id of the created or replaced filter
+ * @return {Promise} resolved with the id of the created or replaced filter
*/
create_filter: function (filter) {
var self = this;
@@ -175,7 +175,7 @@ return core.Class.extend({
* Calls 'unlink' on 'ir_filters'.
*
* @param {integer} filterId Id of the filter to remove
- * @return {Deferred}
+ * @return {Promise}
*/
delete_filter: function (filterId) {
var self = this;
diff --git a/addons/web/static/src/js/services/report_service.js b/addons/web/static/src/js/services/report_service.js
index 006c546041a..ed4907a6d6d 100644
--- a/addons/web/static/src/js/services/report_service.js
+++ b/addons/web/static/src/js/services/report_service.js
@@ -15,7 +15,7 @@ var ReportService = AbstractService.extend({
* Checks the state of the installation of wkhtmltopdf on the server.
* Implements an internal cache to do the request only once.
*
- * @returns {Deferred} resolved with the state of wkhtmltopdf on the server
+ * @returns {Promise} resolved with the state of wkhtmltopdf on the server
* (possible values are 'ok', 'broken', 'install', 'upgrade', 'workers').
*/
checkWkhtmltopdf: function () {
diff --git a/addons/web/static/src/js/tools/debug_manager.js b/addons/web/static/src/js/tools/debug_manager.js
index f09d8745f04..172148e03ef 100644
--- a/addons/web/static/src/js/tools/debug_manager.js
+++ b/addons/web/static/src/js/tools/debug_manager.js
@@ -62,7 +62,7 @@ var DebugManager = Widget.extend({
this._has_features = false;
// whether the current user is an administrator
this._is_admin = session.is_system;
- return $.when(
+ return Promise.resolve(
this._rpc({
model: 'res.users',
method: 'check_access_rights',
@@ -160,7 +160,7 @@ var DebugManager = Widget.extend({
.append(QWeb.render('WebClient.DebugManager.Global', {
manager: this,
}));
- return $.when();
+ return Promise.resolve();
},
select_view: function () {
var self = this;
@@ -281,7 +281,7 @@ DebugManager.include({
model: 'ir.model',
method: 'search',
args: [[['model', '=', model]]]
- }).done(function (ids) {
+ }).then(function (ids) {
self.do_action({
res_model: 'ir.model.fields',
name: _t('View Fields'),
@@ -324,7 +324,7 @@ DebugManager.include({
DebugManager.include({
start: function () {
this._can_edit_views = false;
- return $.when(
+ return Promise.all([
this._super(),
this._rpc({
model: 'ir.ui.view',
@@ -334,6 +334,7 @@ DebugManager.include({
.then(function (ar) {
this._can_edit_views = ar;
}.bind(this))
+ ]
);
},
update: function (tag, descriptor, widget) {
@@ -382,7 +383,7 @@ DebugManager.include({
model: this._action.res_model,
method: 'get_metadata',
args: [selectedIDs],
- }).done(function(result) {
+ }).then(function(result) {
var metadata = result[0];
metadata.creator = field_utils.format.many2one(metadata.create_uid);
metadata.lastModifiedBy = field_utils.format.many2one(metadata.write_uid);
@@ -515,7 +516,7 @@ DebugManager.include({
true,
condition || false,
],
- }).done(function () { d.close(); });
+ }).then(function () { d.close(); });
}}
]
});
diff --git a/addons/web/static/src/js/tools/test_menus.js b/addons/web/static/src/js/tools/test_menus.js
index 4e31b2d4467..d950d5d56ee 100644
--- a/addons/web/static/src/js/tools/test_menus.js
+++ b/addons/web/static/src/js/tools/test_menus.js
@@ -65,16 +65,16 @@
}
console.log('Found ', $listOfAppMenuItems.length, 'apps to test');
- var testDef = $.when();
- testDef = chainDeferred($listOfAppMenuItems, testDef, testApp);
- return testDef.then(function() {
+ var testPromise = Promise.resolve();
+ testPromise = chainDeferred($listOfAppMenuItems, testPromise, testApp);
+ return testPromise.then(function () {
console.log("Successfully tested ", testedApps.length, " apps");
console.log("Successfully tested ", testedMenus.length - testedApps.length, " menus");
console.log("test successful");
- }).always(function() {
- console.log("Test took ", (performance.now() - startTime)/1000, " seconds");
- }).fail(function () {
- console.error("test failed");
+ console.log("Test took ", (performance.now() - startTime) / 1000, " seconds");
+ }).catch(function () {
+ console.log("Test took ", (performance.now() - startTime) / 1000, " seconds");
+ console.error("Error !");
});
}
@@ -86,18 +86,18 @@
* 3 - clicking on each menu
* 3.1 - clicking on each view
* @param {DomElement} element: the App menu item
- * @returns {Deferred}
+ * @returns {Promise}
*/
function testApp(element){
console.log("Testing app menu:", element.dataset.menuXmlid);
- if (testedApps.indexOf(element.dataset.menuXmlid) >= 0) return $.Deferred().resolve(); // Another infinite loop protection
+ if (testedApps.indexOf(element.dataset.menuXmlid) >= 0) return Promise.resolve(); // Another infinite loop protection
testedApps.push(element.dataset.menuXmlid);
return testMenuItem(element).then(function () {
var $subMenuItems;
$subMenuItems = $('.o_menu_entry_lvl_1, .o_menu_entry_lvl_2, .o_menu_entry_lvl_3, .o_menu_entry_lvl_4');
- var testMenuDef = $.when();
- testMenuDef = chainDeferred($subMenuItems, testMenuDef, testMenuItem);
- return testMenuDef;
+ var testMenuPromise = Promise.resolve();
+ testMenuPromise = chainDeferred($subMenuItems, testMenuPromise, testMenuItem);
+ return testMenuPromise;
}).then(function(){
// no effect in community
var $homeMenu = $("nav.o_main_navbar > a.o_menu_toggle.fa-th");
@@ -112,10 +112,10 @@
* 2 - Orchestrate the view switch
*
* @param {DomElement} element: the menu item
- * @returns {Deferred}
+ * @returns {Promise}
*/
function testMenuItem(element){
- if (testedMenus.indexOf(element.dataset.menuXmlid) >= 0) return $.Deferred().resolve(); // Avoid infinite loop
+ if (testedMenus.indexOf(element.dataset.menuXmlid) >= 0) return Promise.resolve(); // Avoid infinite loop
console.log("Testing menu", element.innerText.trim(), " ", element.dataset.menuXmlid);
testedMenus.push(element.dataset.menuXmlid);
var startActionCount = clientActionCount;
@@ -128,7 +128,7 @@
$modal.modal('hide');
isModal = true;
return true;
- };
+ }
return startActionCount != clientActionCount;
}).then(function() {
if (!isModal) {
@@ -138,7 +138,7 @@
if (!isModal) {
return testViews();
}
- }).fail(function() {
+ }).catch(function () {
console.error("Error while testing", element);
});
};
@@ -151,21 +151,21 @@
*/
function testViews() {
var $switches = $("nav.o_cp_switch_buttons > button:not(.active):visible");
- var testSwitchDef = $.when();
- // chainDeferred($switches, testSwitchDef, testViewSwitch # FIXME
+ var testSwitchPromise = Promise.resolve();
+ // chainDeferred($switches, testSwitchPromise, testViewSwitch # FIXME
_.each($switches, function(switchButton) {
- testSwitchDef = testSwitchDef.then(function () {
+ testSwitchPromise = testSwitchPromise.then(function () {
// get the view view-type data attribute
return testViewSwitch(switchButton.dataset.viewType);
});
});
- return testSwitchDef;
+ return testSwitchPromise;
}
/**
* Test a view button
* @param {string} viewType: a string for the view type to test (list, kanban ...)
- * @returns {Deferred} a deferred that wait for the view to be loaded
+ * @returns {Promise} a promise that wait for the view to be loaded
*/
function testViewSwitch(viewType){
console.log("Testing view switch: ", viewType);
@@ -188,20 +188,20 @@
* Click on each filter in the control pannel
*/
function testFilters() {
- var filterDef = $.when();
+ var filterProm = Promise.resolve();
// var $filters = $('div.o_control_panel div.btn-group.o_dropdown > ul.o_filters_menu > li:not(.o_add_custom_filter)');
var $filters = $('.o_filters_menu > .o_menu_item');
console.log("Testing " + $filters.length + " filters");
var filter_ids = _.compact(_.map($filters, function(f) { return f.dataset.id}));
_.each(filter_ids, function(filter_id){
- filterDef = filterDef.then(function(){
+ filterProm = filterProm.then(function(){
var currentViewCount = viewUpdateCount;
var $filter = $('.o_menu_item[data-id="' + filter_id + '"] a');
// with some customized search views, the filter cannot be found
if ($filter[0] === undefined) {
console.warn('Filter with ID ', filter_id , 'cannot be found');
- return $.Deferred().resolve();
- };
+ return Promise.resolve();
+ }
console.log('Clicking on filter "', $filter.text().trim(), '"');
$filter[0].click();
setTimeout(function() {
@@ -220,52 +220,55 @@
});
});
});
- return filterDef;
+ return filterProm;
}
// utility functions
/**
* Wait a certain amount of time for a condition to occur
- * @param stopCondition: a function that returns a boolean
- * @returns {Deferred} that is rejected if the timeout is exceeded
+ * @param {function} stopCondition a function that returns a boolean
+ * @returns {Promise} that is rejected if the timeout is exceeded
*/
function waitForCondition(stopCondition) {
- var def = $.Deferred();
- var interval = 250;
- var timeLimit = 15000;
- function checkCondition() {
- if (stopCondition()) {
- def.resolve();
- } else {
- timeLimit -= interval;
- if (timeLimit > 0) {
- // recursive call until the resolve or the timeout
- setTimeout(checkCondition, interval);
+ var prom = new Promise(function (resolve, reject) {
+ var interval = 250;
+ var timeLimit = 15000;
+
+ function checkCondition() {
+ if (stopCondition()) {
+ resolve();
} else {
- console.error("Timeout exceeded", stopCondition);
- def.reject();
+ timeLimit -= interval;
+ if (timeLimit > 0) {
+ // recursive call until the resolve or the timeout
+ setTimeout(checkCondition, interval);
+ } else {
+ console.error("Timeout exceeded", stopCondition);
+ reject();
+ }
}
}
- }
- setTimeout(checkCondition, interval);
- return def;
- };
+ setTimeout(checkCondition, interval);
+ });
+ return prom;
+ }
/**
- * chain deferred actions
- * @param $elements: a list of jquery elements to be passed as arg to the function
- * @param deferred: the deferred on which other deferreds will be chained
- * @param f: the function to be deferred
- * @returns : the chained deferred
+ * Chain deferred actions.
+ *
+ * @param {jQueryElement} $elements a list of jquery elements to be passed as arg to the function
+ * @param {Promise} promise the promise on which other promises will be chained
+ * @param {function} f the function to be deferred
+ * @returns {Promise} the chained promise
*/
- function chainDeferred($elements, deferred, f) {
+ function chainDeferred($elements, promise, f) {
_.each($elements, function(el) {
- deferred = deferred.then(function () {
+ promise = promise.then(function () {
return f(el);
});
});
- return deferred;
+ return promise;
}
diff --git a/addons/web/static/src/js/views/abstract_controller.js b/addons/web/static/src/js/views/abstract_controller.js
index b5d7c8fe8b3..0c251874480 100644
--- a/addons/web/static/src/js/views/abstract_controller.js
+++ b/addons/web/static/src/js/views/abstract_controller.js
@@ -62,7 +62,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
/**
* Simply renders and updates the url.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
var self = this;
@@ -70,12 +70,16 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
this.$el.addClass('o_view_controller');
return this._super.apply(this, arguments).then(function () {
+ var prom;
if (self._controlPanel) {
// render the ControlPanel elements (buttons, pager, sidebar...)
- self.controlPanelElements = self._renderControlPanelElements();
- self._controlPanel.$el.prependTo(self.$el);
+ prom = self._renderControlPanelElements().then(function (elements) {
+ self.controlPanelElements = elements;
+ self._controlPanel.$el.prependTo(self.$el);
+ });
}
-
+ return Promise.resolve(prom);
+ }).then(function () {
return self._update(self.initialState);
});
},
@@ -119,7 +123,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
*/
canBeRemoved: function () {
// AAB: get rid of this option when on_hashchange mechanism is improved
- return this.discardChanges(undefined, {readonlyIfRealDiscard: true});
+ return this.discardChanges(undefined, { readonlyIfRealDiscard: true });
},
/**
* Discards the changes made on the record associated to the given ID, or
@@ -128,15 +132,15 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* this method on the active view to make sure it is ok to open the home
* screen (and lose all current state).
*
- * Note that it returns a deferred, because the view could choose to ask the
+ * Note that it returns a Promise, because the view could choose to ask the
* user if he agrees to discard.
*
* @param {string} [recordID]
* if not given, we consider all the changes made by the controller
- * @returns {Deferred} resolved if properly discarded, rejected otherwise
+ * @returns {Promise} resolved if properly discarded, rejected otherwise
*/
discardChanges: function (recordID) {
- return $.when();
+ return Promise.resolve();
},
/**
* Export the state of the controller containing information that is shared
@@ -155,7 +159,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
/**
* Gives the focus to the renderer
*/
- giveFocus: function() {
+ giveFocus: function () {
this.renderer.giveFocus();
},
/**
@@ -174,7 +178,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* Short helper method to reload the view
*
* @param {Object} [params] This object will simply be given to the update
- * @returns {Deferred}
+ * @returns {Promise}
*/
reload: function (params) {
params = params || {};
@@ -186,7 +190,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
params = _.extend({}, params, searchQuery);
});
}
- return $.when(def).then(this.update.bind(this, params, {}));
+ return Promise.resolve(def).then(this.update.bind(this, params, {}));
},
/**
* For views that require a pager, this method will be called to allow the
@@ -195,16 +199,20 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* your view does not want a pager, just let this method empty.
*
* @param {jQuery Node} $node
+ * @return {Promise}
*/
renderPager: function ($node) {
+ return Promise.resolve();
},
/**
* Same as renderPager, but for the 'sidebar' zone (the zone with the menu
* dropdown in the control panel next to the buttons)
*
* @param {jQuery Node} $node
+ * @return {Promise}
*/
renderSidebar: function ($node) {
+ return Promise.resolve();
},
/**
* This is the main entry point for the controller. Changes from the search
@@ -219,12 +227,12 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* @param {Object} [options]
* @param {boolean} [options.reload=true] if true, the model will reload data
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
update: function (params, options) {
var self = this;
var shouldReload = (options && 'reload' in options) ? options.reload : true;
- var def = shouldReload ? this.model.reload(this.handle, params) : $.when();
+ var def = shouldReload ? this.model.reload(this.handle, params) : Promise.resolve();
// we check here that the updateIndex of the control panel hasn't changed
// between the start of the update request and the moment the controller
// asks the control panel to update itself ; indeed, it could happen that
@@ -285,17 +293,17 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
* return {'html': '<h1>hello, world</h1>'}
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderBanner: function () {
if (this.bannerRoute !== undefined) {
var self = this;
return this.dp
- .add(this._rpc({route: this.bannerRoute}))
+ .add(this._rpc({ route: this.bannerRoute }))
.then(function (response) {
if (!response.html) {
self.$el.removeClass('o_has_banner');
- return $.when();
+ return Promise.resolve();
}
self.$el.addClass('o_has_banner');
var $banner = $(response.html);
@@ -313,22 +321,24 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
defs.push(ajax.loadJS(js.src));
js.remove();
});
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
$banner.prependTo(self.$('> .o_content'));
self._$banner = $banner;
});
});
}
- return $.when();
+ return Promise.resolve();
},
/**
* Renders the control elements (buttons, pager and sidebar) of the current
* view.
*
* @private
- * @returns {Object} an object containing the control panel jQuery elements
+ * @returns {Promise<Object>} resolved with an object containing the control
+ * panel jQuery elements
*/
_renderControlPanelElements: function () {
+ var self = this;
var elements = {
$buttons: $('<div>'),
$sidebar: $('<div>'),
@@ -336,15 +346,18 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
};
this.renderButtons(elements.$buttons);
- this.renderSidebar(elements.$sidebar);
- this.renderPager(elements.$pager);
- // remove the unnecessary outer div
- elements = _.mapObject(elements, function($node) {
- return $node && $node.contents();
- });
- elements.$switch_buttons = this._renderSwitchButtons();
+ var sidebarProm = this.renderSidebar(elements.$sidebar);
+ var pagerProm = this.renderPager(elements.$pager);
- return elements;
+ return Promise.all([sidebarProm, pagerProm]).then(function () {
+ // remove the unnecessary outer div
+ elements = _.mapObject(elements, function ($node) {
+ return $node && $node.contents();
+ });
+ elements.$switch_buttons = self._renderSwitchButtons();
+
+ return elements;
+ });
},
/**
* Renders the switch buttons and binds listeners on them.
@@ -354,7 +367,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
*/
_renderSwitchButtons: function () {
var self = this;
- var views = _.filter(this.actionViews, {multiRecord: this.isMultiRecord});
+ var views = _.filter(this.actionViews, { multiRecord: this.isMultiRecord });
if (views.length <= 1) {
return $();
@@ -373,7 +386,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
var $switchButtonsFiltered = config.device.isMobile ? $switchButtons.find('button') : $switchButtons.filter('button');
$switchButtonsFiltered.click(_.debounce(function (event) {
var viewType = $(event.target).data('view-type');
- self.trigger_up('switch_view', {view_type: viewType});
+ self.trigger_up('switch_view', { view_type: viewType });
}, 200, true));
// set active view's icon as view switcher button's icon in mobile
@@ -402,7 +415,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
*
* @private
* @param {Object} state the state given by the model
- * @returns {Deferred}
+ * @returns {Promise}
*/
_update: function () {
// AAB: update the control panel -> this will be moved elsewhere at some point
@@ -524,7 +537,7 @@ var AbstractController = mvc.Controller.extend(ActionMixin, {
*/
_onOpenRecord: function (ev) {
ev.stopPropagation();
- var record = this.model.get(ev.data.id, {raw: true});
+ var record = this.model.get(ev.data.id, { raw: true });
this.trigger_up('switch_view', {
view_type: 'form',
res_id: record.res_id,
diff --git a/addons/web/static/src/js/views/abstract_model.js b/addons/web/static/src/js/views/abstract_model.js
index da73ac664a3..d18367b1756 100644
--- a/addons/web/static/src/js/views/abstract_model.js
+++ b/addons/web/static/src/js/views/abstract_model.js
@@ -31,7 +31,7 @@ var AbstractModel = mvc.Model.extend({
* @returns {Promise}
*/
reload: function (params) {
- return $.when();
+ return Promise.resolve();
},
/**
* Processes date(time) and selection field values sent by the server.
diff --git a/addons/web/static/src/js/views/abstract_renderer.js b/addons/web/static/src/js/views/abstract_renderer.js
index 0f18263c9ee..724b63bae79 100644
--- a/addons/web/static/src/js/views/abstract_renderer.js
+++ b/addons/web/static/src/js/views/abstract_renderer.js
@@ -23,14 +23,14 @@ return mvc.Renderer.extend({
this.noContentHelp = params.noContentHelp;
},
/**
- * The rendering can be asynchronous (but it is not encouraged). The start
+ * The rendering is asynchronous. The start
* method simply makes sure that we render the view.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this.$el.addClass(this.arch.attrs.class);
- return $.when(this._render(), this._super());
+ return Promise.all([this._render(), this._super()]);
},
/**
* Called each time the renderer is attached into the DOM.
@@ -86,11 +86,11 @@ return mvc.Renderer.extend({
* @param {Object} params
* @param {boolean} [params.noRender=false]
* if true, the method only updates the state without rerendering
- * @returns {Deferred}
+ * @returns {Promise}
*/
updateState: function (state, params) {
this.state = state;
- return params.noRender ? $.when() : this._render();
+ return params.noRender ? Promise.resolve() : this._render();
},
//--------------------------------------------------------------------------
@@ -102,10 +102,10 @@ return mvc.Renderer.extend({
*
* @abstract
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
- return $.when();
+ return Promise.resolve();
},
});
diff --git a/addons/web/static/src/js/views/abstract_view.js b/addons/web/static/src/js/views/abstract_view.js
index ce8951f6ee8..ba3c198bd21 100644
--- a/addons/web/static/src/js/views/abstract_view.js
+++ b/addons/web/static/src/js/views/abstract_view.js
@@ -194,11 +194,12 @@ var AbstractView = Factory.extend({
def = this._createControlPanel(parent);
}
var _super = this._super.bind(this);
- return $.when(def).then(function (controlPanel) {
+ return Promise.resolve(def).then(function (controlPanel) {
// get the parent of the model if it already exists, as _super will
// set the new controller as parent, which we don't want
var modelParent = self.model && self.model.getParent();
- return _super(parent).done(function (controller) {
+ var prom = _super(parent);
+ prom.then(function (controller) {
if (controlPanel) {
controlPanel.setParent(controller);
}
@@ -207,7 +208,7 @@ var AbstractView = Factory.extend({
self.model.setParent(modelParent);
}
});
-
+ return prom;
});
},
/**
diff --git a/addons/web/static/src/js/views/basic/basic_controller.js b/addons/web/static/src/js/views/basic/basic_controller.js
index 07646c83273..edfaba60b54 100644
--- a/addons/web/static/src/js/views/basic/basic_controller.js
+++ b/addons/web/static/src/js/views/basic/basic_controller.js
@@ -41,11 +41,11 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
// savingDef is used to ensure that we always wait for pending save
// operations to complete before checking if there are changes to
// discard when discardChanges is called
- this.savingDef = $.when();
+ this.savingDef = Promise.resolve();
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
// add classname to reflect the (absence of) access rights (used to
@@ -66,24 +66,27 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
*
* @override
* @param {string} [recordID] - default to main recordID
- * @returns {Deferred<boolean>}
+ * @returns {Promise<boolean>}
* resolved if can be discarded, a boolean value is given to tells
* if there is something to discard or not
* rejected otherwise
*/
canBeDiscarded: function (recordID) {
+ var self = this;
if (!this.isDirty(recordID)) {
- return $.when(false);
+ return Promise.resolve(false);
}
var message = _t("The record has been modified, your changes will be discarded. Do you want to proceed?");
- var def = $.Deferred();
- var dialog = Dialog.confirm(this, message, {
- title: _t("Warning"),
- confirm_callback: def.resolve.bind(def, true),
- cancel_callback: def.reject.bind(def),
+ var def;
+ def = new Promise(function (resolve, reject) {
+ var dialog = Dialog.confirm(self, message, {
+ title: _t("Warning"),
+ confirm_callback: resolve.bind(self, true),
+ cancel_callback: reject,
+ });
+ dialog.on('closed', def, reject);
});
- dialog.on('closed', def, def.reject);
return def;
},
/**
@@ -114,7 +117,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @see _.discardChanges
*/
discardChanges: function (recordID, options) {
- return $.when(this.mutex.getUnlockedDef(), this.savingDef)
+ return Promise.all([this.mutex.getUnlockedDef(), this.savingDef])
.then(this._discardChanges.bind(this, recordID || this.handle, options));
},
/**
@@ -144,6 +147,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @override
*/
renderPager: function ($node, options) {
+ var self = this;
var data = this.model.get(this.handle, {raw: true});
this.pager = new Pager(this, data.count, data.offset + 1, data.limit, options);
@@ -161,19 +165,21 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
})
.then(this.pager.enable.bind(this.pager));
});
- this.pager.appendTo($node);
- this._updatePager(); // to force proper visibility
+ return this.pager.appendTo($node).then(function() {
+ self._updatePager(); // to force proper visibility
+ });
},
/**
* Saves the record whose ID is given if necessary (@see _saveRecord).
*
* @param {string} [recordID] - default to main recordID
* @param {Object} [options]
- * @returns {Deferred}
+ * @returns {Promise}
* Resolved with the list of field names (whose value has been modified)
* Rejected if the record can't be saved
*/
saveRecord: function (recordID, options) {
+ var self = this;
// Some field widgets can't detect (all) their changes immediately or
// may have to validate them before notifying them, so we ask them to
// commit their current value before saving. This has to be done outside
@@ -187,23 +193,22 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
// user if some discarding has to be made). This operation must also be
// mutex-protected as commitChanges function of x2m has to be aware of
// all final changes made to a row.
- var self = this;
- var savingDef = $.Deferred();
- this.savingDef = savingDef;
-
- return this.mutex.getUnlockedDef()
+ var unlockedMutex = this.mutex.getUnlockedDef()
.then(function () {
return self.renderer.commitChanges(recordID || self.handle);
})
.then(function () {
return self.mutex.exec(self._saveRecord.bind(self, recordID, options));
- })
- .then(savingDef.resolve.bind(savingDef))
- .fail(savingDef.resolve.bind(savingDef));
+ });
+ this.savingDef = new Promise(function (resolve) {
+ unlockedMutex.then(resolve).guardedCatch(resolve);
+ });
+
+ return unlockedMutex;
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
update: function (params, options) {
var self = this;
@@ -267,31 +272,32 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @private
* @param {Object} attrs the attrs of the button clicked
* @param {Object} [record] the current state of the view
- * @returns {Deferred}
+ * @returns {Promise}
*/
_callButtonAction: function (attrs, record) {
var self = this;
- var def = $.Deferred();
- var reload = function () {
- return self.isDestroyed() ? $.when() : self.reload();
- };
- record = record || this.model.get(this.handle);
+ var def = new Promise(function (resolve, reject) {
+ var reload = function () {
+ return self.isDestroyed() ? Promise.resolve() : self.reload();
+ };
+ record = record || self.model.get(self.handle);
- this.trigger_up('execute_action', {
- action_data: _.extend({}, attrs, {
- context: record.getContext({additionalContext: attrs.context || {}}),
- }),
- env: {
- context: record.getContext(),
- currentID: record.data.id,
- model: record.model,
- resIDs: record.res_ids,
- },
- on_success: def.resolve.bind(def),
- on_fail: function () {
- self.update({}, {reload: false}).always(def.reject.bind(def));
- },
- on_closed: reload,
+ self.trigger_up('execute_action', {
+ action_data: _.extend({}, attrs, {
+ context: record.getContext({additionalContext: attrs.context || {}}),
+ }),
+ env: {
+ context: record.getContext(),
+ currentID: record.data.id,
+ model: record.model,
+ resIDs: record.res_ids,
+ },
+ on_success: resolve,
+ on_fail: function () {
+ self.update({}, {reload: false}).then(reject).guardedCatch(reject);
+ },
+ on_closed: reload,
+ });
});
return this.alive(def);
},
@@ -305,7 +311,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @param {string} id - the id of one of the view's records
* @param {string[]} fields - the changed fields
* @param {OdooEvent} e - the event that triggered the change
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmChange: function (id, fields, e) {
if (e.name === 'discard_changes' && e.target.reset) {
@@ -364,7 +370,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* the new record to be in edit mode too, but the view manager calls
* this function as the URL changes...) @todo get rid of this when
* the webclient/action_manager's hashchange mechanism is improved.
- * @returns {Deferred}
+ * @returns {Promise}
*/
_discardChanges: function (recordID, options) {
var self = this;
@@ -459,7 +465,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @param {boolean} [options.savePoint=false]
* if true, the record will only be 'locally' saved: its changes
* will move from the _changes key to the data key
- * @returns {Deferred}
+ * @returns {Promise}
* Resolved with the list of field names (whose value has been modified)
* Rejected if the record can't be saved
*/
@@ -490,7 +496,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
}
return saveDef;
} else {
- return $.Deferred().reject(); // Cannot be saved
+ return Promise.reject("SaveRecord: this.canBeSave is false"); // Cannot be saved
}
},
/**
@@ -501,7 +507,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
* @private
* @param {string} mode - 'readonly' or 'edit'
* @param {string} [recordID]
- * @returns {Deferred}
+ * @returns {Promise}
*/
_setMode: function (mode, recordID) {
if ((recordID || this.handle) === this.handle) {
@@ -511,7 +517,7 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
core.bus.trigger('DOM_updated');
});
}
- return $.when();
+ return Promise.resolve();
},
/**
* Helper method, to get the current environment variables from the model
@@ -564,14 +570,14 @@ var BasicController = AbstractController.extend(FieldManagerMixin, {
ev.stopPropagation();
var recordID = ev.data.recordID;
this._discardChanges(recordID)
- .done(function () {
+ .then(function () {
// TODO this will tell the renderer to rerender the widget that
// asked for the discard but will unfortunately lose the click
// made on another row if any
self._confirmChange(recordID, [ev.data.fieldName], ev)
- .always(ev.data.onSuccess);
+ .then(ev.data.onSuccess).guardedCatch(ev.data.onSuccess);
})
- .fail(ev.data.onFailure);
+ .guardedCatch(ev.data.onFailure);
},
/**
* Forces to save directly the changes if the controller is in readonly,
diff --git a/addons/web/static/src/js/views/basic/basic_model.js b/addons/web/static/src/js/views/basic/basic_model.js
index 4d86ef4293b..95b6d439ec1 100644
--- a/addons/web/static/src/js/views/basic/basic_model.js
+++ b/addons/web/static/src/js/views/basic/basic_model.js
@@ -173,7 +173,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} [options]
* @param {string} [options.position=top] if the new record should be added
* on top or on bottom of the list
- * @returns {Deferred<string>} resolves to the id of the new created record
+ * @returns {Promise<string>} resolves to the id of the new created record
*/
addDefaultRecord: function (listID, options) {
var self = this;
@@ -241,7 +241,7 @@ var BasicModel = AbstractModel.extend({
* assume main viewType from the record
* @param {Array} [options.fieldNames] list of field names for which a
* default value must be generated (used to complete the values dict)
- * @returns {Deferred}
+ * @returns {Promise}
*/
applyDefaultValues: function (recordID, values, options) {
options = options || {};
@@ -304,7 +304,7 @@ var BasicModel = AbstractModel.extend({
}
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Onchange RPCs may return values for fields that are not in the current
@@ -321,7 +321,7 @@ var BasicModel = AbstractModel.extend({
*
* @param {string} recordID local resource id of a record
* @param {string} viewType the current viewType
- * @returns {Deferred<string>} resolves to the id of the record
+ * @returns {Promise<string>} resolves to the id of the record
*/
applyRawChanges: function (recordID, viewType) {
var record = this.localData[recordID];
@@ -388,7 +388,7 @@ var BasicModel = AbstractModel.extend({
* @param {string[]} recordIds list of local resources ids. They should all
* be of type 'record', be of the same model and have the same parent.
* @param {string} modelName mode name used to unlink the records
- * @returns {Deferred}
+ * @returns {Promise}
*/
deleteRecords: function (recordIds, modelName) {
var self = this;
@@ -457,7 +457,7 @@ var BasicModel = AbstractModel.extend({
* Duplicate a record (by calling the 'copy' route)
*
* @param {string} recordID id for a local resource
- * @returns {Deferred<string>} resolves to the id of duplicate record
+ * @returns {Promise<string>} resolves to the id of duplicate record
*/
duplicateRecord: function (recordID) {
var self = this;
@@ -725,7 +725,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} params.fields contains the description of each field
* @param {string} [params.type] 'record' or 'list'
* @param {string} [params.recordID] an ID for an existing resource.
- * @returns {Deferred<string>} resolves to a local id, or handle
+ * @returns {Promise<string>} resolves to a local id, or handle
*/
load: function (params) {
params.type = params.type || (params.res_id !== undefined ? 'record' : 'list');
@@ -758,7 +758,7 @@ var BasicModel = AbstractModel.extend({
* @param {string} model name of the model
* @param {Object[]} fields a description of field properties
* @param {Object} [fieldInfo] various field info that we want to set
- * @returns {string} the local id for the created resource
+ * @returns {Promise<string>} the local id for the created resource
*/
makeRecord: function (model, fields, fieldInfo) {
var self = this;
@@ -849,7 +849,7 @@ var BasicModel = AbstractModel.extend({
record.data[field.name] = field.value;
}
});
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
return record.id;
});
},
@@ -863,7 +863,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} changes a map field => new value
* @param {Object} [options] will be transferred to the applyChange method
* @see _applyChange
- * @returns {string[]} list of changed fields
+ * @returns {Promise<string[]>} list of changed fields
*/
notifyChanges: function (record_id, changes, options) {
return this.mutex.exec(this._applyChange.bind(this, record_id, changes, options));
@@ -876,7 +876,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} [options]
* @param {boolean} [options.keepChanges=false] if true, doesn't discard the
* changes on the record before reloading it
- * @returns {Deferred<string>} resolves to the id of the resource
+ * @returns {Promise<string>} resolves to the id of the resource
*/
reload: function (id, options) {
return this.mutex.exec(this._reload.bind(this, id, options));
@@ -925,12 +925,12 @@ var BasicModel = AbstractModel.extend({
* @param {object} [options]
* @param {integer} [options.offset]
* @param {string} [options.field] the field name used as sequence
- * @returns {Deferred<string>} resolves to the local id of the parent
+ * @returns {Promise<string>} resolves to the local id of the parent
*/
resequence: function (modelName, resIDs, parentID, options) {
options = options || {};
if ((resIDs.length <= 1)) {
- return $.when(parentID); // there is nothing to sort
+ return Promise.resolve(parentID); // there is nothing to sort
}
var self = this;
var data = this.localData[parentID];
@@ -952,7 +952,7 @@ var BasicModel = AbstractModel.extend({
if (!wasResequenced) {
// the field on which the resequence was triggered does not
// exist, so no resequence happened server-side
- return $.when();
+ return Promise.resolve();
}
var field = params.field ? params.field : 'sequence';
@@ -1010,7 +1010,7 @@ var BasicModel = AbstractModel.extend({
* be restored later by call discardChanges with option rollback to true
* @param {string} [options.viewType] current viewType. If not set, we will
* assume main viewType from the record
- * @returns {Deferred}
+ * @returns {Promise}
* Resolved with the list of field names (whose value has been modified)
*/
save: function (recordID, options) {
@@ -1054,57 +1054,59 @@ var BasicModel = AbstractModel.extend({
});
}
- var def = $.Deferred();
- var changedFields = Object.keys(changes);
+ var prom = new Promise(function (resolve, reject) {
+ var changedFields = Object.keys(changes);
- if (options.savePoint) {
- return def.resolve(changedFields);
- }
+ if (options.savePoint) {
+ resolve(changedFields);
+ return;
+ }
- def.then(function () {
- record._isDirty = false;
- });
- // in the case of a write, only perform the RPC if there are changes to save
- if (method === 'create' || changedFields.length) {
- var args = method === 'write' ? [[record.data.id], changes] : [changes];
- self._rpc({
- model: record.model,
- method: method,
- args: args,
- context: record.getContext(),
- }).then(function (id) {
- if (method === 'create') {
- record.res_id = id; // create returns an id, write returns a boolean
- record.data.id = id;
- record.offset = record.res_ids.length;
- record.res_ids.push(id);
- record.count++;
- }
+ // in the case of a write, only perform the RPC if there are changes to save
+ if (method === 'create' || changedFields.length) {
+ var args = method === 'write' ? [[record.data.id], changes] : [changes];
+ self._rpc({
+ model: record.model,
+ method: method,
+ args: args,
+ context: record.getContext(),
+ }).then(function (id) {
+ if (method === 'create') {
+ record.res_id = id; // create returns an id, write returns a boolean
+ record.data.id = id;
+ record.offset = record.res_ids.length;
+ record.res_ids.push(id);
+ record.count++;
+ }
- var _changes = record._changes;
+ var _changes = record._changes;
- // Erase changes as they have been applied
- record._changes = {};
+ // Erase changes as they have been applied
+ record._changes = {};
- // Optionally clear the DataManager's cache
- self._invalidateCache(record);
+ // Optionally clear the DataManager's cache
+ self._invalidateCache(record);
- self.unfreezeOrder(record.id);
+ self.unfreezeOrder(record.id);
- // Update the data directly or reload them
- if (shouldReload) {
- self._fetchRecord(record).then(function () {
- def.resolve(changedFields);
- });
- } else {
- _.extend(record.data, _changes);
- def.resolve(changedFields);
- }
- }).fail(def.reject.bind(def));
- } else {
- def.resolve(changedFields);
- }
- return def;
+ // Update the data directly or reload them
+ if (shouldReload) {
+ self._fetchRecord(record).then(function () {
+ resolve(changedFields);
+ });
+ } else {
+ _.extend(record.data, _changes);
+ resolve(changedFields);
+ }
+ }).guardedCatch(reject);
+ } else {
+ resolve(changedFields);
+ }
+ });
+ prom.then(function () {
+ record._isDirty = false;
+ });
+ return prom;
});
},
/**
@@ -1123,7 +1125,7 @@ var BasicModel = AbstractModel.extend({
*
* @param {string} list_id id for the list resource
* @param {string} fieldName valid field name
- * @returns {Deferred}
+ * @returns {Promise}
*/
setSort: function (list_id, fieldName) {
var list = this.localData[list_id];
@@ -1153,7 +1155,7 @@ var BasicModel = AbstractModel.extend({
// sort field is still unknown (i.e. on other pages for example)
return this._fetchUngroupedList(list);
}
- return $.when();
+ return Promise.resolve();
},
/**
* Toggle the active value of given records (to archive/unarchive them)
@@ -1161,7 +1163,7 @@ var BasicModel = AbstractModel.extend({
* @param {Array} recordIDs local ids of the records to (un)archive
* @param {boolean} value false to archive, true to unarchive (value of the active field)
* @param {string} parentID id of the parent resource to reload
- * @returns {Deferred<string>} resolves to the parent id
+ * @returns {Promise<string>} resolves to the parent id
*/
toggleActive: function (recordIDs, value, parentID) {
var self = this;
@@ -1185,7 +1187,7 @@ var BasicModel = AbstractModel.extend({
* data
*
* @param {string} groupId
- * @returns {Deferred<string>} resolves to the group id
+ * @returns {Promise<string>} resolves to the group id
*/
toggleGroup: function (groupId) {
var self = this;
@@ -1196,7 +1198,7 @@ var BasicModel = AbstractModel.extend({
group.res_ids = [];
group.offset = 0;
this._updateParentResIDs(group);
- return $.when(groupId);
+ return Promise.resolve(groupId);
}
if (!group.isOpen) {
group.isOpen = true;
@@ -1206,7 +1208,7 @@ var BasicModel = AbstractModel.extend({
self._updateParentResIDs(group);
});
}
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
return groupId;
});
}
@@ -1260,7 +1262,7 @@ var BasicModel = AbstractModel.extend({
* If several contexts are found, multiple records are added
* @param {boolean} [options.allowWarning=false] if true, the default record
* operation can complete, even if a warning is raised
- * @returns {Deferred<[string]>} resolves to the new records ids
+ * @returns {Promise<[string]>} resolves to the new records ids
*/
_addX2ManyDefaultRecord: function (list, options) {
var self = this;
@@ -1286,9 +1288,9 @@ var BasicModel = AbstractModel.extend({
makeDefaultRecords.push(self._makeDefaultRecord(list.model, params));
}
- return $.when.apply($, makeDefaultRecords).then(function (){
+ return Promise.all(makeDefaultRecords).then(function (resultIds){
var ids = [];
- _.each(arguments, function (id){
+ _.each(resultIds, function (id){
ids.push(id);
list._changes.push({operation: 'ADD', id: id, position: position, isNew: true});
@@ -1324,7 +1326,7 @@ var BasicModel = AbstractModel.extend({
* @param {boolean} [options.allowWarning=false] if true, change
* operation can complete, even if a warning is raised
* (only supported by X2ManyChange)
- * @returns {Deferred} list of changed fields
+ * @returns {Promise} list of changed fields
*/
_applyChange: function (recordID, changes, options) {
var self = this;
@@ -1354,10 +1356,10 @@ var BasicModel = AbstractModel.extend({
}
if (options.notifyChange === false) {
- return $.Deferred().resolve(_.keys(changes));
+ return Promise.resolve(_.keys(changes));
}
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
var onChangeFields = []; // the fields that have changed and that have an on_change
for (var fieldName in changes) {
field = record.fields[fieldName];
@@ -1368,22 +1370,22 @@ var BasicModel = AbstractModel.extend({
}
}
}
- var onchangeDef = $.Deferred();
- if (onChangeFields.length) {
- self._performOnChange(record, onChangeFields, options.viewType)
+ return new Promise(function (resolve, reject) {
+ if (onChangeFields.length) {
+ self._performOnChange(record, onChangeFields, options.viewType)
.then(function (result) {
delete record._warning;
- onchangeDef.resolve(_.keys(changes).concat(Object.keys(result && result.value || {})));
- }).fail(function () {
+ resolve(_.keys(changes).concat(Object.keys(result && result.value || {})));
+ }).guardedCatch(function () {
self._visitChildren(record, function (elem) {
_.extend(elem, initialData[elem.id]);
});
- onchangeDef.resolve({});
+ resolve({});
});
- } else {
- onchangeDef = $.Deferred().resolve(_.keys(changes));
- }
- return onchangeDef.then(function (fieldNames) {
+ } else {
+ resolve(_.keys(changes));
+ }
+ }).then(function (fieldNames) {
_.each(fieldNames, function (name) {
if (record._changes && record._changes[name] === record.data[name]) {
delete record._changes[name];
@@ -1407,13 +1409,13 @@ var BasicModel = AbstractModel.extend({
* @param {Object} record
* @param {string} fieldName
* @param {Object} [data]
- * @returns {Deferred}
+ * @returns {Promise}
*/
_applyX2OneChange: function (record, fieldName, data) {
var self = this;
if (!data || !data.id) {
record._changes[fieldName] = false;
- return $.when();
+ return Promise.resolve();
}
// here, we check that the many2one really changed. If the res_id is the
@@ -1429,7 +1431,7 @@ var BasicModel = AbstractModel.extend({
}
var relatedRecord = this.localData[relatedID];
if (relatedRecord && (data.id === this.localData[relatedID].res_id)) {
- return $.when();
+ return Promise.resolve();
}
var rel_data = _.pick(data, 'id', 'display_name');
var field = record.fields[fieldName];
@@ -1450,7 +1452,7 @@ var BasicModel = AbstractModel.extend({
rel_data.display_name = result[0][1];
});
}
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
var rec = self._makeDataPoint({
context: record.context,
data: rel_data,
@@ -1471,7 +1473,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} record
* @param {string} [viewType] current viewType. If not set, we will assume
* main viewType from the record
- * @returns {Deferred}
+ * @returns {Promise}
*/
_applyOnChange: function (values, record, viewType) {
var self = this;
@@ -1634,7 +1636,7 @@ var BasicModel = AbstractModel.extend({
var def = self._readUngroupedList(list).then(function () {
var x2ManysDef = self._fetchX2ManysBatched(list);
var referencesDef = self._fetchReferencesBatched(list);
- return $.when(x2ManysDef, referencesDef);
+ return Promise.all([x2ManysDef, referencesDef]);
});
defs.push(def);
} else {
@@ -1644,7 +1646,7 @@ var BasicModel = AbstractModel.extend({
}
}
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
// inner function that adds a record (based on its res_id) to a list
// dataPoint (used for onchanges that return commands 4 (LINK TO) or
@@ -1680,7 +1682,7 @@ var BasicModel = AbstractModel.extend({
* @param {boolean} [allowWarning=false] if true, change
* operation can complete, even if a warning is raised
* (only supported by the 'CREATE' command.operation)
- * @returns {Deferred}
+ * @returns {Promise}
*/
_applyX2ManyChange: function (record, fieldName, command, viewType, allowWarning) {
if (command.operation === 'TRIGGER_ONCHANGE') {
@@ -1688,7 +1690,7 @@ var BasicModel = AbstractModel.extend({
// there is no need to apply any change on the record (the changes
// have probably been already applied and saved, usecase: many2many
// edition in a dialog)
- return $.when();
+ return Promise.resolve();
}
var self = this;
@@ -1765,10 +1767,10 @@ var BasicModel = AbstractModel.extend({
list_records[record.id].data = record;
self._parseServerData(fieldNames, list, record);
});
- return $.when(
+ return Promise.all([
self._fetchX2ManysBatched(list),
self._fetchReferencesBatched(list)
- );
+ ]);
});
defs.push(def);
}
@@ -1850,10 +1852,10 @@ var BasicModel = AbstractModel.extend({
}),
}, viewType);
}
- return $.when(addDef, removedDef);
+ return Promise.all([addDef, removedDef]);
}
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
// ensure to fetch up to 'limit' records (may be useful if records of
// the current page have been removed)
return self._readUngroupedList(list).then(function () {
@@ -2103,7 +2105,7 @@ var BasicModel = AbstractModel.extend({
* Fetch all name_gets for the many2ones in a group
*
* @param {Object[]} groups a list of object with context and record sub keys
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchMany2OneGroup: function (groups) {
var ids = _.uniq(_.pluck(_.pluck(groups, 'record'), 'res_id'));
@@ -2124,7 +2126,7 @@ var BasicModel = AbstractModel.extend({
* Fetch name_get for a record datapoint.
*
* @param {Object} dataPoint
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchNameGet: function (dataPoint) {
return this._rpc({
@@ -2143,7 +2145,7 @@ var BasicModel = AbstractModel.extend({
* @params {Object} list: must be a datapoint of type list
* (for example: a datapoint representing a x2many)
* @params {string} fieldName: the name of a field of type Many2one or Reference
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchNameGets: function (list, fieldName) {
var self = this;
@@ -2168,7 +2170,7 @@ var BasicModel = AbstractModel.extend({
});
if (!ids.length) {
- return $.when();
+ return Promise.resolve();
}
return this._rpc({
model: model,
@@ -2195,7 +2197,7 @@ var BasicModel = AbstractModel.extend({
* @param {string} [options.viewType] the type of view for which the record
* is fetched (usefull to load the adequate fields), by defaults, uses
* record.viewType
- * @returns {Deferred<Object>} resolves to the record or is rejected in
+ * @returns {Promise<Object>} resolves to the record or is rejected in
* case no id given were valid ids
*/
_fetchRecord: function (record, options) {
@@ -2211,7 +2213,7 @@ var BasicModel = AbstractModel.extend({
})
.then(function (result) {
if (result.length === 0) {
- return $.Deferred().reject();
+ return Promise.reject();
}
result = result[0];
record.data = _.extend({}, record.data, result);
@@ -2220,10 +2222,10 @@ var BasicModel = AbstractModel.extend({
self._parseServerData(fieldNames, record, record.data);
})
.then(function () {
- return $.when(
+ return Promise.all([
self._fetchX2Manys(record, options),
self._fetchReferences(record, options)
- ).then(function () {
+ ]).then(function () {
return self._postprocess(record, options);
});
});
@@ -2234,7 +2236,7 @@ var BasicModel = AbstractModel.extend({
* @private
* @param {Object} record
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReference: function (record, fieldName) {
var self = this;
@@ -2259,7 +2261,7 @@ var BasicModel = AbstractModel.extend({
});
});
}
- return $.when(def);
+ return Promise.resolve(def);
},
/**
* Fetches data for reference fields and assigns these data to newly
@@ -2270,7 +2272,7 @@ var BasicModel = AbstractModel.extend({
* @see _getDataToFetchByModel
* @param {string} model
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReferenceData: function (datapoints, model, fieldName) {
var self = this;
@@ -2307,7 +2309,7 @@ var BasicModel = AbstractModel.extend({
*
* @private
* @param {Object} record
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReferences: function (record, options) {
var self = this;
@@ -2324,7 +2326,7 @@ var BasicModel = AbstractModel.extend({
defs.push(def);
}
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Batch requests for one reference field in list (one request by different
@@ -2333,7 +2335,7 @@ var BasicModel = AbstractModel.extend({
* @see _fetchReferencesBatched
* @param {Object} list
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReferenceBatched: function (list, fieldName) {
var self = this;
@@ -2347,13 +2349,13 @@ var BasicModel = AbstractModel.extend({
defs.push(self._fetchReferenceData(datapoints, model, fieldName));
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Batch requests for references for datapoint of type list.
*
* @param {Object} list
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReferencesBatched: function (list) {
var defs = [];
@@ -2364,7 +2366,7 @@ var BasicModel = AbstractModel.extend({
defs.push(this._fetchReferenceBatched(list, fieldNames[i]));
}
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Batch reference requests for all records in list.
@@ -2372,7 +2374,7 @@ var BasicModel = AbstractModel.extend({
* @see _fetchReferencesSingleBatch
* @param {Object} list a valid resource object
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReferenceSingleBatch: function (list, fieldName) {
var self = this;
@@ -2390,14 +2392,14 @@ var BasicModel = AbstractModel.extend({
defs.push(self._fetchReferenceData(datapoints, model, fieldName));
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Batch requests for all reference field in list's children.
* Called by _readGroup to make only one 'name_get' rpc by fieldName.
*
* @param {Object} list a valid resource object
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchReferencesSingleBatch: function (list) {
var defs = [];
@@ -2408,7 +2410,7 @@ var BasicModel = AbstractModel.extend({
defs.push(this._fetchReferenceSingleBatch(list, fieldNames[fIndex]));
}
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Fetch model data from server, relationally to fieldName and resulted
@@ -2420,7 +2422,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} toFetch a list of records and res_ids,
* @see _getDataToFetch
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchRelatedData: function (list, toFetch, fieldName) {
var self = this;
@@ -2431,7 +2433,7 @@ var BasicModel = AbstractModel.extend({
var fieldInfo = list.fieldsInfo[list.viewType][fieldName];
if (!ids.length || fieldInfo.__no_fetch) {
- return $.when();
+ return Promise.resolve();
}
var def;
@@ -2445,7 +2447,7 @@ var BasicModel = AbstractModel.extend({
context: list.getContext() || {},
});
} else {
- def = $.when(_.map(ids, function (id) {
+ def = Promise.resolve(_.map(ids, function (id) {
return {id:id};
}));
}
@@ -2465,10 +2467,10 @@ var BasicModel = AbstractModel.extend({
* This method is currently only called by _makeDefaultRecord, it should be
* called by the onchange methods at some point.
*
- * @todo fix bug: returns a list of deferred, not a deferred
+ * @todo fix bug: returns a list of promise, not a promise
*
* @param {Object} record a valid resource object
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchRelationalData: function (record) {
var self = this;
@@ -2496,7 +2498,7 @@ var BasicModel = AbstractModel.extend({
return [elem.record.model, JSON.stringify(elem.context)].join();
});
- return $.when.apply($, _.map(groups, this._fetchMany2OneGroup.bind(this)));
+ return Promise.all(_.map(groups, this._fetchMany2OneGroup.bind(this)));
},
/**
* Check the AbstractField specializations that are (will be) used by the
@@ -2507,15 +2509,15 @@ var BasicModel = AbstractModel.extend({
*
* @param {Object} record - an element from the localData
* @param {Object} options
- * @returns {Deferred<Array>}
- * The deferred is resolved with an array containing the names of
+ * @returns {Promise<Array>}
+ * The promise is resolved with an array containing the names of
* the field whose special data has been changed.
*/
_fetchSpecialData: function (record, options) {
var self = this;
var specialFieldNames = [];
var fieldNames = (options && options.fieldNames) || record.getFieldNames();
- return $.when.apply($, _.map(fieldNames, function (name) {
+ return Promise.all(_.map(fieldNames, function (name) {
var viewType = (options && options.viewType) || record.viewType;
var fieldInfo = record.fieldsInfo[viewType][name] || {};
var Widget = fieldInfo.Widget;
@@ -2541,16 +2543,16 @@ var BasicModel = AbstractModel.extend({
* @param {Object} fieldInfo
* @param {string[]} [fieldsToRead] - the m2os fields to read (id and
* display_name are automatic).
- * @returns {Deferred<any>}
- * The deferred is resolved with the fetched special data. If this
+ * @returns {Promise<any>}
+ * The promise is resolved with the fetched special data. If this
* data is the same as the previously fetched one (for the given
- * parameters), no RPC is done and the deferred is resolved with
+ * parameters), no RPC is done and the promise is resolved with
* the undefined value.
*/
_fetchSpecialMany2ones: function (record, fieldName, fieldInfo, fieldsToRead) {
var field = record.fields[fieldName];
if (field.type !== "many2one") {
- return $.when();
+ return Promise.resolve();
}
var context = record.getContext({fieldName: fieldName});
@@ -2571,7 +2573,7 @@ var BasicModel = AbstractModel.extend({
domain: domain,
});
if (!hasChanged) {
- return $.when();
+ return Promise.resolve();
}
var self = this;
@@ -2607,16 +2609,16 @@ var BasicModel = AbstractModel.extend({
*
* @param {Object} record - an element from the localData
* @param {Object} fieldName - the name of the field
- * @returns {Deferred<any>}
- * The deferred is resolved with the fetched special data. If this
+ * @returns {Promise<any>}
+ * The promise is resolved with the fetched special data. If this
* data is the same as the previously fetched one (for the given
- * parameters), no RPC is done and the deferred is resolved with
+ * parameters), no RPC is done and the promise is resolved with
* the undefined value.
*/
_fetchSpecialRelation: function (record, fieldName) {
var field = record.fields[fieldName];
if (!_.contains(["many2one", "many2many", "one2many"], field.type)) {
- return $.when();
+ return Promise.resolve();
}
var context = record.getContext({fieldName: fieldName});
@@ -2628,7 +2630,7 @@ var BasicModel = AbstractModel.extend({
domain: domain,
});
if (!hasChanged) {
- return $.when();
+ return Promise.resolve();
}
return this._rpc({
@@ -2645,7 +2647,7 @@ var BasicModel = AbstractModel.extend({
* @private
* @param {Object} record - an element from the localData
* @param {Object} fieldName - the name of the field
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchSpecialReference: function (record, fieldName) {
var def;
@@ -2655,7 +2657,7 @@ var BasicModel = AbstractModel.extend({
// needs to be fetched a posteriori
def = this._fetchReference(record, fieldName);
}
- return $.when(def);
+ return Promise.resolve(def);
},
/**
* Fetches all the m2o records associated to the given fieldName. If the
@@ -2666,10 +2668,10 @@ var BasicModel = AbstractModel.extend({
* @param {Object} record - an element from the localData
* @param {Object} fieldName - the name of the field
* @param {Object} fieldInfo
- * @returns {Deferred<any>}
- * The deferred is resolved with the fetched special data. If this
+ * @returns {Promise<any>}
+ * The promise is resolved with the fetched special data. If this
* data is the same as the previously fetched one (for the given
- * parameters), no RPC is done and the deferred is resolved with
+ * parameters), no RPC is done and the promise is resolved with
* the undefined value.
*/
_fetchSpecialStatus: function (record, fieldName, fieldInfo) {
@@ -2689,13 +2691,14 @@ var BasicModel = AbstractModel.extend({
* @param {Object} record - an element from the localData
* @param {Object} fieldName - the name of the field
* @param {Object} fieldInfo
- * @returns {Deferred<any>}
- * The deferred is resolved with the fetched special data. If this
+ * @returns {Promise<any>}
+ * The promise is resolved with the fetched special data. If this
* data is the same as the previously fetched one (for the given
- * parameters), no RPC is done and the deferred is resolved with
+ * parameters), no RPC is done and the promise is resolved with
* the undefined value.
*/
_fetchSpecialDomain: function (record, fieldName, fieldInfo) {
+ var self = this;
var context = record.getContext({fieldName: fieldName});
var domainModel = fieldInfo.options.model;
@@ -2711,34 +2714,37 @@ var BasicModel = AbstractModel.extend({
domainValue: domainValue,
});
if (!hasChanged) {
- return $.when();
+ return Promise.resolve();
} else if (!domainModel) {
- return $.when({
+ return Promise.resolve({
model: domainModel,
nbRecords: 0,
});
}
- var def = $.Deferred();
- var evalContext = this._getEvalContext(record);
- this._rpc({
+ return new Promise(function (resolve) {
+ var evalContext = self._getEvalContext(record);
+ self._rpc({
model: domainModel,
method: 'search_count',
args: [Domain.prototype.stringToArray(domainValue, evalContext)],
context: context
})
- .then(_.identity, function (error, e) {
- e.preventDefault(); // prevent traceback (the search_count might be intended to break)
- return false;
- })
- .always(function (nbRecords) {
- def.resolve({
+ .then(function (nbRecords) {
+ resolve({
model: domainModel,
nbRecords: nbRecords,
});
+ })
+ .guardedCatch(function (reason) {
+ var e = reason.event;
+ e.preventDefault(); // prevent traceback (the search_count might be intended to break)
+ resolve({
+ model: domainModel,
+ nbRecords: 0,
+ });
});
-
- return def;
+ });
},
/**
* Fetch all data in a ungrouped list
@@ -2748,7 +2754,7 @@ var BasicModel = AbstractModel.extend({
* @param {boolean} [options.enableRelationalFetch=true] if false, will not
* fetch x2m and relational data (that will be done by _readGroup in this
* case).
- * @returns {Deferred<Object>} resolves to the fetched list
+ * @returns {Promise<Object>} resolves to the fecthed list
*/
_fetchUngroupedList: function (list, options) {
options = _.defaults(options || {}, {enableRelationalFetch: true});
@@ -2762,7 +2768,7 @@ var BasicModel = AbstractModel.extend({
var defs = _.map(many2ones, function (name) {
return self._fetchNameGets(list, name);
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
}
});
} else {
@@ -2770,10 +2776,10 @@ var BasicModel = AbstractModel.extend({
}
return def.then(function () {
if (options.enableRelationalFetch) {
- return $.when(
- self._fetchX2ManysBatched(list, options),
- self._fetchReferencesBatched(list, options)
- );
+ return Promise.all([
+ self._fetchX2ManysBatched(list),
+ self._fetchReferencesBatched(list)
+ ]);
}
}).then(function () {
return list;
@@ -2785,7 +2791,7 @@ var BasicModel = AbstractModel.extend({
* @see _fetchX2ManysBatched
* @param {Object} list
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchX2ManyBatched: function (list, fieldName) {
list = this._applyX2ManyOperations(list);
@@ -2810,7 +2816,7 @@ var BasicModel = AbstractModel.extend({
* @param {string} [options.viewType] the type of view for which the main
* record is fetched (useful to load the adequate fields), by defaults,
* uses record.viewType
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchX2Manys: function (record, options) {
var self = this;
@@ -2845,22 +2851,22 @@ var BasicModel = AbstractModel.extend({
record.data[fieldName] = list.id;
if (!fieldInfo.__no_fetch) {
var def = self._readUngroupedList(list).then(function () {
- return $.when(
+ return Promise.all([
self._fetchX2ManysBatched(list),
self._fetchReferencesBatched(list)
- );
+ ]);
});
defs.push(def);
}
}
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* batch request for x2ms for datapoint of type list
*
* @param {Object} list
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchX2ManysBatched: function (list) {
var defs = [];
@@ -2871,7 +2877,7 @@ var BasicModel = AbstractModel.extend({
defs.push(this._fetchX2ManyBatched(list, fieldNames[i]));
}
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* For a non-static list, batches requests for all its sublists' records.
@@ -2881,7 +2887,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} list a valid resource object, its data must be another
* list containing records
* @param {string} fieldName
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchX2ManySingleBatch: function (list, fieldName) {
var self = this;
@@ -2904,7 +2910,7 @@ var BasicModel = AbstractModel.extend({
* Called by _readGroup to make only one 'read' rpc by fieldName.
*
* @param {Object} list a valid resource object
- * @returns {Deferred}
+ * @returns {Promise}
*/
_fetchX2ManysSingleBatch: function (list) {
var defs = [];
@@ -2915,7 +2921,7 @@ var BasicModel = AbstractModel.extend({
defs.push(this._fetchX2ManySingleBatch(list, fieldNames[i]));
}
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Generates an object mapping field names to their changed value in a given
@@ -3584,12 +3590,12 @@ var BasicModel = AbstractModel.extend({
* @param {boolean} [options.keepEmptyGroups=false] if set, the groups not
* present in the read_group anymore (empty groups) will stay in the
* datapoint (used to mimic the kanban renderer behaviour for example)
- * @returns {Deferred}
+ * @returns {Promise}
*/
_load: function (dataPoint, options) {
if (options && options.onlyGroups &&
!(dataPoint.type === 'list' && dataPoint.groupedBy.length)) {
- return $.when(dataPoint);
+ return Promise.resolve(dataPoint);
}
if (dataPoint.type === 'record') {
@@ -3733,7 +3739,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} params.fields contains the description of each field
* @param {Object} params.context the context for the new record
* @param {string} params.viewType the key in fieldsInfo of the fields to load
- * @returns {Deferred<string>} resolves to the id for the created resource
+ * @returns {Promise<string>} resolves to the id for the created resource
*/
_makeDefaultRecord: function (modelName, params) {
var self = this;
@@ -3787,16 +3793,19 @@ var BasicModel = AbstractModel.extend({
return self.applyDefaultValues(record.id, result, {fieldNames: fieldNames})
.then(function () {
- var def = $.Deferred();
- self._performOnChange(record, fields_key).always(function () {
- if (record._warning) {
- if (params.allowWarning) {
- delete record._warning;
- } else {
- def.reject();
+ var def = new Promise(function (resolve, reject) {
+ var always = function () {
+ if (record._warning) {
+ if (params.allowWarning) {
+ delete record._warning;
+ } else {
+ reject();
+ }
}
- }
- def.resolve();
+ resolve();
+ };
+ self._performOnChange(record, fields_key)
+ .then(always).guardedCatch(always);
});
return def;
})
@@ -3865,13 +3874,13 @@ var BasicModel = AbstractModel.extend({
* @param {string[]} fields changed fields
* @param {string} [viewType] current viewType. If not set, we will assume
* main viewType from the record
- * @returns {Deferred}
+ * @returns {Promise}
*/
_performOnChange: function (record, fields, viewType) {
var self = this;
var onchangeSpec = this._buildOnchangeSpecs(record, viewType);
if (!onchangeSpec) {
- return $.when();
+ return Promise.resolve();
}
var idList = record.data.id ? [record.data.id] : [];
var options = {
@@ -3925,7 +3934,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} [options]
* @param {Object} [options.viewType] current viewType. If not set, we will
* assume main viewType from the record
- * @returns {Deferred<Object>} resolves to the finished resource
+ * @returns {Promise<Object>} resolves to the finished resource
*/
_postprocess: function (record, options) {
var self = this;
@@ -3954,7 +3963,7 @@ var BasicModel = AbstractModel.extend({
defs.push(this._fetchSpecialData(record, options));
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
return record;
});
},
@@ -3975,7 +3984,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} [options]
* @param {string} [options.viewType] current viewType. If not set, we will
* assume main viewType from the record
- * @returns {Deferred}
+ * @returns {Promise}
*/
_processX2ManyCommands: function (record, fieldName, commands, options) {
var self = this;
@@ -4076,10 +4085,10 @@ var BasicModel = AbstractModel.extend({
x2manyList._changes.push({operation: 'ADD', resID: res_id});
});
var def = self._readUngroupedList(x2manyList).then(function () {
- return $.when(
+ return Promise.all([
self._fetchX2ManysBatched(x2manyList),
self._fetchReferencesBatched(x2manyList)
- );
+ ]);
});
defs.push(def);
}
@@ -4090,7 +4099,7 @@ var BasicModel = AbstractModel.extend({
defs.push(self._fetchNameGets(x2manyList, name));
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Reads data from server for all missing fields.
@@ -4099,7 +4108,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} list a valid resource object
* @param {interger[]} resIDs
* @param {string[]} fieldNames to check and read if missing
- * @returns {Deferred<Object>}
+ * @returns {Promise<Object>}
*/
_readMissingFields: function (list, resIDs, fieldNames) {
var self = this;
@@ -4128,7 +4137,7 @@ var BasicModel = AbstractModel.extend({
context: list.getContext(),
});
} else {
- def = $.when(_.map(missingIDs, function (id) {
+ def = Promise.resolve(_.map(missingIDs, function (id) {
return {id:id};
}));
}
@@ -4174,7 +4183,7 @@ var BasicModel = AbstractModel.extend({
*
* @param {Object} list valid resource object
* @param {Object} [options] @see _load
- * @returns {Deferred<Object>} resolves to the fetched group object
+ * @returns {Promise<Object>} resolves to the fetched group object
*/
_readGroup: function (list, options) {
var self = this;
@@ -4285,20 +4294,20 @@ var BasicModel = AbstractModel.extend({
});
}
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function (groups) {
if (!options || !options.onlyGroups) {
// generate the res_ids of the main list, being the concatenation
// of the fetched res_ids in each group
- list.res_ids = _.flatten(_.map(arguments, function (group) {
+ list.res_ids = _.flatten(_.map(groups, function (group) {
return group ? group.res_ids : [];
}));
}
return list;
}).then(function () {
- var fetchingDefs = [];
- fetchingDefs.push(self._fetchX2ManysSingleBatch(list));
- fetchingDefs.push(self._fetchReferencesSingleBatch(list));
- return $.when.apply($, fetchingDefs).then(function () {
+ return Promise.all([
+ self._fetchX2ManysSingleBatch(list),
+ self._fetchReferencesSingleBatch(list)
+ ]).then(function () {
return list;
});
});
@@ -4309,11 +4318,11 @@ var BasicModel = AbstractModel.extend({
* instead of a /search_read.
*
* @param {Object} list a valid resource object
- * @returns {Deferred<Object>} resolves to the fetched list object
+ * @returns {Promise<Object>} resolves to the fetched list object
*/
_readUngroupedList: function (list) {
var self = this;
- var def = $.when();
+ var def = Promise.resolve();
// generate the current count and res_ids list by applying the changes
list = this._applyX2ManyOperations(list);
@@ -4375,7 +4384,7 @@ var BasicModel = AbstractModel.extend({
* @param {Object} [options]
* @param {boolean} [options.keepChanges=false] if true, doesn't discard the
* changes on the record before reloading it
- * @returns {Deferred<string>} resolves to the id of the resource
+ * @returns {Promise<string>} resolves to the id of the resource
*/
_reload: function (id, options) {
options = options || {};
@@ -4464,7 +4473,7 @@ var BasicModel = AbstractModel.extend({
* /search_read because the data may not be static (for ex, a list view).
*
* @param {Object} list
- * @returns {Deferred}
+ * @returns {Promise}
*/
_searchReadUngroupedList: function (list) {
var self = this;
diff --git a/addons/web/static/src/js/views/basic/basic_renderer.js b/addons/web/static/src/js/views/basic/basic_renderer.js
index 27821081f96..2bc63f47073 100644
--- a/addons/web/static/src/js/views/basic/basic_renderer.js
+++ b/addons/web/static/src/js/views/basic/basic_renderer.js
@@ -61,13 +61,13 @@ var BasicRenderer = AbstractRenderer.extend({
* before notifying them).
*
* @param {string} recordID
- * @return {Deferred}
+ * @return {Promise}
*/
commitChanges: function (recordID) {
var defs = _.map(this.allFieldWidgets[recordID], function (widget) {
return widget.commitChanges();
});
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Updates the internal state of the renderer to the new state. By default,
@@ -86,7 +86,7 @@ var BasicRenderer = AbstractRenderer.extend({
* @param {string} id
* @param {string[]} fields
* @param {OdooEvent} ev
- * @returns {Deferred<AbstractField[]>} resolved with the list of widgets
+ * @returns {Promise<AbstractField[]>} resolved with the list of widgets
* that have been reset
*/
confirmChange: function (state, id, fields, ev) {
@@ -118,7 +118,7 @@ var BasicRenderer = AbstractRenderer.extend({
// state before evaluation
defs.push(this._updateAllModifiers(record));
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
return resetWidgets;
});
},
@@ -295,7 +295,7 @@ var BasicRenderer = AbstractRenderer.extend({
*
* @private
* @param {AbstractField} widget
- * @returns {boolean|Deferred<boolean>} @see AbstractField.isValid
+ * @returns {boolean|Promise<boolean>} @see AbstractField.isValid
*/
_canWidgetBeSaved: function (widget) {
var modifiers = this._getEvaluatedModifiers(widget.__node, widget.record);
@@ -386,6 +386,7 @@ var BasicRenderer = AbstractRenderer.extend({
* @param {Object} node the attrs coming from the arch
*/
_postProcessField: function (widget, node) {
+ this._handleAttributes(widget.$el, node);
},
/**
* Registers or updates the modifiers data associated to the given node.
@@ -503,7 +504,7 @@ var BasicRenderer = AbstractRenderer.extend({
* Render the view
*
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
var oldAllFieldWidgets = this.allFieldWidgets;
@@ -520,7 +521,7 @@ var BasicRenderer = AbstractRenderer.extend({
/**
* Instantiates the appropriate AbstractField specialization for the given
* node and prepares its rendering and addition to the DOM. Indeed, the
- * rendering of the widget will be started and the associated deferred will
+ * rendering of the widget will be started and the associated promise will
* be added to the 'defs' attribute. This is supposed to be created and
* deleted by the calling code if necessary.
*
@@ -559,28 +560,31 @@ var BasicRenderer = AbstractRenderer.extend({
widget.__node = node; // TODO get rid of this if possible one day
- // Prepare widget rendering and save the related deferred
+ // Prepare widget rendering and save the related promise
var def = widget._widgetRenderAndInsert(function () {});
- var async = def.state() === 'pending';
- var $el = async ? $('<div>') : widget.$el;
- if (async) {
- this.defs.push(def);
- }
+ var $el = $('<div>');
+
+ this.defs.push(def);
// Update the modifiers registration by associating the widget and by
// giving the modifiers options now (as the potential callback is
// associated to new widget)
var self = this;
def.then(function () {
- if (async) {
- $el.replaceWith(widget.$el);
- }
+ // when the caller of renderFieldWidget uses something like
+ // this.renderFieldWidget(...).addClass(...), the class is added on
+ // the temporary div and not on the actual element that will be
+ // rendered. As we do not return a promise and some callers cannot
+ // wait for this.defs, we copy those attributes to the final element.
+ widget.$el.attr($el.getAttributes());
+
+ $el.replaceWith(widget.$el);
self._registerModifiers(node, record, widget, {
callback: function (element, modifiers, record) {
element.$el.toggleClass('o_field_empty', !!(
- record.data.id
- && (modifiers.readonly || mode === 'readonly')
- && !element.widget.isSet()
+ record.data.id &&
+ (modifiers.readonly || mode === 'readonly') &&
+ !element.widget.isSet()
));
},
keepBaseMode: !!options.keepBaseMode,
@@ -618,10 +622,10 @@ var BasicRenderer = AbstractRenderer.extend({
* possible.
*
* @abstract
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderView: function () {
- return $.when();
+ return Promise.resolve();
},
/**
* Instantiate custom widgets
@@ -637,22 +641,17 @@ var BasicRenderer = AbstractRenderer.extend({
this.widgets.push(widget);
- // Prepare widget rendering and save the related deferred
+ // Prepare widget rendering and save the related promise
var def = widget._widgetRenderAndInsert(function () {});
- var async = def.state() === 'pending';
- if (async) {
- this.defs.push(def);
- }
- var $el = async ? $('<div>') : widget.$el;
+ this.defs.push(def);
+ var $el = $('<div>');
var self = this;
def.then(function () {
self._handleAttributes(widget.$el, node);
self._registerModifiers(node, record, widget);
widget.$el.addClass('o_widget');
- if (async) {
- $el.replaceWith(widget.$el);
- }
+ $el.replaceWith(widget.$el);
});
return $el;
@@ -709,7 +708,7 @@ var BasicRenderer = AbstractRenderer.extend({
*
* @private
* @param {Object} record
- * @returns {Deferred} resolved once finished
+ * @returns {Promise} resolved once finished
*/
_updateAllModifiers: function (record) {
var self = this;
@@ -722,7 +721,7 @@ var BasicRenderer = AbstractRenderer.extend({
});
delete this.defs;
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/views/basic/basic_view.js b/addons/web/static/src/js/views/basic/basic_view.js
index 313bed44708..008bbcf8775 100644
--- a/addons/web/static/src/js/views/basic/basic_view.js
+++ b/addons/web/static/src/js/views/basic/basic_view.js
@@ -93,7 +93,7 @@ var BasicView = AbstractView.extend({
*
* @override
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadData: function (model) {
if (this.recordID) {
@@ -195,7 +195,7 @@ var BasicView = AbstractView.extend({
}
});
}
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
return model.get(record.id);
});
}
diff --git a/addons/web/static/src/js/views/calendar/calendar_controller.js b/addons/web/static/src/js/views/calendar/calendar_controller.js
index 0934ae462b3..fa41706de2b 100644
--- a/addons/web/static/src/js/views/calendar/calendar_controller.js
+++ b/addons/web/static/src/js/views/calendar/calendar_controller.js
@@ -143,7 +143,7 @@ var CalendarController = AbstractController.extend({
*
* @private
* @param {string} to either 'prev', 'next' or 'today'
- * @returns {Deferred}
+ * @returns {Promise}
*/
_move: function (to) {
this.model[to]();
@@ -153,7 +153,7 @@ var CalendarController = AbstractController.extend({
* @private
* @param {Object} record
* @param {integer} record.id
- * @returns {Deferred}
+ * @returns {Promise}
*/
_updateRecord: function (record) {
return this.model.updateRecord(record).then(this.reload.bind(this, {}));
@@ -388,18 +388,18 @@ var CalendarController = AbstractController.extend({
self.quick.destroy();
self.quick = null;
self.reload();
+ self.quickCreating = false;
})
- .fail(function (error, errorEvent) {
+ .guardedCatch(function (result) {
+ var errorEvent = result.event;
// This will occurs if there are some more fields required
// Preventdefaulting the error event will prevent the traceback window
errorEvent.preventDefault();
event.data.options.disableQuickCreate = true;
event.data.data.on_save = self.quick.destroy.bind(self.quick);
self._onOpenCreate(event.data);
- })
- .always(function () {
self.quickCreating = false;
- });
+ })
},
/**
* Called when we want to open or close the sidebar.
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 aaf52057ad6..9d8cf04f30f 100644
--- a/addons/web/static/src/js/views/calendar/calendar_model.js
+++ b/addons/web/static/src/js/views/calendar/calendar_model.js
@@ -177,7 +177,7 @@ return AbstractModel.extend({
/**
* @override
* @param {any} params
- * @returns {Deferred}
+ * @returns {Promise}
*/
load: function (params) {
var self = this;
@@ -199,15 +199,18 @@ return AbstractModel.extend({
// fields to display color, e.g.: user_id.partner_id
this.fieldColor = params.fieldColor;
- if (!this.preload_def) {
- this.preload_def = $.Deferred();
- $.when(
- this._rpc({model: this.modelName, method: 'check_access_rights', args: ["write", false]}),
- this._rpc({model: this.modelName, method: 'check_access_rights', args: ["create", false]}))
- .then(function (write, create) {
- self.write_right = write;
- self.create_right = create;
- self.preload_def.resolve();
+ if (!this.preloadPromise) {
+ this.preloadPromise = new Promise(function (resolve, reject) {
+ Promise.all([
+ self._rpc({model: self.modelName, method: 'check_access_rights', args: ["write", false]}),
+ self._rpc({model: self.modelName, method: 'check_access_rights', args: ["create", false]})
+ ]).then(function (result) {
+ var write = result[0];
+ var create = result[1];
+ self.write_right = write;
+ self.create_right = create;
+ resolve();
+ }).guardedCatch(reject);
});
}
@@ -229,7 +232,7 @@ return AbstractModel.extend({
}
});
- return this.preload_def.then(this._loadCalendar.bind(this));
+ return this.preloadPromise.then(this._loadCalendar.bind(this));
},
/**
* Move the current date range to the next period
@@ -247,7 +250,7 @@ return AbstractModel.extend({
* @override
* @param {Object} [params.context]
* @param {Array} [params.domain]
- * @returns {Deferred}
+ * @returns {Promise}
*/
reload: function (handle, params) {
if (params.domain) {
@@ -308,7 +311,7 @@ return AbstractModel.extend({
/**
* @param {Object} record
* @param {integer} record.id
- * @returns {Deferred}
+ * @returns {Promise}
*/
updateRecord: function (record) {
// Cannot modify actual name yet
@@ -430,7 +433,7 @@ return AbstractModel.extend({
},
/**
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadCalendar: function () {
var self = this;
@@ -439,7 +442,7 @@ return AbstractModel.extend({
var defs = _.map(this.data.filters, this._loadFilter.bind(this));
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
return self._rpc({
model: self.modelName,
method: 'search_read',
@@ -450,10 +453,10 @@ return AbstractModel.extend({
.then(function (events) {
self._parseServerData(events);
self.data.data = _.map(events, self._recordToCalendarEvent.bind(self));
- return $.when(
+ return Promise.all([
self._loadColors(self.data, self.data.data),
self._loadRecordsToFilters(self.data, self.data.data)
- );
+ ]);
});
});
},
@@ -461,7 +464,7 @@ return AbstractModel.extend({
* @private
* @param {any} element
* @param {any} events
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadColors: function (element, events) {
if (this.fieldColor) {
@@ -472,16 +475,16 @@ return AbstractModel.extend({
});
this.model_color = this.fields[fieldName].relation || element.model;
}
- return $.Deferred().resolve();
+ return Promise.resolve();
},
/**
* @private
* @param {any} filter
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadFilter: function (filter) {
if (!filter.write_model) {
- return $.when();
+ return Promise.resolve();
}
var field = this.fields[filter.fieldName];
@@ -540,7 +543,7 @@ return AbstractModel.extend({
* @private
* @param {any} element
* @param {any} events
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadRecordsToFilters: function (element, events) {
var self = this;
@@ -608,7 +611,7 @@ return AbstractModel.extend({
to_read[model] = _.object(res);
}));
});
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
_.each(self.data.filters, function (filter) {
if (filter.write_model) {
return;
diff --git a/addons/web/static/src/js/views/calendar/calendar_renderer.js b/addons/web/static/src/js/views/calendar/calendar_renderer.js
index 0ea7d60b1ce..c66b7bcc665 100644
--- a/addons/web/static/src/js/views/calendar/calendar_renderer.js
+++ b/addons/web/static/src/js/views/calendar/calendar_renderer.js
@@ -85,7 +85,7 @@ var SidebarFilter = Widget.extend(FieldManagerMixin, {
});
defs.push(def);
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
@@ -193,7 +193,7 @@ return AbstractRenderer.extend({
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this._initSidebar();
@@ -460,7 +460,7 @@ return AbstractRenderer.extend({
*
* @override method from AbstractRenderer
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
var $calendar = this.$calendar;
@@ -504,7 +504,7 @@ return AbstractRenderer.extend({
this.$sidebar_container.toggleClass('o_sidebar_hidden', fullWidth);
this.$sidebar.toggleClass('o_hidden', fullWidth);
- this._renderFilters();
+ var filterProm = this._renderFilters();
this.$calendar.appendTo('body');
if (scrollTop) {
this.$calendar.fullCalendar('reinitView');
@@ -514,7 +514,7 @@ return AbstractRenderer.extend({
this._renderEvents();
this.$calendar.prependTo(this.$('.o_calendar_view'));
- return this._super.apply(this, arguments);
+ return Promise.all([filterProm, this._super.apply(this, arguments)]);
},
/**
* Render all events
@@ -529,25 +529,47 @@ return AbstractRenderer.extend({
* Render all filters
*
* @private
+ * @returns {Promise} resolved when all filters have been rendered
*/
_renderFilters: function () {
- var self = this;
_.each(this.filters || (this.filters = []), function (filter) {
filter.destroy();
});
if (this.state.fullWidth) {
return;
}
- _.each(this.state.filters, function (options) {
+ return this._renderFiltersOneByOne();
+ },
+ /**
+ * Renders each filter one by one, waiting for the first filter finished to
+ * be rendered and appended to render the next one.
+ * We need to do like this since render a filter is asynchronous, we don't
+ * know which one will be appened at first and we want tp force them to be
+ * rendered in order.
+ *
+ * @param {number} filterIndex if not set, 0 by default
+ * @returns {Promise} resolved when all filters have been rendered
+ */
+ _renderFiltersOneByOne: function (filterIndex) {
+ filterIndex = filterIndex || 0;
+ var arrFilters = _.toArray(this.state.filters);
+ var prom;
+ if (filterIndex < arrFilters.length) {
+ var options = arrFilters[filterIndex];
if (!_.find(options.filters, function (f) {return f.display == null || f.display;})) {
return;
}
- options.getColor = self.getColor.bind(self);
- options.fields = self.state.fields;
+
+ var self = this;
+ options.getColor = this.getColor.bind(this);
+ options.fields = this.state.fields;
var filter = new SidebarFilter(self, options);
- filter.appendTo(self.$sidebar);
- self.filters.push(filter);
- });
+ prom = filter.appendTo(this.$sidebar).then(function () {
+ return self._renderFiltersOneByOne(filterIndex + 1);
+ });
+ this.filters.push(filter);
+ }
+ return Promise.resolve(prom);
},
//--------------------------------------------------------------------------
diff --git a/addons/web/static/src/js/views/control_panel/control_panel_controller.js b/addons/web/static/src/js/views/control_panel/control_panel_controller.js
index 40b1c45b9c7..913c226ba85 100644
--- a/addons/web/static/src/js/views/control_panel/control_panel_controller.js
+++ b/addons/web/static/src/js/views/control_panel/control_panel_controller.js
@@ -63,14 +63,14 @@ var ControlPanelController = mvc.Controller.extend({
},
/**
* @param {Object} state a ControlPanelModel state
- * @returns {Deferred<Object>} the result of `getSearchState`
+ * @returns {Promise<Object>} the result of `getSearchState`
*/
importState: function (state) {
var defs = [];
this.model.importState(state);
defs.push(this.getSearchQuery());
defs.push(this.renderer.updateState(this.model.get()));
- return $.when(defs).then(function (defsResults) {
+ return Promise.all(defs).then(function (defsResults) {
return defsResults[0];
});
},
@@ -127,7 +127,7 @@ var ControlPanelController = mvc.Controller.extend({
},
/**
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_reportNewQueryAndRender: function () {
this.trigger_up('search', this.model.getQuery());
diff --git a/addons/web/static/src/js/views/control_panel/control_panel_model.js b/addons/web/static/src/js/views/control_panel/control_panel_model.js
index e59dbfb1036..ad0d80de7a3 100644
--- a/addons/web/static/src/js/views/control_panel/control_panel_model.js
+++ b/addons/web/static/src/js/views/control_panel/control_panel_model.js
@@ -325,7 +325,7 @@ var ControlPanelModel = mvc.Model.extend({
* @param {string[]} [params.searchMenuTypes=[]]
* @param {Object} [params.timeRanges]
* @param {boolean} [params.withSearchBar]
- * @returns {Deferred}
+ * @returns {Promise}
*/
load: function (params) {
var self = this;
@@ -337,11 +337,11 @@ var ControlPanelModel = mvc.Model.extend({
// and the info comming from arch put in params.groups (if any)
// will be lost. This is not a problem because the state
// won't be use elsewhere.
- return $.when();
+ return Promise.resolve();
}
if (params.initialState) {
this.importState(params.initialState);
- return $.when();
+ return Promise.resolve();
} else {
var groups = params.groups || [];
groups.forEach(function (group) {
@@ -351,7 +351,7 @@ var ControlPanelModel = mvc.Model.extend({
this._createEmptyGroup('groupBy');
}
this._createGroupOfTimeRanges();
- return $.when.apply($, self._loadSearchDefaults()).then(function () {
+ return Promise.all(self._loadSearchDefaults()).then(function () {
return self._loadFavorites().then(function () {
if (self.query.length === 0) {
self._activateDefaultFilters();
@@ -910,7 +910,7 @@ var ControlPanelModel = mvc.Model.extend({
* if this.activateDefaultFavorite is true.
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadFavorites: function () {
var self = this;
@@ -980,7 +980,7 @@ var ControlPanelModel = mvc.Model.extend({
* is asynchronous.
*
* @private
- * @returns {Deferred[]}
+ * @returns {Promise[]}
*/
_loadSearchDefaults: function () {
var self = this;
@@ -1044,7 +1044,7 @@ var ControlPanelModel = mvc.Model.extend({
*
* @private
* @param {Object} favorite
- * @returns {Deferred}
+ * @returns {Promise}
*/
_saveQuery: function (favorite) {
var self = this;
diff --git a/addons/web/static/src/js/views/control_panel/control_panel_renderer.js b/addons/web/static/src/js/views/control_panel/control_panel_renderer.js
index fd9037cdf6f..a1da2925eb6 100644
--- a/addons/web/static/src/js/views/control_panel/control_panel_renderer.js
+++ b/addons/web/static/src/js/views/control_panel/control_panel_renderer.js
@@ -86,7 +86,7 @@ var ControlPanelRenderer = Renderer.extend({
var superDef = this._super.apply(this, arguments);
var searchDef = this._renderSearch();
- return $.when(superDef, searchDef).then(function () {
+ return Promise.all([superDef, searchDef]).then(function () {
self._setSearchMenusVisibility();
});
},
@@ -148,7 +148,7 @@ var ControlPanelRenderer = Renderer.extend({
* Update the state of the renderer state. It retriggers a full rerendering.
*
* @param {Object} state
- * @returns {Deferred}
+ * @returns {Promise}
*/
updateState: function (state) {
this.state = state;
@@ -261,7 +261,7 @@ var ControlPanelRenderer = Renderer.extend({
* Renderer the search bar and the search menus
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderSearch: function () {
var defs = [];
@@ -274,11 +274,11 @@ var ControlPanelRenderer = Renderer.extend({
if (this.withSearchBar) {
defs.push(this._renderSearchBar());
}
- return $.when(this, defs).then(this._focusSearchInput.bind(this));
+ return Promise.all(defs).then(this._focusSearchInput.bind(this));
},
/**
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderSearchBar: function () {
// TODO: might need a reload instead of a destroy/instantiate
@@ -315,7 +315,7 @@ var ControlPanelRenderer = Renderer.extend({
*
* @private
* @param {string} menuType
- * @returns {Deferred}
+ * @returns {Promise}
*/
_setupMenu: function (menuType) {
var Menu;
@@ -345,7 +345,7 @@ var ControlPanelRenderer = Renderer.extend({
* Instantiate the search menu determined by this.searchMenuTypes.
*
* @private
- * @returns {Deferred[]}
+ * @returns {Promise[]}
*/
_setupMenus: function () {
this.$subMenus = this._getSubMenusPlace();
diff --git a/addons/web/static/src/js/views/control_panel/search/filter_menu.js b/addons/web/static/src/js/views/control_panel/search/filter_menu.js
index 04f333b37c4..4ded35cfecc 100644
--- a/addons/web/static/src/js/views/control_panel/search/filter_menu.js
+++ b/addons/web/static/src/js/views/control_panel/search/filter_menu.js
@@ -67,14 +67,14 @@ var FilterMenu = DropdownMenu.extend({
* Add a proposition inside the custom filter edition menu.
*
* @private
- * @returns {$.Deferred}
+ * @returns {Promise}
*/
_appendProposition: function () {
// make modern sear_filters code!!! It works but...
var prop = new search_filters.ExtendedSearchProposition(this, this.fields);
this.propositions.push(prop);
this.$('.o_apply_filter').prop('disabled', false);
- prop.insertBefore(this.$addFilterMenu);
+ return prop.insertBefore(this.$addFilterMenu);
},
/**
* Confirm a filter proposition, creates it and add it to the menu.
diff --git a/addons/web/static/src/js/views/control_panel/search/search_bar.js b/addons/web/static/src/js/views/control_panel/search/search_bar.js
index 77d6d7fa5e9..4c2e71a378f 100644
--- a/addons/web/static/src/js/views/control_panel/search/search_bar.js
+++ b/addons/web/static/src/js/views/control_panel/search/search_bar.js
@@ -46,7 +46,7 @@ var SearchBar = Widget.extend({
defs.push(self._renderFacet(facet));
});
defs.push(this._setupAutoCompletion());
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
//--------------------------------------------------------------------------
@@ -116,18 +116,21 @@ var SearchBar = Widget.extend({
* @param {Function} callback
*/
_getAutoCompleteSources: function (req, callback) {
- var defs = _.invoke(this.autoCompleteSources, 'getAutocompletionValues', req.term);
- $.when.apply($, defs).then(function () {
- callback(_(arguments).chain()
+ var defs = this.autoCompleteSources.map(function (source) {
+ return source.getAutocompletionValues(req.term);
+ });
+ Promise.all(defs).then(function (result) {
+ var resultCleaned = _(result).chain()
.compact()
.flatten(true)
- .value());
- });
+ .value();
+ callback(resultCleaned);
+ });
},
/**
* @private
* @param {Object} facet
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderFacet: function (facet) {
var searchFacet = new SearchFacet(this, facet);
@@ -136,7 +139,7 @@ var SearchBar = Widget.extend({
},
/**
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_setupAutoCompletion: function () {
var self = this;
diff --git a/addons/web/static/src/js/views/control_panel/search/search_bar_autocomplete_sources.js b/addons/web/static/src/js/views/control_panel/search/search_bar_autocomplete_sources.js
index f1ac0ee0f2e..8adc385a789 100644
--- a/addons/web/static/src/js/views/control_panel/search/search_bar_autocomplete_sources.js
+++ b/addons/web/static/src/js/views/control_panel/search/search_bar_autocomplete_sources.js
@@ -32,7 +32,7 @@ var FilterInterface = Class.extend(mixins.EventDispatcherMixin, {
* label. They will be used by search_bar in @_onAutoCompleteSelected.
*
* @param {string} value value to getAutocompletionValues
- * @returns {Deferred<null|Array>}
+ * @returns {Promise<null|Array>}
*/
getAutocompletionValues: function (value) {
var result;
@@ -46,7 +46,7 @@ var FilterInterface = Class.extend(mixins.EventDispatcherMixin, {
},
}];
}
- return $.when(result);
+ return Promise.resolve(result);
},
});
@@ -83,7 +83,7 @@ var Field = FilterInterface.extend(ServicesMixin, {
* @override
*/
getAutocompletionValues: function (value) {
- return $.when([{
+ return Promise.resolve([{
label: this._getAutocompletionLabel(value),
facet: this._getFacetValue(value),
}]);
@@ -194,7 +194,7 @@ var CharField = Field.extend({
* @override
*/
getAutocompletionValues: function (value) {
- if (_.isEmpty(value)) { return $.when(null); }
+ if (_.isEmpty(value)) { return Promise.resolve(null); }
return this._super.apply(this, arguments);
},
});
@@ -210,7 +210,7 @@ var NumberField = Field.extend({
*/
getAutocompletionValues: function (value) {
var val = this.parse(value);
- if (isNaN(val)) { return $.when(); }
+ if (isNaN(val)) { return Promise.resolve(); }
return this._super.apply(this, arguments);
},
});
@@ -261,8 +261,8 @@ var SelectionField = Field.extend({
facet: self._getFacetValue(sel)
};
}).value();
- if (_.isEmpty(results)) { return $.when(null); }
- return $.when.call(null, [{
+ if (_.isEmpty(results)) { return Promise.resolve(null); }
+ return Promise.resolve([{
label: _.escape(this.attrs.string)
}].concat(results));
},
@@ -310,15 +310,15 @@ var DateField = Field.extend({
t = (this.attrs && this.attrs.type === 'datetime') ? 'datetime' : 'date';
v = field_utils.parse[t](value, {type: t}, {timezone: true});
} catch (e) {
- return $.when(null);
+ return Promise.resolve(null);
}
var m = moment(v, t === 'datetime' ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD');
- if (!m.isValid()) { return $.when(null); }
+ if (!m.isValid()) { return Promise.resolve(null); }
var dateString = field_utils.format[t](m, {type: t});
var label = this._getAutocompletionLabel(dateString);
var facet = this._getFacetValue(dateString, m.toDate());
- return $.when([{
+ return Promise.resolve([{
label: label,
facet: facet,
}]);
@@ -379,9 +379,9 @@ var ManyToOneField = CharField.extend({
* @override
*/
getAutocompletionValues: function (value) {
- if (_.isEmpty(value)) { return $.when(null); }
+ if (_.isEmpty(value)) { return Promise.resolve(null); }
var label = this._getAutocompletionLabel(value);
- return $.when([{
+ return Promise.resolve([{
label: label,
facet: this._getFacetValue(value),
expand: this._expand.bind(this),
diff --git a/addons/web/static/src/js/views/control_panel/search/search_filters.js b/addons/web/static/src/js/views/control_panel/search/search_filters.js
index 80a9019c02d..ae0ed12772e 100644
--- a/addons/web/static/src/js/views/control_panel/search/search_filters.js
+++ b/addons/web/static/src/js/views/control_panel/search/search_filters.js
@@ -40,7 +40,9 @@ var ExtendedSearchProposition = Widget.extend({
this.value = null;
},
start: function () {
- return this._super().done(this.proxy('changed'));
+ var parent = this._super();
+ parent.then(this.proxy('changed'));
+ return parent;
},
changed: function () {
var nval = this.$(".o_searchview_extended_prop_field").val();
@@ -234,10 +236,10 @@ var DateTime = Field.extend({
return str;
},
start: function () {
- return $.when(
+ return Promise.all([
this._super.apply(this, arguments),
this._create_new_widget("datewidget_0")
- );
+ ]);
},
_create_new_widget: function (name) {
this[name] = new (this._get_widget_class())(this);
diff --git a/addons/web/static/src/js/views/field_manager_mixin.js b/addons/web/static/src/js/views/field_manager_mixin.js
index bc61e92a89a..99aabc6e66d 100644
--- a/addons/web/static/src/js/views/field_manager_mixin.js
+++ b/addons/web/static/src/js/views/field_manager_mixin.js
@@ -41,7 +41,7 @@ var FieldManagerMixin = {
* @param {string} dataPointID
* @param {Object} changes
* @param {OdooEvent} event
- * @returns {Deferred} resolves when the change has been done, and the UI
+ * @returns {Promise} resolves when the change has been done, and the UI
* updated
*/
_applyChanges: function (dataPointID, changes, event) {
@@ -66,10 +66,10 @@ var FieldManagerMixin = {
* @param {string} id basicModel Id for the changed record
* @param {string[]} fields the fields (names) that have been changed
* @param {OdooEvent} event the event that triggered the change
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmChange: function (id, fields, event) {
- return $.when();
+ return Promise.resolve();
},
/**
* This method will be called whenever a save has been triggered by a change
@@ -79,10 +79,10 @@ var FieldManagerMixin = {
* @see _onFieldChanged
* @abstract
* @param {string} id The basicModel ID for the saved record
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmSave: function (id) {
- return $.when();
+ return Promise.resolve();
},
//--------------------------------------------------------------------------
@@ -103,9 +103,9 @@ var FieldManagerMixin = {
// subrecord's form view), otherwise it bubbles up to the main form view
// but its model doesn't have any data related to the given dataPointID
event.stopPropagation();
- this._applyChanges(event.data.dataPointID, event.data.changes, event)
- .done(event.data.onSuccess || function () {})
- .fail(event.data.onFailure || function () {});
+ return this._applyChanges(event.data.dataPointID, event.data.changes, event)
+ .then(event.data.onSuccess || function () {})
+ .guardedCatch(event.data.onFailure || function () {});
},
/**
* Some widgets need to trigger a reload of their data. For example, a
diff --git a/addons/web/static/src/js/views/form/form_controller.js b/addons/web/static/src/js/views/form/form_controller.js
index d0400ef041f..5616a5099bc 100644
--- a/addons/web/static/src/js/views/form/form_controller.js
+++ b/addons/web/static/src/js/views/form/form_controller.js
@@ -84,7 +84,7 @@ var FormController = BasicController.extend({
* @todo make record creation a basic controller feature
* @param {string} [parentID] if given, the parentID will be used as parent
* for the new record.
- * @returns {Deferred}
+ * @returns {Promise}
*/
createRecord: function (parentID) {
var self = this;
@@ -165,20 +165,23 @@ var FormController = BasicController.extend({
* @override method from BasicController
* @param {jQueryElement} $node
* @param {Object} options
+ * @returns {Promise}
*/
renderPager: function ($node, options) {
options = _.extend({}, options, {
validate: this.canBeDiscarded.bind(this),
});
- this._super($node, options);
+ return this._super($node, options);
},
/**
* Instantiate and render the sidebar if a sidebar is requested
* Sets this.sidebar
* @param {jQuery} [$node] a jQuery node where the sidebar should be
* inserted
+ * @return {Promise}
**/
renderSidebar: function ($node) {
+ var self = this;
if (this.hasSidebar) {
var otherItems = [];
if (this.is_action_enabled('delete')) {
@@ -203,11 +206,12 @@ var FormController = BasicController.extend({
},
actions: _.extend(this.toolbarActions, {other: otherItems}),
});
- this.sidebar.appendTo($node);
-
- // Show or hide the sidebar according to the view mode
- this._updateSidebar();
+ return this.sidebar.appendTo($node).then(function() {
+ // Show or hide the sidebar according to the view mode
+ self._updateSidebar();
+ });
}
+ return Promise.resolve();
},
/**
* Show a warning message if the user modified a translated field. For each
@@ -296,7 +300,7 @@ var FormController = BasicController.extend({
* @private
* @override method from field manager mixin
* @param {string} id - id of the previously changed record
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmSave: function (id) {
if (id === this.handle) {
@@ -393,14 +397,19 @@ var FormController = BasicController.extend({
* @override
* @private
* @param {Object} state
- * @returns {Deferred}
+ * @returns {Promise}
*/
_update: function () {
- var title = this.getTitle();
- this._setTitle(title);
- this._updateButtons();
- this._updateSidebar();
- return this._super.apply(this, arguments).then(this.autofocus.bind(this));
+ var self = this;
+
+ return this._super.apply(this, arguments).then(function() {
+ var title = self.getTitle();
+ self._setTitle(title);
+ self._updateButtons();
+ self._updateSidebar();
+
+ self.autofocus();
+ });
},
/**
* @private
@@ -470,13 +479,11 @@ var FormController = BasicController.extend({
}
var attrs = ev.data.attrs;
if (attrs.confirm) {
- var d = $.Deferred();
- Dialog.confirm(this, attrs.confirm, {
- confirm_callback: saveAndExecuteAction,
- }).on("closed", null, function () {
- d.resolve();
+ def = new Promise(function (resolve, reject) {
+ Dialog.confirm(this, attrs.confirm, {
+ confirm_callback: saveAndExecuteAction,
+ }).on("closed", null, resolve);
});
- def = d.promise();
} else if (attrs.special === 'cancel') {
def = this._callButtonAction(attrs, ev.data.record);
} else if (!attrs.special || attrs.special === 'save') {
@@ -484,7 +491,7 @@ var FormController = BasicController.extend({
def = saveAndExecuteAction();
}
- def.always(this._enableButtons.bind(this));
+ def.then(this._enableButtons.bind(this)).guardedCatch(this._enableButtons.bind(this));
},
/**
* Called when the user wants to create a new record -> @see createRecord
@@ -659,9 +666,7 @@ var FormController = BasicController.extend({
ev.stopPropagation(); // Prevent x2m lines to be auto-saved
var self = this;
this._disableButtons();
- this.saveRecord().always(function () {
- self._enableButtons();
- });
+ this.saveRecord().then(this._enableButtons.bind(this)).guardedCatch(this._enableButtons.bind(this));
},
/**
* Called when user swipes left. Move to next record.
diff --git a/addons/web/static/src/js/views/form/form_renderer.js b/addons/web/static/src/js/views/form/form_renderer.js
index ca26d7e90ad..97ab575cbc3 100644
--- a/addons/web/static/src/js/views/form/form_renderer.js
+++ b/addons/web/static/src/js/views/form/form_renderer.js
@@ -251,7 +251,7 @@ var FormRenderer = BasicRenderer.extend({
* @param {string} [params.mode] new mode, either 'edit' or 'readonly'
* @param {string[]} [params.fieldNames] if given, the renderer will only
* update the fields in this list
- * @returns {Deferred}
+ * @returns {Promise}
*/
updateState: function (state, params) {
this.mode = (params && 'mode' in params) ? params.mode : this.mode;
@@ -342,8 +342,8 @@ var FormRenderer = BasicRenderer.extend({
* @private
*/
_postProcessField: function (widget, node) {
+ this._super.apply(this, arguments);
this._setIDForLabel(widget, this._getIDForLabel(node.attrs.name));
- this._handleAttributes(widget.$el, node);
if (JSON.parse(node.attrs.default_focus || "0")) {
this.defaultFocusField = widget;
}
@@ -355,7 +355,14 @@ var FormRenderer = BasicRenderer.extend({
*/
_renderButtonBox: function (node) {
var self = this;
- var $result = $('<' + node.tag + '>', { 'class': 'o_not_full' });
+ var $result = $('<' + node.tag + '>', {class: 'o_not_full'});
+
+ // The rendering of buttons may be async (see renderFieldWidget), so we
+ // must wait for the buttons to be ready (and their modifiers to be
+ // applied) before manipulating them, as we check if they are visible or
+ // not. To do so, we extract from this.defs the promises corresponding
+ // to the buttonbox buttons, and wait for them to be resolved.
+ var nextDefIndex = this.defs.length;
var buttons = _.map(node.children, function (child) {
if (child.tag === 'button') {
return self._renderStatButton(child);
@@ -363,48 +370,62 @@ var FormRenderer = BasicRenderer.extend({
return self._renderNode(child);
}
});
- var buttons_partition = _.partition(buttons, function ($button) {
- return $button.is('.o_invisible_modifier');
+
+ // At this point, each button is an empty div that will be replaced by
+ // the real $el of the button when it is ready (with replaceWith).
+ // However, this only works if the empty div is appended somewhere, so
+ // we here append them into a wrapper, and unwrap them once they have
+ // been replaced.
+ var $tempWrapper = $('<div>');
+ _.each(buttons, function ($button) {
+ $button.appendTo($tempWrapper);
});
- var invisible_buttons = buttons_partition[0];
- var visible_buttons = buttons_partition[1];
+ var defs = this.defs.slice(nextDefIndex);
+ Promise.all(defs).then(function () {
+ buttons = $tempWrapper.children();
+ var buttons_partition = _.partition(buttons, function (button) {
+ return $(button).is('.o_invisible_modifier');
+ });
+ var invisible_buttons = buttons_partition[0];
+ var visible_buttons = buttons_partition[1];
- // Get the unfolded buttons according to window size
- var nb_buttons = [2, 2, 4, 6][config.device.size_class] || 7;
- var unfolded_buttons = visible_buttons.slice(0, nb_buttons).concat(invisible_buttons);
+ // Get the unfolded buttons according to window size
+ var nb_buttons = [2, 2, 4, 6][config.device.size_class] || 7;
+ var unfolded_buttons = visible_buttons.slice(0, nb_buttons).concat(invisible_buttons);
- // Get the folded buttons
- var folded_buttons = visible_buttons.slice(nb_buttons);
- if (folded_buttons.length === 1) {
- unfolded_buttons = buttons;
- folded_buttons = [];
- }
+ // Get the folded buttons
+ var folded_buttons = visible_buttons.slice(nb_buttons);
+ if (folded_buttons.length === 1) {
+ unfolded_buttons = buttons;
+ folded_buttons = [];
+ }
- // Toggle class to tell if the button box is full (CSS requirement)
- var full = (visible_buttons.length > nb_buttons);
- $result.toggleClass('o_full', full).toggleClass('o_not_full', !full);
+ // Toggle class to tell if the button box is full (CSS requirement)
+ var full = (visible_buttons.length > nb_buttons);
+ $result.toggleClass('o_full', full).toggleClass('o_not_full', !full);
- // Add the unfolded buttons
- _.each(unfolded_buttons, function ($button) {
- $button.appendTo($result);
- });
+ // Add the unfolded buttons
+ _.each(unfolded_buttons, function (button) {
+ $(button).appendTo($result);
+ });
- // Add the dropdown with folded buttons if any
- if (folded_buttons.length) {
- $result.append(dom.renderButton({
- attrs: {
- class: 'oe_stat_button o_button_more dropdown-toggle',
- 'data-toggle': 'dropdown',
- },
- text: _t("More"),
- }));
+ // Add the dropdown with folded buttons if any
+ if (folded_buttons.length) {
+ $result.append(dom.renderButton({
+ attrs: {
+ 'class': 'oe_stat_button o_button_more dropdown-toggle',
+ 'data-toggle': 'dropdown',
+ },
+ text: _t("More"),
+ }));
- var $dropdown = $("<div>", {'class': "dropdown-menu o_dropdown_more", role: "menu"});
- _.each(folded_buttons, function ($button) {
- $button.addClass('dropdown-item').appendTo($dropdown);
- });
- $dropdown.appendTo($result);
- }
+ var $dropdown = $("<div>", {class: "dropdown-menu o_dropdown_more", role: "menu"});
+ _.each(folded_buttons, function (button) {
+ $(button).addClass('dropdown-item').appendTo($dropdown);
+ });
+ $dropdown.appendTo($result);
+ }
+ });
this._handleAttributes($result, node);
this._registerModifiers(node, this.state, $result);
@@ -477,6 +498,7 @@ var FormRenderer = BasicRenderer.extend({
_renderInnerGroup: function (node) {
var self = this;
var $result = $('<table/>', {class: 'o_group o_inner_group'});
+ var $tbody = $('<tbody />').appendTo($result);
this._handleAttributes($result, node);
this._registerModifiers(node, this.state, $result);
@@ -490,7 +512,7 @@ var FormRenderer = BasicRenderer.extend({
var rows = [];
var $currentRow = $('<tr/>');
var currentColspan = 0;
- _.each(node.children, function (child) {
+ node.children.forEach(function (child) {
if (child.tag === 'newline') {
rows.push($currentRow);
$currentRow = $('<tr/>');
@@ -537,7 +559,7 @@ var FormRenderer = BasicRenderer.extend({
var $el = $(el);
$el.css('width', ((parseInt($el.attr('colspan'), 10) || 1) * nonLabelColSize) + '%');
});
- $result.append($tr);
+ $tbody.append($tr);
});
return $result;
@@ -575,7 +597,7 @@ var FormRenderer = BasicRenderer.extend({
*
* For fields, it will return the $el of the field widget. Note that this
* method is synchronous, field widgets are instantiated and appended, but
- * if they are asynchronous, they register their deferred in this.defs, and
+ * if they are asynchronous, they register their promises in this.defs, and
* the _renderView method will properly wait.
*
* @private
@@ -705,7 +727,8 @@ var FormRenderer = BasicRenderer.extend({
if (node.attrs.class) {
$result.addClass(node.attrs.class);
}
- $result.append(_.map(node.children, this._renderNode.bind(this)));
+ var allNodes = node.children.map(this._renderNode.bind(this));
+ $result.append(allNodes);
return $result;
},
/**
@@ -870,7 +893,7 @@ var FormRenderer = BasicRenderer.extend({
_renderTagSheet: function (node) {
this.has_sheet = true;
var $sheet = $('<div>', {class: 'clearfix o_form_sheet'});
- $sheet.append(_.map(node.children, this._renderNode.bind(this)));
+ $sheet.append(node.children.map(this._renderNode.bind(this)));
return $sheet;
},
/**
@@ -885,12 +908,12 @@ var FormRenderer = BasicRenderer.extend({
},
/**
* Main entry point for the rendering. From here, we call _renderNode on
- * the root of the arch, then, when every deferred (from the field widgets)
+ * the root of the arch, then, when every promise (from the field widgets)
* are done, it will resolves itself.
*
* @private
* @override method from BasicRenderer
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderView: function () {
var self = this;
@@ -901,17 +924,17 @@ var FormRenderer = BasicRenderer.extend({
var $form = this._renderNode(this.arch).addClass(this.className);
delete this.defs;
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
self._updateView($form.contents());
if (self.state.res_id in self.alertFields) {
self.displayTranslationAlert();
}
- }, function () {
- $form.remove();
}).then(function(){
if (self.lastActivatedFieldIndex >= 0) {
self._activateNextFieldWidget(self.state, self.lastActivatedFieldIndex);
}
+ }).guardedCatch(function () {
+ $form.remove();
});
},
/**
diff --git a/addons/web/static/src/js/views/form/form_view.js b/addons/web/static/src/js/views/form/form_view.js
index 5a00350c68f..0703d9713d5 100644
--- a/addons/web/static/src/js/views/form/form_view.js
+++ b/addons/web/static/src/js/views/form/form_view.js
@@ -93,7 +93,7 @@ var FormView = BasicView.extend({
*
* @private
* @param {Widget} parent the parent of the model, if it has to be created
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadSubviews: function (parent) {
var self = this;
@@ -145,7 +145,7 @@ var FormView = BasicView.extend({
}
});
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* We set here the limit for the number of records fetched (in one page).
diff --git a/addons/web/static/src/js/views/graph/graph_model.js b/addons/web/static/src/js/views/graph/graph_model.js
index 4c359a4778f..91b017524d8 100644
--- a/addons/web/static/src/js/views/graph/graph_model.js
+++ b/addons/web/static/src/js/views/graph/graph_model.js
@@ -50,7 +50,7 @@ return AbstractModel.extend({
* @param {string[]} params.domain
* @param {Object} params.intervalMapping object linking fieldNames with intervals.
* this could be useful to simplify the code. For now this parameter is not used.
- * @returns {Deferred} The deferred does not return a handle, we don't need
+ * @returns {Promise} The promise does not return a handle, we don't need
* to keep track of various entities.
*/
load: function (params) {
@@ -92,7 +92,7 @@ return AbstractModel.extend({
* @param {string[]} [params.groupBy]
* @param {string} [params.mode] one of 'bar', 'pie', 'line'
* @param {string} [params.measure] a valid field name
- * @returns {Deferred}
+ * @returns {Promise}
*/
reload: function (handle, params) {
if ('context' in params) {
@@ -130,7 +130,7 @@ return AbstractModel.extend({
}
if ('mode' in params) {
this.chart.mode = params.mode;
- return $.when();
+ return Promise.resolve();
}
return this._loadGraph();
},
@@ -145,7 +145,7 @@ return AbstractModel.extend({
* in the field list, because they can be defined with an aggregation
* function, such as my_date:week
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadGraph: function () {
var groupedBy = this.chart.groupedBy;
@@ -186,7 +186,7 @@ return AbstractModel.extend({
}).then(this._processData.bind(this, 'comparisonData')));
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Since read_group is insane and returns its result on different keys
diff --git a/addons/web/static/src/js/views/graph/graph_renderer.js b/addons/web/static/src/js/views/graph/graph_renderer.js
index 9353301ca09..6311df5d8b2 100644
--- a/addons/web/static/src/js/views/graph/graph_renderer.js
+++ b/addons/web/static/src/js/views/graph/graph_renderer.js
@@ -99,7 +99,7 @@ return AbstractRenderer.extend({
*
* @override
* @private
- * @returns {Deferred} The _super deferred is actually resolved immediately
+ * @returns {Promise} The _super promise is actually resolved immediately
*/
_render: function () {
if (this.to_remove) {
diff --git a/addons/web/static/src/js/views/kanban/kanban_column.js b/addons/web/static/src/js/views/kanban/kanban_column.js
index 2828ca491ca..b4aecd7a236 100644
--- a/addons/web/static/src/js/views/kanban/kanban_column.js
+++ b/addons/web/static/src/js/views/kanban/kanban_column.js
@@ -97,10 +97,7 @@ var KanbanColumn = Widget.extend({
this.$header = this.$('.o_kanban_header');
for (var i = 0; i < this.data_records.length; i++) {
- var def = this._addRecord(this.data_records[i]);
- if (def.state() === 'pending') {
- defs.push(def);
- }
+ defs.push(this._addRecord(this.data_records[i]));
}
if (!config.device.isMobile) {
@@ -170,7 +167,7 @@ var KanbanColumn = Widget.extend({
this.$('.o_kanban_load_more').html(QWeb.render('KanbanView.LoadMore', {widget: this}));
}
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* Called when a record has been quick created, as a new column is rendered
@@ -193,7 +190,7 @@ var KanbanColumn = Widget.extend({
/**
* Adds the quick create record to the top of the column.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
addQuickCreate: function () {
if (this.folded) {
@@ -205,7 +202,7 @@ var KanbanColumn = Widget.extend({
}
if (this.quickCreateWidget) {
- return $.Deferred().reject();
+ return Promise.reject();
}
this.trigger_up('close_quick_create'); // close other quick create widgets
this.trigger_up('start_quick_create');
@@ -245,7 +242,7 @@ var KanbanColumn = Widget.extend({
* @param {Object} [options]
* @param {string} [options.position]
* 'before' to add at the top, add at the bottom by default
- * @return {Deferred}
+ * @return {Promise}
*/
_addRecord: function (recordState, options) {
var record = new this.KanbanRecord(this, recordState, this.record_options);
diff --git a/addons/web/static/src/js/views/kanban/kanban_controller.js b/addons/web/static/src/js/views/kanban/kanban_controller.js
index 3b41b26e015..58174c7812d 100644
--- a/addons/web/static/src/js/views/kanban/kanban_controller.js
+++ b/addons/web/static/src/js/views/kanban/kanban_controller.js
@@ -76,6 +76,7 @@ var KanbanController = BasicController.extend({
/**
* @param {jQueryElement} $node
+ * @returns {Promise}
*/
renderButtons: function ($node) {
if (this.hasButtons && this.is_action_enabled('create')) {
@@ -86,8 +87,9 @@ var KanbanController = BasicController.extend({
this.$buttons.on('click', 'button.o-kanban-button-new', this._onButtonNew.bind(this));
this.$buttons.on('keydown', this._onButtonsKeyDown.bind(this));
this._updateButtons();
- this.$buttons.appendTo($node);
+ return Promise.resolve(this.$buttons.appendTo($node));
}
+ return Promise.resolve();
},
/**
* Override to add the domain coming from the searchPanel (if any) to the
@@ -110,7 +112,7 @@ var KanbanController = BasicController.extend({
params.domain = this.controlPanelDomain.concat(this.searchPanelDomain);
var superProm = this._super.apply(this, arguments);
var searchPanelProm = this._updateSearchPanel();
- return $.when(superProm, searchPanelProm).then(function () {
+ return Promise.all([superProm, searchPanelProm]).then(function () {
// searchPanel has been re-rendered, so re-render the view
return self.renderer.render();
});
@@ -124,7 +126,7 @@ var KanbanController = BasicController.extend({
* @override method comes from field manager mixin
* @private
* @param {string} id local id from the basic record data
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmSave: function (id) {
var data = this.model.get(this.handle, {raw: true});
@@ -197,7 +199,7 @@ var KanbanController = BasicController.extend({
/**
* @param {number[]} ids
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_resequenceColumns: function (ids) {
var state = this.model.get(this.handle, {raw: true});
@@ -212,7 +214,7 @@ var KanbanController = BasicController.extend({
* @private
* @param {string} column_id
* @param {string[]} ids
- * @returns {Deferred}
+ * @returns {Promise}
*/
_resequenceRecords: function (column_id, ids) {
var self = this;
@@ -246,7 +248,7 @@ var KanbanController = BasicController.extend({
},
/**
* @private
- * @returns {$.Promise}
+ * @returns {Promise}
*/
_updateSearchPanel: function () {
return this._searchPanel.update({searchDomain: this.controlPanelDomain});
@@ -296,7 +298,7 @@ var KanbanController = BasicController.extend({
self.renderer.updateColumn(db_id, data);
});
});
- }).fail(this.reload.bind(this, {}));
+ }).guardedCatch(this.reload.bind(this));
},
/**
* @private
@@ -400,7 +402,7 @@ var KanbanController = BasicController.extend({
var relatedModelName = state.fields[state.groupedBy[0]].relation;
this.model
.deleteRecords([column.db_id], relatedModelName)
- .done(function () {
+ .then(function () {
self.update({}, {reload: !column.isEmpty()});
});
},
@@ -415,11 +417,12 @@ var KanbanController = BasicController.extend({
var self = this;
this.model.loadColumnRecords(ev.data.columnID).then(function (dbID) {
var data = self.model.get(dbID);
- self.renderer.updateColumn(dbID, data);
- self._updateEnv();
- if (ev.data.onSuccess) {
- ev.data.onSuccess();
- }
+ return self.renderer.updateColumn(dbID, data).then(function() {
+ self._updateEnv();
+ if (ev.data.onSuccess) {
+ ev.data.onSuccess();
+ }
+ });
});
},
/**
@@ -470,8 +473,8 @@ var KanbanController = BasicController.extend({
this.model.createRecordInGroup(column.db_id, values)
.then(update)
- .fail(function (error, ev) {
- ev.preventDefault();
+ .guardedCatch(function (reason) {
+ reason.event.preventDefault();
var columnState = self.model.get(column.db_id, {raw: true});
var context = columnState.getContext();
var state = self.model.get(self.handle, {raw: true});
@@ -538,11 +541,15 @@ var KanbanController = BasicController.extend({
*
* @private
* @param {OdooEvent} ev
+ * @param {function} [ev.data.onSuccess] callback to execute after applying
+ * changes
*/
_onUpdateRecord: function (ev) {
+ var onSuccess = ev.data.onSuccess;
+ delete ev.data.onSuccess;
var changes = _.clone(ev.data);
ev.data.force_save = true;
- this._applyChanges(ev.target.db_id, changes, ev);
+ this._applyChanges(ev.target.db_id, changes, ev).then(onSuccess);
},
/**
* Allow the user to archive/restore all the records of a column.
diff --git a/addons/web/static/src/js/views/kanban/kanban_model.js b/addons/web/static/src/js/views/kanban/kanban_model.js
index bfb6f5e0cc9..8b1135d3f15 100644
--- a/addons/web/static/src/js/views/kanban/kanban_model.js
+++ b/addons/web/static/src/js/views/kanban/kanban_model.js
@@ -20,7 +20,7 @@ var KanbanModel = BasicModel.extend({
*
* @param {string} groupID localID of the group
* @param {integer} resId id of the record
- * @returns {Deferred<string>} resolves to the local id of the new record
+ * @returns {Promise<string>} resolves to the local id of the new record
*/
addRecordToGroup: function (groupID, resId) {
var self = this;
@@ -52,7 +52,7 @@ var KanbanModel = BasicModel.extend({
*
* @param {string} name
* @param {string} parentID localID of the parent of the group
- * @returns {Deferred<string>} resolves to the local id of the new group
+ * @returns {Promise<string>} resolves to the local id of the new group
*/
createGroup: function (name, parentID) {
var self = this;
@@ -60,7 +60,7 @@ var KanbanModel = BasicModel.extend({
var groupBy = parent.groupedBy[0];
var groupByField = parent.fields[groupBy];
if (!groupByField || groupByField.type !== 'many2one') {
- return $.Deferred().reject(); // only supported when grouped on m2o
+ return Promise.reject(); // only supported when grouped on m2o
}
return this._rpc({
model: groupByField.relation,
@@ -99,7 +99,7 @@ var KanbanModel = BasicModel.extend({
*
* @param {string} groupID
* @param {Object} values
- * @returns {Deferred} resolved with the local id of the created record
+ * @returns {Promise} resolved with the local id of the created record
*/
createRecordInGroup: function (groupID, values) {
var self = this;
@@ -187,7 +187,7 @@ var KanbanModel = BasicModel.extend({
* Opens a given group and loads its <limit> first records
*
* @param {string} groupID
- * @returns {Deferred}
+ * @returns {Promise}
*/
loadColumnRecords: function (groupID) {
var dataPoint = this.localData[groupID];
@@ -198,7 +198,7 @@ var KanbanModel = BasicModel.extend({
* Load more records in a group.
*
* @param {string} groupID localID of the group
- * @returns {Deferred<string>} resolves to the localID of the group
+ * @returns {Promise<string>} resolves to the localID of the group
*/
loadMore: function (groupID) {
var group = this.localData[groupID];
@@ -213,7 +213,7 @@ var KanbanModel = BasicModel.extend({
* @param {string} recordID localID of the record
* @param {string} groupID localID of the new group of the record
* @param {string} parentID localID of the parent
- * @returns {Deferred<string[]>} resolves to a pair [oldGroupID, newGroupID]
+ * @returns {Promise<string[]>} resolves to a pair [oldGroupID, newGroupID]
*/
moveRecord: function (recordID, groupID, parentID) {
var self = this;
@@ -330,7 +330,7 @@ var KanbanModel = BasicModel.extend({
/**
* @private
* @param {Object} dataPoint
- * @returns {Deferred<Object>}
+ * @returns {Promise<Object>}
*/
_readProgressBarGroup: function (list, options) {
var self = this;
@@ -345,7 +345,8 @@ var KanbanModel = BasicModel.extend({
context: list.context,
},
});
- return $.when(groupsDef, progressBarDef).then(function (a, data) {
+ return Promise.all([groupsDef, progressBarDef]).then(function (results) {
+ var data = results[1];
_.each(list.data, function (groupID) {
var group = self.localData[groupID];
group.progressBarValues = _.extend({
@@ -365,13 +366,13 @@ var KanbanModel = BasicModel.extend({
*
* @private
* @param {Object} list a list of groups
- * @returns {Deferred}
+ * @returns {Promise}
*/
_readTooltipFields: function (list) {
var self = this;
var groupedByField = list.fields[list.groupedBy[0].split(':')[0]];
if (groupedByField.type !== 'many2one') {
- return $.when();
+ return Promise.resolve();
}
var groupIds = _.reduce(list.data, function (groupIds, id) {
var res_id = self.get(id, {raw: true}).res_id;
@@ -400,16 +401,16 @@ var KanbanModel = BasicModel.extend({
});
});
}
- return $.when();
+ return Promise.resolve();
},
/**
- * Reloads all progressbar data. This is done after given deferred and
- * insures that the given deferred's result is not lost.
+ * Reloads all progressbar data. This is done after given promise and
+ * insures that the given promise's result is not lost.
*
* @private
* @param {string} recordID
- * @param {Deferred} def
- * @returns {Deferred}
+ * @param {Promise} def
+ * @returns {Promise}
*/
_reloadProgressBarGroupFromRecord: function (recordID, def) {
var element = this.localData[recordID];
diff --git a/addons/web/static/src/js/views/kanban/kanban_record.js b/addons/web/static/src/js/views/kanban/kanban_record.js
index 3dc1d6788bf..116de142b0c 100644
--- a/addons/web/static/src/js/views/kanban/kanban_record.js
+++ b/addons/web/static/src/js/views/kanban/kanban_record.js
@@ -62,7 +62,7 @@ var KanbanRecord = Widget.extend({
* @override
*/
start: function () {
- return $.when(this._super.apply(this, arguments), this._render());
+ return Promise.all([this._super.apply(this, arguments), this._render()]);
},
/**
* Called each time the record is attached to the DOM.
@@ -85,7 +85,7 @@ var KanbanRecord = Widget.extend({
* Re-renders the record with a new state
*
* @param {Object} state
- * @returns {Deferred}
+ * @returns {Promise}
*/
update: function (state) {
// detach the widgets because the record will empty its $el, which will
@@ -147,7 +147,7 @@ var KanbanRecord = Widget.extend({
}
if (typeof variable === 'string') {
var index = 0;
- for (var i = 0 ; i < variable.length ; i++) {
+ for (var i = 0; i < variable.length; i++) {
index += variable.charCodeAt(i);
}
return index % NB_KANBAN_RECORD_COLORS;
@@ -195,7 +195,7 @@ var KanbanRecord = Widget.extend({
field = options.preview_image;
var unique = this.record.__last_update && this.record.__last_update.value.replace(/[^0-9]/g, '');
var session = this.getSession();
- url = session.url('/web/image', {model: model, field: field, id: id, unique: unique});
+ url = session.url('/web/image', { model: model, field: field, id: id, unique: unique });
if (cache !== undefined) {
// Set the cache duration in seconds.
url += '&cache=' + parseInt(cache, 10);
@@ -300,6 +300,7 @@ var KanbanRecord = Widget.extend({
// field's widgets point of view
// that dict being shared between records, we don't modify it
// in place
+ var self = this;
var attrs = Object.create(null);
_.each(this.fieldsInfo[field_name], function (value, key) {
if (_.str.startsWith(key, 't-att-')) {
@@ -308,13 +309,13 @@ var KanbanRecord = Widget.extend({
}
attrs[key] = value;
});
- var options = _.extend({}, this.options, {attrs: attrs});
+ var options = _.extend({}, this.options, { attrs: attrs });
var widget = new Widget(this, field_name, this.state, options);
var def = widget.replace($field);
- if (def.state() === 'pending') {
- this.defs.push(def);
- }
- this._setFieldDisplay(widget.$el, field_name);
+ this.defs.push(def);
+ def.then(function () {
+ self._setFieldDisplay(widget.$el, field_name);
+ });
return widget;
},
_processWidgets: function () {
@@ -324,23 +325,23 @@ var KanbanRecord = Widget.extend({
var Widget = widgetRegistry.get($field.attr('name'));
var widget = new Widget(self, self.state);
- var def = widget._widgetRenderAndInsert(function () {});
- if (def.state() === 'pending') {
- self.defs.push(def);
- }
- widget.$el.addClass('o_widget');
- $field.replaceWith(widget.$el);
+ var def = widget._widgetRenderAndInsert(function () { });
+ self.defs.push(def);
+ def.then(function () {
+ $field.replaceWith(widget.$el);
+ widget.$el.addClass('o_widget');
+ });
});
},
/**
* Renders the record
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
this.defs = [];
this._replaceElement(this.qweb.render('kanban-box', this.qweb_context));
- this.$el.addClass('o_kanban_record').attr("tabindex",0);
+ this.$el.addClass('o_kanban_record').attr("tabindex", 0);
this.$el.attr('role', 'article');
this.$el.data('record', this);
if (this.$el.hasClass('oe_kanban_global_click') ||
@@ -357,9 +358,9 @@ var KanbanRecord = Widget.extend({
this._attachTooltip();
// We use boostrap tooltips for better and faster display
- this.$('span.o_tag').tooltip({delay: {'show': 50}});
+ this.$('span.o_tag').tooltip({ delay: { 'show': 50 } });
- return $.when.apply(this, this.defs);
+ return Promise.all(this.defs);
},
/**
* Sets particular classnames on a field $el according to the
@@ -419,7 +420,7 @@ var KanbanRecord = Widget.extend({
var colorHelp = _.str.sprintf(_t("Card color: %s"), this._getColorname(this.recordData[color_field]));
var colorClass = this._getColorClassname(this.recordData[color_field]);
this.$el.addClass(colorClass);
- this.$el.prepend('<span title="' + colorHelp + '" aria-label="' + colorHelp +'" role="img" class="oe_kanban_color_help"/>');
+ this.$el.prepend('<span title="' + colorHelp + '" aria-label="' + colorHelp + '" role="img" class="oe_kanban_color_help"/>');
}
},
/**
@@ -454,7 +455,7 @@ var KanbanRecord = Widget.extend({
r.raw_value = value.toDate();
} else if (r.type === 'one2many' || r.type === 'many2many') {
r.raw_value = value.count ? value.res_ids : [];
- } else if (r.type === 'many2one' ) {
+ } else if (r.type === 'many2one') {
r.raw_value = value && value.res_id || false;
} else {
r.raw_value = value;
@@ -554,13 +555,13 @@ var KanbanRecord = Widget.extend({
switch (type) {
case 'edit':
- this.trigger_up('open_record', {id: this.db_id, mode: 'edit'});
+ this.trigger_up('open_record', { id: this.db_id, mode: 'edit' });
break;
case 'open':
- this.trigger_up('open_record', {id: this.db_id});
+ this.trigger_up('open_record', { id: this.db_id });
break;
case 'delete':
- this.trigger_up('kanban_record_delete', {id: this.db_id, record: this});
+ this.trigger_up('kanban_record_delete', { id: this.db_id, record: this });
break;
case 'action':
case 'object':
diff --git a/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js b/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js
index 741cc6a898a..e69914acd49 100644
--- a/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js
+++ b/addons/web/static/src/js/views/kanban/kanban_record_quick_create.js
@@ -47,14 +47,14 @@ var RecordQuickCreate = Widget.extend({
*/
willStart: function () {
var self = this;
- var def1 = this._super.apply(this, arguments);
- var def2;
+ var superWillStart = this._super.apply(this, arguments);
+ var viewsLoaded;
if (this.formViewRef) {
var views = [[false, 'form']];
var context = _.extend({}, this.context, {
form_view_ref: this.formViewRef,
});
- def2 = this.loadViews(this.model, context, views);
+ viewsLoaded = this.loadViews(this.model, context, views);
} else {
var fieldsView = {};
fieldsView.arch = '<form>' +
@@ -65,9 +65,9 @@ var RecordQuickCreate = Widget.extend({
};
fieldsView.fields = fields;
fieldsView.viewFields = fields;
- def2 = $.when({form: fieldsView});
+ viewsLoaded = Promise.resolve({form: fieldsView});
}
- def2 = def2.then(function (fieldsViews) {
+ viewsLoaded = viewsLoaded.then(function (fieldsViews) {
var formView = new QuickCreateFormView(fieldsViews.form, {
context: self.context,
modelName: self.model,
@@ -78,7 +78,7 @@ var RecordQuickCreate = Widget.extend({
return self.controller.appendTo(document.createDocumentFragment());
});
});
- return $.when(def1, def2);
+ return Promise.all([superWillStart, viewsLoaded]);
},
/**
* @override
@@ -113,7 +113,7 @@ var RecordQuickCreate = Widget.extend({
* have been made yet
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
cancel: function () {
var self = this;
@@ -129,7 +129,6 @@ var RecordQuickCreate = Widget.extend({
//--------------------------------------------------------------------------
/**
- * @override
* @private
* @param {Object} [options]
* @param {boolean} [options.openRecord] set to true to directly open the
@@ -139,7 +138,7 @@ var RecordQuickCreate = Widget.extend({
var self = this;
if (this._disabled) {
// don't do anything if we are already creating a record
- return $.Deferred();
+ return;
}
// disable the widget to prevent the user from creating multiple records
// with the current values ; if the create works, the widget will be
@@ -157,13 +156,13 @@ var RecordQuickCreate = Widget.extend({
} else {
self._enableQuickCreate();
}
- }).fail(this._enableQuickCreate.bind(this));
+ }).guardedCatch(this._enableQuickCreate.bind(this));
},
/**
* Notifies the environment that the quick creation must be cancelled
*
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_cancel: function () {
this.trigger_up('cancel_quick_create');
diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer.js b/addons/web/static/src/js/views/kanban/kanban_renderer.js
index 252b4587af6..eda15f706d3 100644
--- a/addons/web/static/src/js/views/kanban/kanban_renderer.js
+++ b/addons/web/static/src/js/views/kanban/kanban_renderer.js
@@ -148,7 +148,7 @@ var KanbanRenderer = BasicRenderer.extend({
/**
* Displays the quick create record in the first column.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
addQuickCreate: function () {
return this.widgets[0].addQuickCreate();
@@ -187,7 +187,7 @@ var KanbanRenderer = BasicRenderer.extend({
* @param {boolean} [options.openQuickCreate] if true, directly opens the
* QuickCreate widget in the updated column
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
updateColumn: function (localID, columnState, options) {
var self = this;
@@ -204,7 +204,7 @@ var KanbanRenderer = BasicRenderer.extend({
if (options && options.openQuickCreate) {
def = newColumn.addQuickCreate();
}
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
newColumn.$el.insertAfter(column.$el);
self._toggleNoContentHelper();
// When a record has been quick created, the new column directly
@@ -221,7 +221,7 @@ var KanbanRenderer = BasicRenderer.extend({
* Updates a given record with its new state.
*
* @param {Object} recordState
- * @returns {Deferred}
+ * @returns {Promise}
*/
updateRecord: function (recordState) {
var isGrouped = !!this.state.groupedBy.length;
@@ -242,7 +242,7 @@ var KanbanRenderer = BasicRenderer.extend({
if (record) {
return record.update(recordState);
}
- return $.when();
+ return Promise.resolve();
},
/**
* @override
@@ -295,10 +295,13 @@ var KanbanRenderer = BasicRenderer.extend({
* @param {integer} nbDivs the number of divs to append
*/
_renderGhostDivs: function (fragment, nbDivs) {
+ var ghostDefs = [];
for (var $ghost, i = 0; i < nbDivs; i++) {
$ghost = $('<div>').addClass('o_kanban_record o_kanban_ghost');
- $ghost.appendTo(fragment);
+ var def = $ghost.appendTo(fragment);
+ ghostDefs.push(def);
}
+ return Promise.all(ghostDefs);
},
/**
* Renders an grouped kanban view in a fragment.
@@ -321,10 +324,7 @@ var KanbanRenderer = BasicRenderer.extend({
def = column.appendTo(fragment);
self.widgets.push(column);
}
- if (def.state() === 'pending') {
- self.defs.push(def);
- }
-
+ self.defs.push(def);
});
// remove previous sorting
@@ -359,13 +359,13 @@ var KanbanRenderer = BasicRenderer.extend({
this.quickCreate = new ColumnQuickCreate(this, {
examples: this.examples,
});
- this.quickCreate.appendTo(fragment).then(function () {
+ this.defs.push(this.quickCreate.appendTo(fragment).then(function () {
// Open it directly if there is no column yet
if (!self.state.data.length) {
self.quickCreate.toggleFold();
self._renderExampleBackground(fragment);
}
- });
+ }));
}
}
},
@@ -382,13 +382,14 @@ var KanbanRenderer = BasicRenderer.extend({
var kanbanRecord = new KanbanRecord(self, record, self.recordOptions);
self.widgets.push(kanbanRecord);
var def = kanbanRecord.appendTo(fragment);
- if (def.state() === 'pending') {
- self.defs.push(def);
- }
+ self.defs.push(def);
});
// append ghost divs to ensure that all kanban records are left aligned
- this._renderGhostDivs(fragment, 6);
+ var prom = Promise.all(self.defs).then(function () {
+ return self._renderGhostDivs(fragment, 6);
+ });
+ this.defs.push(prom);
},
/**
* @override
@@ -398,28 +399,31 @@ var KanbanRenderer = BasicRenderer.extend({
var self = this;
var oldWidgets = this.widgets;
this.widgets = [];
- this.$el.empty();
+ // render the kanban view
var isGrouped = !!this.state.groupedBy.length;
- this.$el.toggleClass('o_kanban_grouped', isGrouped);
- this.$el.toggleClass('o_kanban_ungrouped', !isGrouped);
var fragment = document.createDocumentFragment();
- // render the kanban view
- this.defs = [];
+ var defs = [];
+ this.defs = defs;
if (isGrouped) {
this._renderGrouped(fragment);
} else {
this._renderUngrouped(fragment);
}
- this.$el.append(fragment);
- this._toggleNoContentHelper();
- var defs = this.defs;
+ delete this.defs;
+
return this._super.apply(this, arguments).then(function () {
- _.invoke(oldWidgets, 'destroy');
- if (self._isInDom) {
- _.invoke(self.widgets, 'on_attach_callback');
- }
- return $.when.apply(null, defs);
+ return Promise.all(defs).then(function () {
+ self.$el.empty();
+ self.$el.toggleClass('o_kanban_grouped', isGrouped);
+ self.$el.toggleClass('o_kanban_ungrouped', !isGrouped);
+ self.$el.append(fragment);
+ self._toggleNoContentHelper();
+ _.invoke(oldWidgets, 'destroy');
+ if (self._isInDom) {
+ _.invoke(self.widgets, 'on_attach_callback');
+ }
+ });
});
},
/**
diff --git a/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js b/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js
index a9576e9836f..eae16968833 100644
--- a/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js
+++ b/addons/web/static/src/js/views/kanban/kanban_renderer_mobile.js
@@ -75,7 +75,7 @@ KanbanRenderer.include({
/**
* Displays the quick create record in the active column
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
addQuickCreate: function () {
return this.widgets[this.activeColumnIndex].addQuickCreate();
@@ -260,26 +260,26 @@ KanbanRenderer.include({
* @private
* @param {integer} moveToIndex index of the column to move to
* @param {boolean} [animate=false] set to true to animate
- * @returns {Deferred} resolved when the new current group has been loaded
+ * @returns {Promise} resolved when the new current group has been loaded
* and displayed
*/
_moveToGroup: function (moveToIndex, animate) {
var self = this;
if (moveToIndex < 0 || moveToIndex >= this.widgets.length) {
this._layoutUpdate(animate);
- return $.when();
+ return Promise.resolve();
}
- var def = $.Deferred();
this.activeColumnIndex = moveToIndex;
var column = this.widgets[this.activeColumnIndex];
- this.trigger_up('kanban_load_records', {
- columnID: column.db_id,
- onSuccess: function () {
- self._layoutUpdate(animate);
- def.resolve();
- },
+ return new Promise(function (resolve) {
+ self.trigger_up('kanban_load_records', {
+ columnID: column.db_id,
+ onSuccess: function () {
+ self._layoutUpdate(animate);
+ resolve();
+ },
+ });
});
- return def;
},
/**
@@ -287,22 +287,23 @@ KanbanRenderer.include({
* @private
*/
_renderGrouped: function (fragment) {
- var result = this._super.apply(this, arguments);
- var data = [];
- _.each(this.state.data, function (group) {
- if (!group.value) {
- group = _.extend({}, group, {value: _t('Undefined')});
- data.unshift(group);
- }
- else {
- data.push(group);
- }
- });
+ var self = this;
+ this._super.apply(this, arguments);
+ this.defs.push(Promise.all(this.defs).then(function () {
+ var data = [];
+ _.each(self.state.data, function (group) {
+ if (!group.value) {
+ group = _.extend({}, group, {value: _t('Undefined')});
+ data.unshift(group);
+ } else {
+ data.push(group);
+ }
+ });
- $(qweb.render('KanbanView.MobileTabs', {
- data: data,
- })).prependTo(fragment);
- return result;
+ $(qweb.render('KanbanView.MobileTabs', {
+ data: data,
+ })).prependTo(fragment);
+ }));
},
/**
diff --git a/addons/web/static/src/js/views/kanban/kanban_view.js b/addons/web/static/src/js/views/kanban/kanban_view.js
index 37f7fdd42ef..49ba9b74034 100644
--- a/addons/web/static/src/js/views/kanban/kanban_view.js
+++ b/addons/web/static/src/js/views/kanban/kanban_view.js
@@ -139,7 +139,7 @@ var KanbanView = BasicView.extend({
/**
* @private
* @param {Widget} parent
- * @returns {$.Promise} resolved when the searchPanel is ready
+ * @returns {Promise} resolved when the searchPanel is ready
*/
_createSearchPanel: function (parent) {
var self = this;
diff --git a/addons/web/static/src/js/views/kanban/quick_create_form_view.js b/addons/web/static/src/js/views/kanban/quick_create_form_view.js
index af769d62095..8725c3104de 100644
--- a/addons/web/static/src/js/views/kanban/quick_create_form_view.js
+++ b/addons/web/static/src/js/views/kanban/quick_create_form_view.js
@@ -71,7 +71,7 @@ var QuickCreateFormController = FormController.extend({
*/
commitChanges: function () {
var mutexDef = this.mutex.getUnlockedDef();
- return $.when(mutexDef, this.renderer.commitChanges(this.handle));
+ return Promise.all([mutexDef, this.renderer.commitChanges(this.handle)]);
},
/**
* @returns {Object} the changes done on the current record
diff --git a/addons/web/static/src/js/views/kanban/search_panel.js b/addons/web/static/src/js/views/kanban/search_panel.js
index b906d02b89a..d06eacbdb07 100644
--- a/addons/web/static/src/js/views/kanban/search_panel.js
+++ b/addons/web/static/src/js/views/kanban/search_panel.js
@@ -55,7 +55,7 @@ var SearchPanel = Widget.extend({
var loadProm = this._fetchCategories().then(function () {
return self._fetchFilters().then(self._applyDefaultFilterValues.bind(self));
});
- return $.when(loadProm, this._super.apply(this, arguments));
+ return Promise.all([loadProm, this._super.apply(this, arguments)]);
},
/**
* @override
@@ -82,18 +82,18 @@ var SearchPanel = Widget.extend({
*
* @param {Object} params
* @param {Array[]} params.searchDomain domain coming from controlPanel
- * @returns {$.Promise}
+ * @returns {Promise}
*/
update: function (params) {
var currentSearchDomainStr = JSON.stringify(this.searchDomain);
var newSearchDomainStr = JSON.stringify(params.searchDomain);
- var def;
+ var filtersProm;
if (this.needReload || (currentSearchDomainStr !== newSearchDomainStr)) {
this.needReload = false;
this.searchDomain = params.searchDomain;
- def = this._fetchFilters();
+ filtersProm = this._fetchFilters();
}
- return $.when(def).then(this._render.bind(this));
+ return Promise.resolve(filtersProm).then(this._render.bind(this));
},
//--------------------------------------------------------------------------
@@ -231,21 +231,21 @@ var SearchPanel = Widget.extend({
* Fetch values for each category. This is done only once, at startup.
*
* @private
- * @returns {$.Promise} resolved when all categories have been fetched
+ * @returns {Promise} resolved when all categories have been fetched
*/
_fetchCategories: function () {
var self = this;
- var defs = Object.keys(this.categories).map(function (categoryId) {
+ var proms = Object.keys(this.categories).map(function (categoryId) {
var category = self.categories[categoryId];
var field = self.fields[category.fieldName];
- var def;
+ var categoriesProm;
if (field.type === 'selection') {
var values = field.selection.map(function (value) {
return {id: value[0], display_name: value[1]};
});
- def = $.when(values);
+ categoriesProm = Promise.resolve(values);
} else {
- def = self._rpc({
+ categoriesProm = self._rpc({
method: 'search_panel_select_range',
model: self.model,
args: [category.fieldName],
@@ -254,18 +254,18 @@ var SearchPanel = Widget.extend({
return result.values;
});
}
- return def.then(function (values) {
+ return categoriesProm.then(function (values) {
self._createCategoryTree(categoryId, values);
});
});
- return $.when.apply($, defs);
+ return Promise.all(proms);
},
/**
* Fetch values for each filter. This is done at startup, and at each reload
* (when the controlPanel or searchPanel domain changes).
*
* @private
- * @returns {$.Promise} resolved when all filters have been fetched
+ * @returns {Promise} resolved when all filters have been fetched
*/
_fetchFilters: function () {
var self = this;
@@ -276,7 +276,7 @@ var SearchPanel = Widget.extend({
});
var categoryDomain = this._getCategoryDomain();
var filterDomain = this._getFilterDomain();
- var defs = Object.keys(this.filters).map(function (filterId) {
+ var proms = Object.keys(this.filters).map(function (filterId) {
var filter = self.filters[filterId];
return self._rpc({
method: 'search_panel_select_multi_range',
@@ -294,7 +294,7 @@ var SearchPanel = Widget.extend({
self._createFilterTree(filterId, values);
});
});
- return $.when.apply($, defs);
+ return Promise.all(proms);
},
/**
* Compute and return the domain based on the current active categories.
diff --git a/addons/web/static/src/js/views/list/list_controller.js b/addons/web/static/src/js/views/list/list_controller.js
index dfa7d272a49..055cd8177e3 100644
--- a/addons/web/static/src/js/views/list/list_controller.js
+++ b/addons/web/static/src/js/views/list/list_controller.js
@@ -65,7 +65,7 @@ var ListController = BasicController.extend({
* this method should be private, most of the code in the sidebar should be
* moved to the controller, and we should not use the getParent method...
*
- * @returns {Deferred<array[]>} a deferred that resolve to the active domain
+ * @returns {Promise<array[]>} a promise that resolve to the active domain
*/
getActiveDomain: function () {
// TODO: this method should be synchronous...
@@ -73,9 +73,9 @@ var ListController = BasicController.extend({
if (this.$('thead .o_list_record_selector input').prop('checked')) {
var searchQuery = this._controlPanel ? this._controlPanel.getSearchQuery() : {};
var record = self.model.get(self.handle, {raw: true});
- return $.when(record.getDomain().concat(searchQuery.domain || []));
+ return Promise.all(record.getDomain().concat(searchQuery.domain || []));
} else {
- return $.Deferred().resolve();
+ return Promise.resolve();
}
},
/*
@@ -143,6 +143,7 @@ var ListController = BasicController.extend({
* main buttons)
*
* @param {jQuery Node} $node
+ * @returns {Promise}
*/
renderSidebar: function ($node) {
var self = this;
@@ -180,10 +181,11 @@ var ListController = BasicController.extend({
},
actions: _.extend(this.toolbarActions, {other: other}),
});
- this.sidebar.appendTo($node);
-
- this._toggleSidebar();
+ return this.sidebar.appendTo($node).then(function() {
+ self._toggleSidebar();
+ });
}
+ return Promise.resolve();
},
/**
* Overrides to update the list of selected records
@@ -243,10 +245,11 @@ var ListController = BasicController.extend({
});
}).then(function (recordID) {
var state = self.model.get(self.handle);
- self.renderer.updateState(state, {});
- self.renderer.editRecord(recordID);
- self._updatePager();
- }).always(this._enableButtons.bind(this));
+ self.renderer.updateState(state, {})
+ .then(function () {
+ self.renderer.editRecord(recordID);
+ }).then(self._updatePager.bind(self));
+ }).then(this._enableButtons.bind(this)).guardedCatch(this._enableButtons.bind(this));
},
/**
* Archive the current selection
@@ -254,11 +257,11 @@ var ListController = BasicController.extend({
* @private
* @param {string[]} ids
* @param {boolean} archive
- * @returns {Deferred}
+ * @returns {Promise}
*/
_archive: function (ids, archive) {
if (ids.length === 0) {
- return $.when();
+ return Promise.resolve();
}
return this.model
.toggleActive(ids, !archive, this.handle)
@@ -298,7 +301,7 @@ var ListController = BasicController.extend({
* @override
* @param {string} id a basicmodel valid resource handle. It is supposed to
* be a record from the list view.
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmSave: function (id) {
var state = this.model.get(this.handle);
@@ -313,13 +316,13 @@ var ListController = BasicController.extend({
* @override
* @private
* @param {string} [recordID] - default to main recordID
- * @returns {Deferred}
+ * @returns {Promise}
*/
_discardChanges: function (recordID) {
if ((recordID || this.handle) === this.handle) {
recordID = this.renderer.getEditableRecordID();
if (recordID === null) {
- return $.when();
+ return Promise.resolve();
}
}
var self = this;
@@ -343,7 +346,7 @@ var ListController = BasicController.extend({
* @private
* @param {string} mode
* @param {string} [recordID] - default to main recordID
- * @returns {Deferred}
+ * @returns {Promise}
*/
_setMode: function (mode, recordID) {
if ((recordID || this.handle) !== this.handle) {
@@ -373,11 +376,13 @@ var ListController = BasicController.extend({
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
_update: function () {
- this._toggleSidebar();
- return this._super.apply(this, arguments);
+ var self = this;
+ return this._super.apply(this, arguments).then(function() {
+ self._toggleSidebar();
+ });
},
/**
* This helper simply makes sure that the control panel buttons matches the
@@ -471,7 +476,7 @@ var ListController = BasicController.extend({
var record = self.model.get(self.handle);
var editedRecord = record.data[ev.data.index];
self._setMode('edit', editedRecord.id)
- .done(ev.data.onSuccess);
+ .then(ev.data.onSuccess);
},
});
},
@@ -523,8 +528,8 @@ var ListController = BasicController.extend({
_onSaveLine: function (ev) {
var recordID = ev.data.recordID;
this.saveRecord(recordID)
- .done(ev.data.onSuccess)
- .fail(ev.data.onFailure);
+ .then(ev.data.onSuccess)
+ .guardedCatch(ev.data.onFailure);
},
/**
* When the current selection changes (by clicking on the checkboxes on the
diff --git a/addons/web/static/src/js/views/list/list_editable_renderer.js b/addons/web/static/src/js/views/list/list_editable_renderer.js
index ab5e5036dfa..4619cb86e66 100644
--- a/addons/web/static/src/js/views/list/list_editable_renderer.js
+++ b/addons/web/static/src/js/views/list/list_editable_renderer.js
@@ -93,7 +93,7 @@ ListRenderer.include({
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
// deliberately use the 'editable' attribute instead of '_isEditable'
@@ -171,7 +171,7 @@ ListRenderer.include({
* @param {string} id
* @param {string[]} fields
* @param {OdooEvent} ev
- * @returns {Deferred<AbstractField[]>} resolved with the list of widgets
+ * @returns {Promise<AbstractField[]>} resolved with the list of widgets
* that have been reset
*/
confirmUpdate: function (state, id, fields, ev) {
@@ -180,7 +180,7 @@ ListRenderer.include({
// store the cursor position to restore it once potential onchanges have
// been applied
var currentRowID, currentWidget, focusedElement, selectionRange;
- if (self.currentRow !== null) {
+ if (this.currentRow !== null) {
currentRowID = this.state.data[this.currentRow].id;
currentWidget = this.allFieldWidgets[currentRowID][this.currentFieldIndex];
if (currentWidget) {
@@ -212,10 +212,14 @@ ListRenderer.include({
});
var newRowIndex = _.findIndex(state.data, {id: id});
var $lastRow = $row;
- _.each(state.data, function (record, index) {
+ var defs = [];
+ self.defs = defs;
+ state.data.forEach(function (record, index) {
if (index === newRowIndex) {
return;
}
+ // FIXME: as we are manipulating the DOM directly, it will
+ // flicker if there is an async widget in the row
var $newRow = self._renderRow(record);
if (index < newRowIndex) {
$newRow.insertBefore($row);
@@ -224,20 +228,23 @@ ListRenderer.include({
$lastRow = $newRow;
}
});
- if (self.currentRow !== null) {
- self.currentRow = newRowIndex;
- return self._selectCell(newRowIndex, self.currentFieldIndex, {force: true}).then(function () {
- // restore the cursor position
- currentRowID = self.state.data[newRowIndex].id;
- currentWidget = self.allFieldWidgets[currentRowID][self.currentFieldIndex];
- if (currentWidget) {
- focusedElement = currentWidget.getFocusableElement().get(0);
- if (selectionRange) {
- dom.setSelectionRange(focusedElement, selectionRange);
- }
+ delete self.defs;
+ return Promise.all(defs).then(function () {
+ if (self.currentRow !== null) {
+ self.currentRow = newRowIndex;
+ return self._selectCell(newRowIndex, self.currentFieldIndex, {force: true});
+ }
+ }).then(function () {
+ // restore the cursor position
+ currentRowID = self.state.data[newRowIndex].id;
+ currentWidget = self.allFieldWidgets[currentRowID][self.currentFieldIndex];
+ if (currentWidget) {
+ focusedElement = currentWidget.getFocusableElement().get(0);
+ if (selectionRange) {
+ dom.setSelectionRange(focusedElement, selectionRange);
}
- });
- }
+ }
+ });
});
},
/**
@@ -294,7 +301,7 @@ ListRenderer.include({
*
* @param {string} recordID
* @param {string} mode
- * @returns {Deferred}
+ * @returns {Promise}
*/
setRowMode: function (recordID, mode) {
var self = this;
@@ -321,7 +328,7 @@ ListRenderer.include({
}
if (rowIndex < 0) {
- return $.when();
+ return Promise.resolve();
}
var editMode = (mode === 'edit');
@@ -350,7 +357,7 @@ ListRenderer.include({
options.mode = editMode ? 'edit' : 'readonly';
// Switch each cell to the new mode; note: the '_renderBodyCell'
- // function might fill the 'this.defs' variables with multiple deferred
+ // function might fill the 'this.defs' variables with multiple promise
// so we create the array and delete it after the rendering.
var defs = [];
this.defs = defs;
@@ -385,7 +392,7 @@ ListRenderer.include({
$row.toggleClass('o_selected_row', editMode);
$row.find('.o_list_record_selector input').prop('disabled', !record.res_id);
- return $.when.apply($, defs).then(function () {
+ return Promise.all(defs).then(function () {
// necessary to trigger resize on fieldtexts
core.bus.trigger('DOM_updated');
});
@@ -399,27 +406,32 @@ ListRenderer.include({
* prevent subsequent editions. These edits would be lost, because the list
* view only saves records when unselecting a row.
*
- * @returns {Deferred} The deferred resolves if the row was unselected (and
+ * @returns {Promise} The promise resolves if the row was unselected (and
* possibly removed). If may be rejected, when the row is dirty and the
* user refuses to discard its changes.
*/
unselectRow: function () {
+ var self = this;
// Protect against calling this method when no row is selected
if (this.currentRow === null) {
- return $.when();
+ return Promise.resolve();
}
var record = this.state.data[this.currentRow];
var recordWidgets = this.allFieldWidgets[record.id];
toggleWidgets(true);
- var def = $.Deferred();
- this.trigger_up('save_line', {
- recordID: record.id,
- onSuccess: def.resolve.bind(def),
- onFailure: def.reject.bind(def),
+ var prom = new Promise(function (resolve, reject) {
+ self.trigger_up('save_line', {
+ recordID: record.id,
+ onSuccess: resolve,
+ onFailure: reject,
+ });
});
- return def.fail(toggleWidgets.bind(null, false));
+ prom.guardedCatch(function() {
+ toggleWidgets(false);
+ });
+ return prom;
function toggleWidgets(disabled) {
_.each(recordWidgets, function (widget) {
@@ -511,7 +523,7 @@ ListRenderer.include({
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
this.currentRow = null;
@@ -524,10 +536,9 @@ ListRenderer.include({
* widget.
*
* @override
- * @returns {jQueryElement}
*/
_renderBody: function () {
- var $body = this._super();
+ var $body = this._super.apply(this, arguments);
if (this.hasHandle) {
$body.sortable({
axis: 'y',
@@ -568,15 +579,13 @@ ListRenderer.include({
* on the first real column.
*
* @override
- * @returns {jQueryElement}
+ * @returns {jQueryElement[]}
*/
_renderRows: function () {
- var self = this;
var $rows = this._super();
-
if (this.addCreateLine) {
var $tr = $('<tr>');
- var colspan = self._getNumberOfCols();
+ var colspan = this._getNumberOfCols();
if (this.handleField) {
colspan = colspan - 1;
@@ -589,7 +598,7 @@ ListRenderer.include({
$tr.append($td);
$rows.push($tr);
- _.each(self.creates, function (create, index) {
+ _.each(this.creates, function (create, index) {
var $a = $('<a href="#" role="button">')
.attr('data-context', create.context)
.text(create.string);
@@ -604,7 +613,7 @@ ListRenderer.include({
/**
* @override
* @private
- * @returns {Deferred} this deferred is resolved immediately
+ * @returns {Promise} this promise is resolved immediately
*/
_renderView: function () {
var self = this;
@@ -692,13 +701,13 @@ ListRenderer.include({
* @param {boolean} [options.force=false] if true, force selecting the cell
* even if seems to be already the selected one (useful after a re-
* rendering, to reset the focus on the correct field)
- * @return {Deferred} fails if no cell could be selected
+ * @return {Promise} fails if no cell could be selected
*/
_selectCell: function (rowIndex, fieldIndex, options) {
options = options || {};
// Do nothing if the user tries to select current cell
if (!options.force && rowIndex === this.currentRow && fieldIndex === this.currentFieldIndex) {
- return $.when();
+ return Promise.resolve();
}
var wrap = options.wrap === undefined ? true : options.wrap;
@@ -707,7 +716,7 @@ ListRenderer.include({
return this._selectRow(rowIndex).then(function () {
var record = self.state.data[rowIndex];
if (fieldIndex >= (self.allFieldWidgets[record.id] || []).length) {
- return $.Deferred().reject();
+ return Promise.reject();
}
// _activateFieldWidget might trigger an onchange,
// which requires currentFieldIndex to be set
@@ -721,7 +730,7 @@ ListRenderer.include({
});
if (fieldIndex < 0) {
self.currentFieldIndex = oldFieldIndex;
- return $.Deferred().reject();
+ return Promise.reject();
}
self.currentFieldIndex = fieldIndex;
});
@@ -730,12 +739,12 @@ ListRenderer.include({
* Activates the row at the given row index.
*
* @param {integer} rowIndex
- * @returns {Deferred}
+ * @returns {Promise}
*/
_selectRow: function (rowIndex) {
// Do nothing if already selected
if (rowIndex === this.currentRow) {
- return $.when();
+ return Promise.resolve();
}
// To select a row, the currently selected one must be unselected first
@@ -745,15 +754,15 @@ ListRenderer.include({
// The row to selected doesn't exist anymore (probably because
// an onchange triggered when unselecting the previous one
// removes rows)
- return $.Deferred().reject();
+ return Promise.reject();
}
// Notify the controller we want to make a record editable
- var def = $.Deferred();
- self.trigger_up('edit_line', {
- index: rowIndex,
- onSuccess: def.resolve.bind(def),
+ return new Promise(function (resolve) {
+ self.trigger_up('edit_line', {
+ index: rowIndex,
+ onSuccess: resolve,
+ });
});
- return def;
});
},
@@ -778,7 +787,7 @@ ListRenderer.include({
// but we do want to unselect current row
var self = this;
this.unselectRow().then(function () {
- self.trigger_up('add_record', {context: ev.currentTarget.dataset.context && [ev.currentTarget.dataset.context]}); // TODO write a test, the deferred was not considered
+ self.trigger_up('add_record', {context: ev.currentTarget.dataset.context && [ev.currentTarget.dataset.context]}); // TODO write a test, the promise was not considered
});
},
/**
@@ -864,12 +873,13 @@ ListRenderer.include({
* @param {OdooEvent} ev
*/
_onNavigationMove: function (ev) {
+ var self = this;
ev.stopPropagation(); // stop the event, the action is done by this renderer
switch (ev.data.direction) {
case 'previous':
if (this.currentFieldIndex > 0) {
this._selectCell(this.currentRow, this.currentFieldIndex - 1, {wrap: false})
- .fail(this._moveToPreviousLine.bind(this));
+ .guardedCatch(this._moveToPreviousLine.bind(this));
} else {
this._moveToPreviousLine();
}
@@ -882,7 +892,7 @@ ListRenderer.include({
if (column.attrs.name === lastWidget.name) {
if (this.currentRow + 1 < this.state.data.length) {
this._selectCell(this.currentRow+1, 0, {wrap:false})
- .fail(this._moveToNextLine.bind(this));
+ .guardedCatch(this._moveToNextLine.bind(this));
} else {
var currentRowData = this.state.data[this.currentRow];
if (currentRowData.isDirty(currentRowData.id)) {
@@ -895,7 +905,7 @@ ListRenderer.include({
} else {
if (this.currentFieldIndex + 1 < this.columns.length) {
this._selectCell(this.currentRow, this.currentFieldIndex + 1, {wrap: false})
- .fail(this._moveToNextLine.bind(this));
+ .guardedCatch(this._moveToNextLine.bind(this));
} else {
this._moveToNextLine();
}
@@ -911,8 +921,10 @@ ListRenderer.include({
ev.data.originalEvent.stopPropagation();
this.trigger_up('discard_changes', {
recordID: ev.target.dataPointID,
+ onSuccess: function () {
+ self.$('.o_field_x2many_list_row_add a:first').focus();
+ }
});
- this.$('.o_field_x2many_list_row_add a:first').focus();
break;
}
},
diff --git a/addons/web/static/src/js/views/list/list_renderer.js b/addons/web/static/src/js/views/list/list_renderer.js
index ee081aa3c5b..760ab9ed7a8 100644
--- a/addons/web/static/src/js/views/list/list_renderer.js
+++ b/addons/web/static/src/js/views/list/list_renderer.js
@@ -250,9 +250,10 @@ var ListRenderer = BasicRenderer.extend({
* @returns {jQueryElement} a jquery element <tbody>
*/
_renderBody: function () {
+ var self = this;
var $rows = this._renderRows();
while ($rows.length < 4) {
- $rows.push(this._renderEmptyRow());
+ $rows.push(self._renderEmptyRow());
}
return $('<tbody>').append($rows);
},
@@ -306,7 +307,6 @@ var ListRenderer = BasicRenderer.extend({
}
if (node.attrs.widget || (options && options.renderWidgets)) {
var $el = this._renderFieldWidget(node, record, _.pick(options, 'mode'));
- this._handleAttributes($el, node);
return $td.append($el);
}
var name = node.attrs.name;
@@ -395,7 +395,7 @@ var ListRenderer = BasicRenderer.extend({
*
* @private
* @param {Object} group
- * @returns {JQueryElement} the pager's $el
+ * @returns {jQueryElement} the pager's $el
*/
_renderGroupPager: function (group) {
var pager = new Pager(this, group.count, group.offset + 1, group.limit);
@@ -416,9 +416,14 @@ var ListRenderer = BasicRenderer.extend({
// register the pager so that it can be destroyed on next rendering
this.pagers.push(pager);
- var fragment = document.createDocumentFragment();
- pager.appendTo(fragment); // starts the pager
- return pager.$el;
+ var pagerProm = pager._widgetRenderAndInsert(function () {}); // start the pager
+ this.defs.push(pagerProm);
+ var $el = $('<div>');
+ pagerProm.then(function () {
+ $el.replaceWith(pager.$el);
+ });
+
+ return $el;
},
/**
* Render the row that represent a group
@@ -514,10 +519,9 @@ var ListRenderer = BasicRenderer.extend({
* with the name of each fields
*
* @private
- * @param {boolean} isGrouped
* @returns {jQueryElement} a <thead> element
*/
- _renderHeader: function (isGrouped) {
+ _renderHeader: function () {
var $tr = $('<tr>')
.append(_.map(this.columns, this._renderHeaderCell.bind(this)));
if (this.hasSelectors) {
@@ -585,11 +589,9 @@ var ListRenderer = BasicRenderer.extend({
*/
_renderRow: function (record) {
var self = this;
- this.defs = []; // TODO maybe wait for those somewhere ?
- var $cells = _.map(this.columns, function (node, index) {
+ var $cells = this.columns.map(function (node, index) {
return self._renderBodyCell(record, node, index, { mode: 'readonly' });
});
- delete this.defs;
var $tr = $('<tr/>', { class: 'o_data_row' })
.data('id', record.id)
@@ -608,7 +610,7 @@ var ListRenderer = BasicRenderer.extend({
* @returns {jQueryElement[]} a list of <tr>
*/
_renderRows: function () {
- return _.map(this.state.data, this._renderRow.bind(this));
+ return this.state.data.map(this._renderRow.bind(this));
},
/**
* A 'selector' is the small checkbox on the left of a record in a list
@@ -638,52 +640,60 @@ var ListRenderer = BasicRenderer.extend({
*
* @override
* @private
- * returns {Deferred} this deferred is resolved immediately
+ * @returns {Promise} resolved when the view has been rendered
*/
_renderView: function () {
var self = this;
- this.$el
- .removeClass('table-responsive')
- .empty();
-
- // destroy the previously instantiated pagers, if any
- _.invoke(this.pagers, 'destroy');
+ var oldPagers = this.pagers;
this.pagers = [];
- var displayNoContentHelper = !this._hasContent() && !!this.noContentHelp;
// display the no content helper if there is no data to display
+ var displayNoContentHelper = !this._hasContent() && !!this.noContentHelp;
if (displayNoContentHelper) {
+ // destroy the previously instantiated pagers, if any
+ _.invoke(oldPagers, 'destroy');
+
+ this.$el.removeClass('table-responsive');
this.$el.html(this._renderNoContentHelper());
- return this._super();
+ return this._super.apply(this, arguments);
}
- var $table = $('<table>').addClass('o_list_view table table-sm table-hover table-striped');
- this.$el.addClass('table-responsive')
- .append($table);
+ var orderedBy = this.state.orderedBy;
+ this.hasHandle = orderedBy.length === 0 || orderedBy[0].name === this.handleField;
this._computeAggregates();
+
+ var $table = $('<table>').addClass('o_list_view table table-sm table-hover table-striped');
$table.toggleClass('o_list_view_grouped', this.isGrouped);
$table.toggleClass('o_list_view_ungrouped', !this.isGrouped);
- this.hasHandle = this.state.orderedBy.length === 0 ||
- this.state.orderedBy[0].name === this.handleField;
+ var defs = [];
+ this.defs = defs;
if (this.isGrouped) {
- $table
- .append(this._renderHeader(true))
- .append(this._renderGroups(this.state.data))
- .append(this._renderFooter());
+ $table.append(this._renderHeader());
+ $table.append(this._renderGroups(this.state.data));
+ $table.append(this._renderFooter());
+
} else {
- $table
- .append(this._renderHeader())
- .append(this._renderBody())
- .append(this._renderFooter());
- }
- if (this.selection.length) {
- var $checked_rows = this.$('tr').filter(function (index, el) {
- return _.contains(self.selection, $(el).data('id'));
- });
- $checked_rows.find('.o_list_record_selector input').prop('checked', true);
+ $table.append(this._renderHeader());
+ $table.append(this._renderBody());
+ $table.append(this._renderFooter());
}
- return this._super();
+ delete this.defs;
+
+ var prom = Promise.all(defs).then(function () {
+ // destroy the previously instantiated pagers, if any
+ _.invoke(oldPagers, 'destroy');
+
+ self.$el.addClass('table-responsive').html($table);
+
+ if (self.selection.length) {
+ var $checked_rows = self.$('tr').filter(function (index, el) {
+ return _.contains(self.selection, $(el).data('id'));
+ });
+ $checked_rows.find('.o_list_record_selector input').prop('checked', true);
+ }
+ });
+ return Promise.all([this._super.apply(this, arguments), prom]);
},
/**
* Each line can be decorated according to a few simple rules. The arch
diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js
index 3f195c1ea24..a4a2bae8fb0 100644
--- a/addons/web/static/src/js/views/pivot/pivot_model.js
+++ b/addons/web/static/src/js/views/pivot/pivot_model.js
@@ -45,10 +45,10 @@ var PivotModel = AbstractModel.extend({
/**
* Close a header. This method is actually synchronous, but returns a
- * deferred.
+ * promise.
*
* @param {any} headerID
- * @returns {Deferred}
+ * @returns {Promise}
*/
closeHeader: function (headerID) {
var header = this.data.headers[headerID];
@@ -58,7 +58,7 @@ var PivotModel = AbstractModel.extend({
header.root.groupbys.splice(newGroupbyLength);
},
/**
- * @returns {Deferred}
+ * @returns {Promise}
*/
expandAll: function () {
return this._loadData();
@@ -118,8 +118,8 @@ var PivotModel = AbstractModel.extend({
});
}));
}
- return $.when.apply(null, defs).then(function () {
- var results = Array.prototype.slice.call(arguments);
+ return Promise.all(defs).then(function () {
+ var results = Array.prototype.slice.call(arguments[0]);
var data = [];
var comparisonData = [];
_.each(results, function (result) {
@@ -358,7 +358,7 @@ var PivotModel = AbstractModel.extend({
* @param {string[]} params.compare
* @param {Object} params.fields
* @param {string} params.default_order
- * @returns {Deferred}
+ * @returns {Promise}
*/
load: function (params) {
var self = this;
@@ -394,7 +394,7 @@ var PivotModel = AbstractModel.extend({
* @override
* @param {any} handle this parameter is ignored
* @param {Object} params
- * @returns {Deferred}
+ * @returns {Promise}
*/
reload: function (handle, params) {
var self = this;
@@ -507,14 +507,14 @@ var PivotModel = AbstractModel.extend({
* Toggle the active state for a given measure, then reload the data.
*
* @param {string} field
- * @returns {Deferred}
+ * @returns {Promise}
*/
toggleMeasure: function (field) {
if (_.contains(this.data.measures, field)) {
this.data.measures = _.without(this.data.measures, field);
// in this case, we already have all data in memory, no need to
// actually reload a lesser amount of information
- return $.when();
+ return Promise.resolve();
} else {
this.data.measures.push(field);
}
@@ -705,7 +705,7 @@ var PivotModel = AbstractModel.extend({
return result;
},
/**
- * @returns {Deferred}
+ * @returns {Promise}
*/
_loadData: function () {
var self = this;
@@ -755,8 +755,7 @@ var PivotModel = AbstractModel.extend({
}));
}
- return this._loadDataDropPrevious.add($.when.apply(null, defs)).then(function () {
- var results = Array.prototype.slice.call(arguments);
+ return this._loadDataDropPrevious.add(Promise.all(defs)).then(function (results) {
var data = [];
var comparisonData = [];
_.each(results, function (result) {
diff --git a/addons/web/static/src/js/views/pivot/pivot_renderer.js b/addons/web/static/src/js/views/pivot/pivot_renderer.js
index 1a3c451f064..101f3734392 100644
--- a/addons/web/static/src/js/views/pivot/pivot_renderer.js
+++ b/addons/web/static/src/js/views/pivot/pivot_renderer.js
@@ -72,7 +72,7 @@ var PivotRenderer = AbstractRenderer.extend({
/**
* @override
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_render: function () {
if (!this._hasContent()) {
diff --git a/addons/web/static/src/js/views/standalone_field_manager_mixin.js b/addons/web/static/src/js/views/standalone_field_manager_mixin.js
index da3cc19350d..501ecf7c012 100644
--- a/addons/web/static/src/js/views/standalone_field_manager_mixin.js
+++ b/addons/web/static/src/js/views/standalone_field_manager_mixin.js
@@ -38,7 +38,7 @@ var StandaloneFieldManagerMixin = _.extend({}, FieldManagerMixin, {
* @param {string} id basicModel Id for the changed record
* @param {string[]} fields the fields (names) that have been changed
* @param {OdooEvent} event the event that triggered the change
- * @returns {Deferred}
+ * @returns {Promise}
*/
_confirmChange: function (id, fields, event) {
var result = FieldManagerMixin._confirmChange.apply(this, arguments);
diff --git a/addons/web/static/src/js/views/view_dialogs.js b/addons/web/static/src/js/views/view_dialogs.js
index befe4247c00..75be3a3d07e 100644
--- a/addons/web/static/src/js/views/view_dialogs.js
+++ b/addons/web/static/src/js/views/view_dialogs.js
@@ -128,7 +128,7 @@ var FormViewDialog = ViewDialog.extend({
text: (multi_select ? _t("Save & Close") : _t("Save")),
classes: "btn-primary",
click: function () {
- this._save().then(self.close.bind(self));
+ self._save().then(self.close.bind(self));
}
});
@@ -137,7 +137,7 @@ var FormViewDialog = ViewDialog.extend({
text: _t("Save & New"),
classes: "btn-primary",
click: function () {
- this._save()
+ self._save()
.then(self.form_view.createRecord.bind(self.form_view, self.parentID))
.then(function () {
if (!self.deletable) {
@@ -183,7 +183,7 @@ var FormViewDialog = ViewDialog.extend({
var FormView = view_registry.get('form');
var fields_view_def;
if (this.options.fields_view) {
- fields_view_def = $.when(this.options.fields_view);
+ fields_view_def = Promise.resolve(this.options.fields_view);
} else {
fields_view_def = this.loadFieldView(this.res_model, this.context, this.options.view_id, 'form');
}
@@ -213,9 +213,9 @@ var FormViewDialog = ViewDialog.extend({
if (self.recordID && self.shouldSaveLocally) {
self.model.save(self.recordID, {savePoint: true});
}
- self.form_view.appendTo(fragment)
+ return self.form_view.appendTo(fragment)
.then(function () {
- self.opened().always(function () {
+ self.opened().then(function () {
var $buttons = $('<div>');
self.form_view.renderButtons($buttons);
if ($buttons.children().length) {
@@ -226,7 +226,7 @@ var FormViewDialog = ViewDialog.extend({
in_DOM: true,
});
});
- _super();
+ return _super();
});
});
@@ -255,7 +255,7 @@ var FormViewDialog = ViewDialog.extend({
/**
* @private
- * @returns {Deferred}
+ * @returns {Promise}
*/
_save: function () {
var self = this;
@@ -332,7 +332,7 @@ var SelectCreateDialog = ViewDialog.extend({
}
var self = this;
var _super = this._super.bind(this);
- this.loadViews(this.res_model, this.context, [[false, 'list'], [false, 'search']], {})
+ return this.loadViews(this.res_model, this.context, [[false, 'list'], [false, 'search']], {})
.then(this.setup.bind(this))
.then(function (fragment) {
self.opened().then(function () {
@@ -342,9 +342,8 @@ var SelectCreateDialog = ViewDialog.extend({
});
self.set_buttons(self.__buttons);
});
- _super();
+ return _super();
});
- return this;
},
setup: function (fieldsViews) {
diff --git a/addons/web/static/src/js/views/view_utils.js b/addons/web/static/src/js/views/view_utils.js
index 94485c1401a..ea2270ce466 100644
--- a/addons/web/static/src/js/views/view_utils.js
+++ b/addons/web/static/src/js/views/view_utils.js
@@ -63,7 +63,7 @@ var viewUtils = {
*/
renderButtonFromNode: function (node, options) {
var btnOptions = {
- attrs: _.omit(node.attrs, 'icon', 'string', 'type', 'attrs', 'modifiers', 'options'),
+ attrs: _.omit(node.attrs, 'icon', 'string', 'type', 'attrs', 'modifiers', 'options', 'effect'),
icon: node.attrs.icon,
};
if (options && options.extraClass) {
diff --git a/addons/web/static/src/js/widgets/attach_document.js b/addons/web/static/src/js/widgets/attach_document.js
index 13496f3aea7..3175875c151 100644
--- a/addons/web/static/src/js/widgets/attach_document.js
+++ b/addons/web/static/src/js/widgets/attach_document.js
@@ -108,26 +108,27 @@ var AttachDocument = Widget.extend({
* @private
*/
_onFileLoaded: function () {
- var self = this,
- def = $.Deferred();
-
- if (self.node.attrs.action) {
- // the first argument isn't a file but the jQuery.Event
- var files = Array.prototype.slice.call(arguments, 1);
- self._rpc({
- model: self.res_model,
- method: self.node.attrs.action,
- args: [self.res_id],
- kwargs: {
- 'attachment_ids': _.map(files, function (file) {return file.id;}),
- }
- }).then( function () {
- def.resolve();
- });
- } else {
- def.resolve();
- }
- return $.when(def).then(function () {
+ var self = this;
+ return new Promise(function (resolve) {
+ if (self.node.attrs.action) {
+ // the first argument isn't a file but the jQuery.Event
+ var files = Array.prototype.slice.call(arguments, 1);
+ self._rpc({
+ model: self.res_model,
+ method: self.node.attrs.action,
+ args: [self.res_id],
+ kwargs: {
+ attachment_ids: _.map(files, function (file) {
+ return file.id;
+ }),
+ }
+ }).then(function () {
+ resolve();
+ });
+ } else {
+ resolve();
+ }
+ }).then(function () {
self.trigger_up('reload');
framework.unblockUI();
});
diff --git a/addons/web/static/src/js/widgets/change_password.js b/addons/web/static/src/js/widgets/change_password.js
index c05fa30408b..e75d8dfda38 100644
--- a/addons/web/static/src/js/widgets/change_password.js
+++ b/addons/web/static/src/js/widgets/change_password.js
@@ -20,7 +20,7 @@ var ChangePassword = AbstractAction.extend({
* @fixme: weird interaction with the parent for the $buttons handling
*
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
var self = this;
@@ -37,7 +37,7 @@ var ChangePassword = AbstractAction.extend({
fields: $('form[name=change_password_form]').serializeArray()
}
})
- .done(function (result) {
+ .then(function (result) {
if (result.error) {
self._display_error(result);
} else {
diff --git a/addons/web/static/src/js/widgets/data_export.js b/addons/web/static/src/js/widgets/data_export.js
index e24818f7336..a913fcd0ea2 100644
--- a/addons/web/static/src/js/widgets/data_export.js
+++ b/addons/web/static/src/js/widgets/data_export.js
@@ -56,7 +56,7 @@ var DataExport = Dialog.extend({
*/
start: function () {
var self = this;
- var defs = [this._super.apply(this, arguments)];
+ var proms = [this._super.apply(this, arguments)];
// The default for the ".modal_content" element is "max-height: 100%;"
// but we want it to always expand to "height: 100%;" for this modal.
@@ -67,10 +67,10 @@ var DataExport = Dialog.extend({
this.$fieldsList = this.$('.o_fields_list');
this.$importCompatRadios = this.$('.o_import_compat input');
- defs.push(this._rpc({route: '/web/export/formats'}).then(doSetupExportFormats));
- defs.push(this._onChangeCompatibleInput());
+ proms.push(this._rpc({route: '/web/export/formats'}).then(doSetupExportFormats));
+ proms.push(this._onChangeCompatibleInput());
- defs.push(this.getParent().getActiveDomain().then(function (domain) {
+ proms.push(this.getParent().getActiveDomain().then(function (domain) {
if (domain === undefined) {
self.idsToExport = self.getParent().getSelectedIds();
self.domain = self.record.domain;
@@ -80,7 +80,7 @@ var DataExport = Dialog.extend({
}
}));
- defs.push(this._showExportsList().then(function () {
+ proms.push(this._showExportsList().then(function () {
_.each(self.records, function (record, key) {
if (_.contains(self.defaultExportFields, key)) {
self._addField(key, record.string);
@@ -88,12 +88,12 @@ var DataExport = Dialog.extend({
});
}));
- return $.when.apply($, defs);
+ return Promise.all(proms);
- function doSetupExportFormats (formats) {
+ function doSetupExportFormats(formats) {
var $fmts = self.$('.o_export_format');
- _.each(formats, function (format, i) {
+ _.each(formats, function (format) {
var $radio = $('<input/>', {type: 'radio', value: format.tag, name: 'o_export_format_name'});
var $label = $('<span/>', {html: format.label});
@@ -192,16 +192,16 @@ var DataExport = Dialog.extend({
*/
_onExpandAction: function (record) {
var self = this;
- if (!record['children']) {
+ if (!record.children) {
return;
}
- var model = record['params']['model'];
- var prefix = record['params']['prefix'];
- var name = record['params']['name'];
+ var model = record.params.model;
+ var prefix = record.params.prefix;
+ var name = record.params.name;
var excludeFields = [];
- if (record['relation_field']) {
- excludeFields.push(record['relation_field']);
+ if (record.relation_field) {
+ excludeFields.push(record.relation_field);
}
if (!record.loaded) {
@@ -212,11 +212,11 @@ var DataExport = Dialog.extend({
prefix: prefix,
parent_name: name,
import_compat: !!this.$importCompatRadios.filter(':checked').val(),
- parent_field_type: record['field_type'],
- parent_field: record['params']['parent_field'],
+ parent_field_type: record.field_type,
+ parent_field: record.params.parent_field,
exclude: excludeFields,
},
- }).done(function (results) {
+ }).then(function (results) {
record.loaded = true;
self._onShowData(results, record.id);
});
@@ -294,7 +294,7 @@ var DataExport = Dialog.extend({
var self = this;
if (this.$('.o_exported_lists_select').is(':hidden')) {
this.$('.o_exported_lists').show();
- return $.when();
+ return Promise.resolve();
}
return this._rpc({
@@ -355,7 +355,7 @@ var DataExport = Dialog.extend({
model: this.record.model,
import_compat: this.isCompatibleMode,
},
- }).done(function (records) {
+ }).then(function (records) {
var compatibleFields = _.map(records, function (record) { return record.id; });
self.$fieldsList
.find('option')
diff --git a/addons/web/static/src/js/widgets/domain_selector.js b/addons/web/static/src/js/widgets/domain_selector.js
index 8e20e1ce18d..ed71679699c 100644
--- a/addons/web/static/src/js/widgets/domain_selector.js
+++ b/addons/web/static/src/js/widgets/domain_selector.js
@@ -188,11 +188,14 @@ var DomainTree = DomainNode.extend({
},
/**
* @see DomainNode.start
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this._postRender();
- return $.when(this._super.apply(this, arguments), this._renderChildrenTo(this.$childrenContainer));
+ return Promise.all([
+ this._super.apply(this, arguments),
+ this._renderChildrenTo(this.$childrenContainer)
+ ]);
},
//--------------------------------------------------------------------------
@@ -369,11 +372,11 @@ var DomainTree = DomainNode.extend({
*
* @private
* @param {jQuery} $to - the jQuery node to which the children must be added
- * @returns {Deferred}
+ * @returns {Promise}
*/
_renderChildrenTo: function ($to) {
var $div = $("<div/>");
- return $.when.apply($, _.map(this.children, (function (child) {
+ return Promise.all(_.map(this.children, (function (child) {
return child.appendTo($div);
}).bind(this))).then((function () {
_.each(this.children, function (child) {
@@ -485,11 +488,11 @@ var DomainSelector = DomainTree.extend({
* does nothing.
*
* @param {string} domain
- * @returns {Deferred} resolved when the rerendering is finished
+ * @returns {Promise} resolved when the rerendering is finished
*/
setDomain: function (domain) {
if (domain === Domain.prototype.arrayToString(this.getDomain())) {
- return $.when();
+ return Promise.resolve();
}
var parsedDomain = this._parseDomain(domain);
if (parsedDomain) {
@@ -542,7 +545,7 @@ var DomainSelector = DomainTree.extend({
* This method is ugly but achieves the right behavior without flickering.
*
* @param {Array|string} domain
- * @returns {Deferred}
+ * @returns {Promise}
*/
_redraw: function (domain) {
var oldChildren = this.children.slice();
@@ -637,7 +640,7 @@ var DomainLeaf = DomainNode.extend({
* Prepares the information the rendering of the widget will need by
* pre-instantiating its internal field selector widget.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
willStart: function () {
var defs = [this._super.apply(this, arguments)];
@@ -702,17 +705,17 @@ var DomainLeaf = DomainNode.extend({
}).bind(this)));
}
- return $.when.apply($, wDefs);
+ return Promise.all(wDefs);
}
}).bind(this)));
- return $.when.apply($, defs);
+ return Promise.all(defs);
},
/**
* @see DomainNode.start
* Appends the prepared field selector and value widget.
*
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this.fieldSelector.$el.prependTo(this.$("> .o_domain_leaf_info, > .o_domain_leaf_edition")); // place the field selector
diff --git a/addons/web/static/src/js/widgets/domain_selector_dialog.js b/addons/web/static/src/js/widgets/domain_selector_dialog.js
index 46b54089c5f..f6fe7f0c479 100644
--- a/addons/web/static/src/js/widgets/domain_selector_dialog.js
+++ b/addons/web/static/src/js/widgets/domain_selector_dialog.js
@@ -45,10 +45,10 @@ return Dialog.extend({
// this restores default modal height (bootstrap) and allows field selector to overflow
self.$el.css('overflow', 'visible').closest('.modal-dialog').css('height', 'auto');
});
- return $.when(
+ return Promise.all([
this._super.apply(this, arguments),
this.domainSelector.appendTo(this.$el)
- );
+ ]);
},
});
});
diff --git a/addons/web/static/src/js/widgets/iframe_widget.js b/addons/web/static/src/js/widgets/iframe_widget.js
index 77d27fac5b4..8ecbd5f1c7d 100644
--- a/addons/web/static/src/js/widgets/iframe_widget.js
+++ b/addons/web/static/src/js/widgets/iframe_widget.js
@@ -29,7 +29,7 @@ var IFrameWidget = Widget.extend({
},
/**
* @override
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this.$el.css({height: '100%', width: '100%', border: 0});
diff --git a/addons/web/static/src/js/widgets/model_field_selector.js b/addons/web/static/src/js/widgets/model_field_selector.js
index b8c953a2d0e..08a7ae47c81 100644
--- a/addons/web/static/src/js/widgets/model_field_selector.js
+++ b/addons/web/static/src/js/widgets/model_field_selector.js
@@ -112,17 +112,17 @@ var ModelFieldSelector = Widget.extend({
},
/**
* @see Widget.willStart()
- * @returns {Deferred}
+ * @returns {Promise}
*/
willStart: function () {
- return $.when(
+ return Promise.all([
this._super.apply(this, arguments),
this._prefill()
- );
+ ]);
},
/**
* @see Widget.start
- * @returns {Deferred}
+ * @returns {Promise}
*/
start: function () {
this.$value = this.$(".o_field_selector_value");
@@ -162,11 +162,11 @@ var ModelFieldSelector = Widget.extend({
* Saves a new field chain (array) and re-render.
*
* @param {string[]} chain - the new field chain
- * @returns {Deferred} resolved once the re-rendering is finished
+ * @returns {Promise} resolved once the re-rendering is finished
*/
setChain: function (chain) {
if (_.isEqual(chain, this.chain)) {
- return $.when();
+ return Promise.resolve();
}
this.chain = chain;
@@ -290,14 +290,14 @@ var ModelFieldSelector = Widget.extend({
* chain.
*
* @private
- * @returns {Deferred} resolved once the whole field chain has been
+ * @returns {Promise} resolved once the whole field chain has been
* processed
*/
_prefill: function () {
this.pages = [];
return this._pushPageData(this.model).then((function () {
this._validate(true);
- return (this.chain.length ? processChain.call(this, this.chain.slice().reverse()) : $.when());
+ return (this.chain.length ? processChain.call(this, this.chain.slice().reverse()) : Promise.resolve());
}).bind(this));
function processChain(chain) {
@@ -305,11 +305,11 @@ var ModelFieldSelector = Widget.extend({
if (field && field.relation && chain.length > 0) { // Fetch next chain node if any and possible
return this._pushPageData(field.relation).then(processChain.bind(this, chain));
} else if (field && chain.length === 0) { // Last node fetched
- return $.when();
+ return Promise.resolve();
} else { // Wrong node chain
this._validate(false);
}
- return $.when();
+ return Promise.resolve();
}
},
/**
@@ -318,12 +318,12 @@ var ModelFieldSelector = Widget.extend({
*
* @private
* @param {string} model - the model name whose fields have to be fetched
- * @returns {Deferred} resolved once the fields have been added
+ * @returns {Promise} resolved once the fields have been added
*/
_pushPageData: function (model) {
var def;
if (this.model === model && this.options.fields) {
- def = $.when(sortFields(this.options.fields, model, this.options.order));
+ def = Promise.resolve(sortFields(this.options.fields, model, this.options.order));
} else {
def = this._getModelFieldsFromCache(model, this.options.filters);
}
diff --git a/addons/web/static/src/js/widgets/name_and_signature.js b/addons/web/static/src/js/widgets/name_and_signature.js
index c860b0a4361..7c3f05a7148 100644
--- a/addons/web/static/src/js/widgets/name_and_signature.js
+++ b/addons/web/static/src/js/widgets/name_and_signature.js
@@ -80,14 +80,12 @@ var NameAndSignature = Widget.extend({
*/
willStart: function () {
var self = this;
-
- return $.when(
+ return Promise.all([
this._super.apply(this, arguments),
this._rpc({route: '/web/sign/get_fonts/' + self.defaultFont}).then(function (data) {
self.fonts = data;
})
- );
-
+ ]);
},
/**
* Finds the DOM elements, initializes the signature area,
@@ -217,7 +215,7 @@ var NameAndSignature = Widget.extend({
resetSignature: function () {
if (!this.$signatureField) {
// no action if called before start
- return $.Deferred().reject();
+ return Promise.reject();
}
// recompute size based on the current width
this.$signatureField.css({width: 'unset'});
@@ -248,7 +246,7 @@ var NameAndSignature = Widget.extend({
this.focusName();
- return $.Deferred().resolve();
+ return Promise.resolve();
},
/**
* Changes the signature mode. Toggles the display of the relevant
diff --git a/addons/web/static/src/js/widgets/pie_chart.js b/addons/web/static/src/js/widgets/pie_chart.js
index 44a08a5a22a..ddeca1fdcec 100644
--- a/addons/web/static/src/js/widgets/pie_chart.js
+++ b/addons/web/static/src/js/widgets/pie_chart.js
@@ -67,7 +67,7 @@ var PieChart = Widget.extend({
self.controller = controller;
return self.controller.appendTo(document.createDocumentFragment());
});
- return $.when(def1, def2);
+ return Promise.all([def1, def2]);
},
/**
* @override
diff --git a/addons/web/static/src/js/widgets/switch_company_menu.js b/addons/web/static/src/js/widgets/switch_company_menu.js
index cc0f8825643..a389ee268cd 100644
--- a/addons/web/static/src/js/widgets/switch_company_menu.js
+++ b/addons/web/static/src/js/widgets/switch_company_menu.js
@@ -31,12 +31,6 @@ var SwitchCompanyMenu = Widget.extend({
/**
* @override
*/
- willStart: function () {
- return session.user_companies ? this._super() : $.Deferred().reject();
- },
- /**
- * @override
- */
start: function () {
var companiesList = '';
if (this.isMobile) {
@@ -81,9 +75,9 @@ var SwitchCompanyMenu = Widget.extend({
});
},
});
-
-SystrayMenu.Items.push(SwitchCompanyMenu);
-
+if (session.user_companies) {
+ SystrayMenu.Items.push(SwitchCompanyMenu);
+}
return SwitchCompanyMenu;
});
diff --git a/addons/web/static/tests/chrome/action_manager_mobile_tests.js b/addons/web/static/tests/chrome/action_manager_mobile_tests.js
index d1bc7a5e489..6be9aae8e26 100644
--- a/addons/web/static/tests/chrome/action_manager_mobile_tests.js
+++ b/addons/web/static/tests/chrome/action_manager_mobile_tests.js
@@ -53,23 +53,23 @@ QUnit.module('ActionManager', {
};
},
}, function () {
- QUnit.test('uses a mobile-friendly view by default (if possible)', function (assert) {
+ QUnit.test('uses a mobile-friendly view by default (if possible)', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
// should default on a mobile-friendly view (kanban) for action 1
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.containsNone(actionManager, '.o_list_view');
assert.containsOnce(actionManager, '.o_kanban_view');
// there is no mobile-friendly view for action 2, should use the first one (list)
- actionManager.doAction(2);
+ await actionManager.doAction(2);
assert.containsOnce(actionManager, '.o_list_view');
assert.containsNone(actionManager, '.o_kanban_view');
@@ -77,10 +77,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('lazy load mobile-friendly view', function (assert) {
+ QUnit.test('lazy load mobile-friendly view', async function (assert) {
assert.expect(11);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -89,7 +89,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 1,
view_type: 'form',
});
@@ -99,7 +99,7 @@ QUnit.module('ActionManager', {
assert.containsOnce(actionManager, '.o_form_view');
// go back to lazy loaded view
- testUtils.dom.click(actionManager.$('.o_control_panel .breadcrumb .breadcrumb-item:first'));
+ await testUtils.dom.click(actionManager.$('.o_control_panel .breadcrumb .breadcrumb-item:first'));
assert.containsNone(actionManager, '.o_form_view');
assert.containsNone(actionManager, '.o_list_view');
assert.containsOnce(actionManager, '.o_kanban_view');
@@ -114,16 +114,16 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('view switcher button should be displayed in dropdown on mobile screens', function (assert) {
+ QUnit.test('view switcher button should be displayed in dropdown on mobile screens', async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.containsOnce(actionManager.$('.o_control_panel'), '.o_cp_switch_buttons button[data-toggle="dropdown"]');
assert.hasClass(actionManager.$('.o_cp_switch_buttons .o_cp_switch_kanban'), 'active');
diff --git a/addons/web/static/tests/chrome/action_manager_tests.js b/addons/web/static/tests/chrome/action_manager_tests.js
index 4b8a3a79751..bef2057a076 100644
--- a/addons/web/static/tests/chrome/action_manager_tests.js
+++ b/addons/web/static/tests/chrome/action_manager_tests.js
@@ -146,23 +146,23 @@ QUnit.module('ActionManager', {
}, function () {
QUnit.module('Misc');
- QUnit.test('breadcrumbs and actions with target inline', function (assert) {
+ QUnit.test('breadcrumbs and actions with target inline', async function (assert) {
assert.expect(3);
this.actions[3].views = [[false, 'form']];
this.actions[3].target = 'inline';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.ok(!$('.o_control_panel').is(':visible'),
"control panel should not be visible");
- actionManager.doAction(1, {clear_breadcrumbs: true});
+ await actionManager.doAction(1, {clear_breadcrumbs: true});
assert.ok($('.o_control_panel').is(':visible'),
"control panel should now be visible");
assert.strictEqual($('.o_control_panel .breadcrumb').text(), "Partners Action 1",
@@ -171,7 +171,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('no widget memory leaks when doing some action stuff', function (assert) {
+ QUnit.test('no widget memory leaks when doing some action stuff', async function (assert) {
assert.expect(1);
var delta = 0;
@@ -186,21 +186,21 @@ QUnit.module('ActionManager', {
},
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(8);
+ await actionManager.doAction(8);
var n = delta;
- actionManager.doAction(4);
+ await actionManager.doAction(4);
// kanban view is loaded, switch to list view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// go back to action 7 in breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
assert.strictEqual(delta, n,
"should have properly destroyed all other widgets");
@@ -208,7 +208,7 @@ QUnit.module('ActionManager', {
testUtils.mock.unpatch(Widget);
});
- QUnit.test('no widget memory leaks when executing actions in dialog', function (assert) {
+ QUnit.test('no widget memory leaks when executing actions in dialog', async function (assert) {
assert.expect(1);
var delta = 0;
@@ -225,15 +225,15 @@ QUnit.module('ActionManager', {
},
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
var n = delta;
- actionManager.doAction(5);
- actionManager.doAction({type: 'ir.actions.act_window_close'});
+ await actionManager.doAction(5);
+ await actionManager.doAction({type: 'ir.actions.act_window_close'});
assert.strictEqual(delta, n,
"should have properly destroyed all widgets");
@@ -242,7 +242,7 @@ QUnit.module('ActionManager', {
testUtils.mock.unpatch(Widget);
});
- QUnit.test('no memory leaks when executing an action while switching view', function (assert) {
+ QUnit.test('no memory leaks when executing an action while switching view', async function (assert) {
assert.expect(1);
var def;
@@ -258,33 +258,34 @@ QUnit.module('ActionManager', {
},
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'read') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
- actionManager.doAction(4);
+ await actionManager.doAction(4);
var n = delta;
- actionManager.doAction(3, {clear_breadcrumbs: true});
+ await actionManager.doAction(3, {clear_breadcrumbs: true});
// switch to the form view (this request is blocked)
- def = $.Deferred();
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// execute another action meanwhile (don't block this request)
- actionManager.doAction(4, {clear_breadcrumbs: true});
+ await actionManager.doAction(4, {clear_breadcrumbs: true});
// unblock the switch to the form view in action 3
def.resolve();
+ await testUtils.nextTick();
assert.strictEqual(n, delta,
"all widgets of action 3 should have been destroyed");
@@ -293,7 +294,7 @@ QUnit.module('ActionManager', {
testUtils.mock.unpatch(Widget);
});
- QUnit.test('no memory leaks when executing an action while loading views', function (assert) {
+ QUnit.test('no memory leaks when executing an action while loading views', async function (assert) {
assert.expect(1);
var def;
@@ -309,30 +310,31 @@ QUnit.module('ActionManager', {
},
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'load_views') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
// execute action 4 to know the number of widgets it instantiates
- actionManager.doAction(4);
+ await actionManager.doAction(4);
var n = delta;
// execute a first action (its 'load_views' RPC is blocked)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
actionManager.doAction(3, {clear_breadcrumbs: true});
// execute another action meanwhile (and unlock the RPC)
actionManager.doAction(4, {clear_breadcrumbs: true});
def.resolve();
+ await testUtils.nextTick();
assert.strictEqual(n, delta,
"all widgets of action 3 should have been destroyed");
@@ -341,7 +343,7 @@ QUnit.module('ActionManager', {
testUtils.mock.unpatch(Widget);
});
- QUnit.test('no memory leaks when executing an action while loading data of default view', function (assert) {
+ QUnit.test('no memory leaks when executing an action while loading data of default view', async function (assert) {
assert.expect(1);
var def;
@@ -357,30 +359,31 @@ QUnit.module('ActionManager', {
},
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route) {
var result = this._super.apply(this, arguments);
if (route === '/web/dataset/search_read') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
// execute action 4 to know the number of widgets it instantiates
- actionManager.doAction(4);
+ await actionManager.doAction(4);
var n = delta;
// execute a first action (its 'search_read' RPC is blocked)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
actionManager.doAction(3, {clear_breadcrumbs: true});
// execute another action meanwhile (and unlock the RPC)
actionManager.doAction(4, {clear_breadcrumbs: true});
def.resolve();
+ await testUtils.nextTick();
assert.strictEqual(n, delta,
"all widgets of action 3 should have been destroyed");
@@ -389,71 +392,72 @@ QUnit.module('ActionManager', {
testUtils.mock.unpatch(Widget);
});
- QUnit.test('action with "no_breadcrumbs" set to true', function (assert) {
+ QUnit.test('action with "no_breadcrumbs" set to true', async function (assert) {
assert.expect(2);
_.findWhere(this.actions, {id: 4}).context = {no_breadcrumbs: true};
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should be one controller in the breadcrumbs");
// push another action flagged with 'no_breadcrumbs=true'
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 0,
"the breadcrumbs should be empty");
actionManager.destroy();
});
- QUnit.test('on_reverse_breadcrumb handler is correctly called', function (assert) {
+ QUnit.test('on_reverse_breadcrumb handler is correctly called', async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
// execute action 3 and open a record in form view
- actionManager.doAction(3);
+ await actionManager.doAction(3);
testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// execute action 4 without 'on_reverse_breadcrumb' handler, then go back
- actionManager.doAction(4);
- testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
+ await actionManager.doAction(4);
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
assert.verifySteps([]);
// execute action 4 with an 'on_reverse_breadcrumb' handler, then go back
- actionManager.doAction(4, {
+ await actionManager.doAction(4, {
on_reverse_breadcrumb: function () {
assert.step('on_reverse_breadcrumb');
}
});
- testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
assert.verifySteps(['on_reverse_breadcrumb']);
actionManager.destroy();
});
- QUnit.test('handles "history_back" event', function (assert) {
+ QUnit.test('handles "history_back" event', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(4);
- actionManager.doAction(3);
+ await actionManager.doAction(4);
+ await actionManager.doAction(3);
actionManager.trigger_up('history_back');
+ await testUtils.nextTick();
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should be one controller in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners Action 4',
@@ -462,12 +466,12 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('stores and restores scroll position', function (assert) {
+ QUnit.test('stores and restores scroll position', async function (assert) {
assert.expect(7);
var left;
var top;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -484,17 +488,17 @@ QUnit.module('ActionManager', {
// execute a first action and simulate a scroll
assert.step('execute action 3');
- actionManager.doAction(3);
+ await actionManager.doAction(3);
left = 50;
top = 100;
// execute a second action (in which we don't scroll)
assert.step('execute action 4');
- actionManager.doAction(4);
+ await actionManager.doAction(4);
// go back using the breadcrumbs
assert.step('go back to action 3');
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.verifySteps([
'execute action 3',
@@ -510,7 +514,7 @@ QUnit.module('ActionManager', {
QUnit.module('Push State');
- QUnit.test('properly push state', function (assert) {
+ QUnit.test('properly push state', async function (assert) {
assert.expect(3);
var stateDescriptions = [
@@ -519,7 +523,7 @@ QUnit.module('ActionManager', {
{action: 8, id: 4, model: "pony", title: "Twilight Sparkle", view_type: "form"},
];
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -531,17 +535,17 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(4);
- actionManager.doAction(8);
- testUtils.dom.click(actionManager.$('tr.o_data_row:first'));
+ await actionManager.doAction(4);
+ await actionManager.doAction(8);
+ await testUtils.dom.click(actionManager.$('tr.o_data_row:first'));
actionManager.destroy();
});
- QUnit.test('push state after action is loaded, not before', function (assert) {
+ QUnit.test('push state after action is loaded, not before', async function (assert) {
assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -555,7 +559,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.verifySteps([
'/web/action/load',
'/web/dataset/call_kw/partner',
@@ -566,10 +570,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('do not push state for actions in target=new', function (assert) {
+ QUnit.test('do not push state for actions in target=new', async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -579,18 +583,18 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(4);
- assert.verifySteps(['push_state']);
- actionManager.doAction(5);
+ await actionManager.doAction(4);
assert.verifySteps(['push_state']);
+ await actionManager.doAction(5);
+ assert.verifySteps([]);
actionManager.destroy();
});
- QUnit.test('do not push state when action fails', function (assert) {
+ QUnit.test('do not push state when action fails', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -602,15 +606,15 @@ QUnit.module('ActionManager', {
mockRPC: function (route, args) {
if (args.method === 'read') {
// this is the rpc to load form view
- return $.Deferred().reject();
+ return Promise.reject();
}
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(8);
- assert.verifySteps(['push_state']);
- testUtils.dom.click(actionManager.$('tr.o_data_row:first'));
+ await actionManager.doAction(8);
assert.verifySteps(['push_state']);
+ await testUtils.dom.click(actionManager.$('tr.o_data_row:first'));
+ assert.verifySteps([]);
// we make sure here that the list view is still in the dom
assert.containsOnce(actionManager, '.o_list_view',
"there should still be a list view in dom");
@@ -620,10 +624,10 @@ QUnit.module('ActionManager', {
QUnit.module('Load State');
- QUnit.test('should not crash on invalid state', function (assert) {
+ QUnit.test('should not crash on invalid state', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -632,7 +636,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
res_model: 'partner', // the valid key for the model is 'model', not 'res_model'
});
@@ -642,7 +646,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('properly load client actions', function (assert) {
+ QUnit.test('properly load client actions', async function (assert) {
assert.expect(2);
var ClientAction = AbstractAction.extend({
@@ -653,7 +657,7 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('HelloWorldTest', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -662,7 +666,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 'HelloWorldTest',
});
@@ -675,10 +679,10 @@ QUnit.module('ActionManager', {
delete core.action_registry.map.HelloWorldTest;
});
- QUnit.test('properly load act window actions', function (assert) {
+ QUnit.test('properly load act window actions', async function (assert) {
assert.expect(6);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -687,7 +691,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 1,
});
@@ -705,10 +709,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('properly load records', function (assert) {
+ QUnit.test('properly load records', async function (assert) {
assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -717,7 +721,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
id: 2,
model: 'partner',
});
@@ -735,10 +739,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('properly load default record', function (assert) {
+ QUnit.test('properly load default record', async function (assert) {
assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -747,7 +751,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 3,
id: "", // might happen with bbq and id=& in URL
model: 'partner',
@@ -766,10 +770,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('load requested view for act window actions', function (assert) {
+ QUnit.test('load requested view for act window actions', async function (assert) {
assert.expect(6);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -778,7 +782,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 3,
view_type: 'kanban',
});
@@ -797,10 +801,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('lazy load multi record view if mono record one is requested', function (assert) {
+ QUnit.test('lazy load multi record view if mono record one is requested', async function (assert) {
assert.expect(11);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -809,12 +813,11 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 3,
id: 2,
view_type: 'form',
});
-
assert.containsNone(actionManager, '.o_list_view',
"should not have rendered a list view");
assert.containsOnce(actionManager, '.o_form_view',
@@ -825,7 +828,7 @@ QUnit.module('ActionManager', {
"breadcrumbs should contain the display_name of the opened record");
// go back to Lst
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.containsOnce(actionManager, '.o_list_view',
"should now display the list view");
assert.containsNone(actionManager, '.o_form_view',
@@ -841,22 +844,22 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('lazy load multi record view with previous action', function (assert) {
+ QUnit.test('lazy load multi record view with previous action', async function (assert) {
assert.expect(6);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.strictEqual($('.o_control_panel .breadcrumb li').length, 1,
"there should be one controller in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb li').text(), 'Partners Action 4',
"breadcrumbs should contain the display_name of the opened record");
- actionManager.doAction(3, {
+ await actionManager.doAction(3, {
resID: 2,
viewType: 'form',
});
@@ -867,7 +870,7 @@ QUnit.module('ActionManager', {
"the breadcrumb elements should be correctly ordered");
// go back to List
- testUtils.dom.click($('.o_control_panel .breadcrumb a:last'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:last'));
assert.strictEqual($('.o_control_panel .breadcrumb li').length, 2,
"there should be two controllers in the breadcrumbs");
@@ -877,10 +880,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('change the viewType of the current action', function (assert) {
+ QUnit.test('change the viewType of the current action', async function (assert) {
assert.expect(13);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -889,13 +892,13 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.containsOnce(actionManager, '.o_list_view',
"should have rendered a list view");
// switch to kanban view
- actionManager.loadState({
+ await actionManager.loadState({
action: 3,
view_type: 'kanban',
});
@@ -906,7 +909,7 @@ QUnit.module('ActionManager', {
"should have switched to the kanban view");
// switch to form view, open record 4
- actionManager.loadState({
+ await actionManager.loadState({
action: 3,
id: 4,
view_type: 'form',
@@ -935,10 +938,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('change the id of the current action', function (assert) {
+ QUnit.test('change the id of the current action', async function (assert) {
assert.expect(11);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -949,8 +952,8 @@ QUnit.module('ActionManager', {
});
// execute action 3 and open the first record in a form view
- actionManager.doAction(3);
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await actionManager.doAction(3);
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.containsOnce(actionManager, '.o_form_view',
"should have rendered a form view");
@@ -958,7 +961,7 @@ QUnit.module('ActionManager', {
"should have opened the first record");
// switch to record 4
- actionManager.loadState({
+ await actionManager.loadState({
action: 3,
id: 4,
view_type: 'form',
@@ -985,10 +988,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('should not push a loaded state', function (assert) {
+ QUnit.test('should not push a loaded state', async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -998,11 +1001,11 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.loadState({action: 3});
+ await actionManager.loadState({action: 3});
assert.verifySteps([], "should not push the loaded state");
- testUtils.dom.click(actionManager.$('tr.o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('tr.o_data_row:first'));
assert.verifySteps(['push_state'],
"should push the state of it changes afterwards");
@@ -1010,7 +1013,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('should not push a loaded state of a client action', function (assert) {
+ QUnit.test('should not push a loaded state of a client action', async function (assert) {
assert.expect(4);
var ClientAction = AbstractAction.extend({
@@ -1033,7 +1036,7 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('ClientAction', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1048,11 +1051,11 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.loadState({action: 9});
+ await actionManager.loadState({action: 9});
assert.verifySteps([], "should not push the loaded state");
- testUtils.dom.click(actionManager.$('button'));
+ await testUtils.dom.click(actionManager.$('button'));
assert.verifySteps(['push_state'],
"should push the state of it changes afterwards");
@@ -1060,7 +1063,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('change a param of an ir.actions.client in the url', function (assert) {
+ QUnit.test('change a param of an ir.actions.client in the url', async function (assert) {
assert.expect(7);
var ClientAction = AbstractAction.extend({
@@ -1083,14 +1086,14 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('ClientAction', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
// execute the client action
- actionManager.doAction(9);
+ await actionManager.doAction(9);
assert.strictEqual(actionManager.$('.o_client_action .o_content').text(), 'default value',
"should have rendered the client action");
@@ -1098,7 +1101,7 @@ QUnit.module('ActionManager', {
"there should be one controller in the breadcrumbs");
// update param 'a' in the url
- actionManager.loadState({
+ await actionManager.loadState({
action: 9,
a: 'new value',
});
@@ -1115,14 +1118,14 @@ QUnit.module('ActionManager', {
delete core.action_registry.map.ClientAction;
});
- QUnit.test('load a window action without id (in a multi-record view)', function (assert) {
+ QUnit.test('load a window action without id (in a multi-record view)', async function (assert) {
assert.expect(14);
var RamStorageService = AbstractStorageService.extend({
storage: new RamStorage(),
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1141,14 +1144,14 @@ QUnit.module('ActionManager', {
}
}, true);
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.containsOnce(actionManager, '.o_kanban_view',
"should display a kanban view");
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners Action 4',
"breadcrumbs should display the display_name of the action");
- actionManager.loadState({
+ await actionManager.loadState({
model: 'partner',
view_type: 'list',
});
@@ -1176,11 +1179,11 @@ QUnit.module('ActionManager', {
QUnit.module('Concurrency management');
- QUnit.test('drop previous actions if possible', function (assert) {
+ QUnit.test('drop previous actions if possible', async function (assert) {
assert.expect(6);
- var def = $.Deferred();
- var actionManager = createActionManager({
+ var def = testUtils.makeTestPromise();
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1197,7 +1200,7 @@ QUnit.module('ActionManager', {
actionManager.doAction(8);
def.resolve();
-
+ await testUtils.nextTick();
// action 4 loads a kanban view first, 6 loads a list view. We want a list
assert.containsOnce(actionManager, '.o_list_view',
'there should be a list view in DOM');
@@ -1212,13 +1215,13 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('handle switching view and switching back on slow network', function (assert) {
+ QUnit.test('handle switching view and switching back on slow network', async function (assert) {
assert.expect(8);
- var def = $.Deferred();
- var defs = [$.when(), def, $.when()];
+ var def = testUtils.makeTestPromise();
+ var defs = [Promise.resolve(), def, Promise.resolve()];
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1232,14 +1235,13 @@ QUnit.module('ActionManager', {
return result;
},
});
- actionManager.doAction(4);
-
+ await actionManager.doAction(4);
// kanban view is loaded, switch to list view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
// here, list view is not ready yet, because def is not resolved
// switch back to kanban view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
// here, we want the kanban view to reload itself, regardless of list view
assert.verifySteps([
@@ -1252,7 +1254,7 @@ QUnit.module('ActionManager', {
// we resolve def => list view is now ready (but we want to ignore it)
def.resolve();
-
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_kanban_view',
"there should be a kanban view in dom");
assert.containsNone(actionManager, '.o_list_view',
@@ -1261,12 +1263,12 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('when an server action takes too much time...', function (assert) {
+ QUnit.test('when an server action takes too much time...', async function (assert) {
assert.expect(1);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1282,19 +1284,19 @@ QUnit.module('ActionManager', {
actionManager.doAction(4);
def.resolve();
-
+ await testUtils.nextTick();
assert.strictEqual($('.o_control_panel .breadcrumb-item.active').text(), 'Partners Action 4',
'action 4 should be loaded');
actionManager.destroy();
});
- QUnit.test('clicking quickly on breadcrumbs...', function (assert) {
+ QUnit.test('clicking quickly on breadcrumbs...', async function (assert) {
assert.expect(1);
- var def = $.when();
+ var def = Promise.resolve();
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1308,21 +1310,23 @@ QUnit.module('ActionManager', {
});
// create a situation with 3 breadcrumbs: kanban/form/list
- actionManager.doAction(4);
- testUtils.dom.click(actionManager.$('.o_kanban_record:first'));
+ await actionManager.doAction(4);
+ await testUtils.dom.click(actionManager.$('.o_kanban_record:first'));
actionManager.doAction(8);
- // now, the next read operations will be deferred (this is the read
+ // now, the next read operations will be promise (this is the read
// operation for the form view reload)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
+ await testUtils.nextTick();
// click on the breadcrumbs for the form view, then on the kanban view
// before the form view is fully reloaded
- testUtils.dom.click($('.o_control_panel .breadcrumb-item:eq(1)'));
- testUtils.dom.click($('.o_control_panel .breadcrumb-item:eq(0)'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb-item:eq(1)'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb-item:eq(0)'));
// resolve the form view read
def.resolve();
+ await testUtils.nextTick();
assert.strictEqual($('.o_control_panel .breadcrumb-item.active').text(), 'Partners Action 4',
'action 4 should be loaded and visible');
@@ -1330,11 +1334,11 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('execute a new action while loading a lazy-loaded controller', function (assert) {
+ QUnit.test('execute a new action while loading a lazy-loaded controller', async function (assert) {
assert.expect(15);
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1342,12 +1346,12 @@ QUnit.module('ActionManager', {
var result = this._super.apply(this, arguments);
assert.step(args.method || route);
if (route === '/web/dataset/search_read' && args.model === 'partner') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
- actionManager.loadState({
+ await actionManager.loadState({
action: 4,
id: 2,
view_type: 'form',
@@ -1357,19 +1361,20 @@ QUnit.module('ActionManager', {
"should display the form view of action 4");
// click to go back to Kanban (this request is blocked)
- def = $.Deferred();
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ def = testUtils.makeTestPromise();
+ await testUtils.nextTick();
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.containsOnce(actionManager, '.o_form_view',
- "should still display the form view of action 4");
+ "should still display the form view of action 4");
// execute another action meanwhile (don't block this request)
- actionManager.doAction(8, {clear_breadcrumbs: true});
+ await actionManager.doAction(8, {clear_breadcrumbs: true});
assert.containsOnce(actionManager, '.o_list_view',
- "should display action 8");
+ "should display action 8");
assert.containsNone(actionManager, '.o_form_view',
- "should no longer display the form view");
+ "should no longer display the form view");
assert.verifySteps([
'/web/action/load', // load state action 4
@@ -1383,31 +1388,24 @@ QUnit.module('ActionManager', {
// unblock the switch to Kanban in action 4
def.resolve();
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_list_view',
"should still display action 8");
assert.containsNone(actionManager, '.o_kanban_view',
"should not display the kanban view of action 4");
- assert.verifySteps([
- '/web/action/load', // load state action 4
- 'load_views', // load state action 4
- 'read', // read the opened record (action 4)
- '/web/dataset/search_read', // blocked search read when coming back to Kanban (action 4)
- '/web/action/load', // action 8
- 'load_views', // action 8
- '/web/dataset/search_read', // search read action 8
- ]);
+ assert.verifySteps([]);
actionManager.destroy();
});
- QUnit.test('execute a new action while handling a call_button', function (assert) {
+ QUnit.test('execute a new action while handling a call_button', async function (assert) {
assert.expect(16);
var self = this;
- var def = $.Deferred();
- var actionManager = createActionManager({
+ var def = testUtils.makeTestPromise();
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1421,20 +1419,20 @@ QUnit.module('ActionManager', {
});
// execute action 3 and open a record in form view
- actionManager.doAction(3);
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await actionManager.doAction(3);
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.containsOnce(actionManager, '.o_form_view',
"should display the form view of action 3");
// click on 'Call method' button (this request is blocked)
- testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)'));
+ await testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)'));
assert.containsOnce(actionManager, '.o_form_view',
"should still display the form view of action 3");
// execute another action
- actionManager.doAction(8, {clear_breadcrumbs: true});
+ await actionManager.doAction(8, {clear_breadcrumbs: true});
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view of action 8");
@@ -1454,31 +1452,22 @@ QUnit.module('ActionManager', {
// unblock the call_button request
def.resolve();
-
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_list_view',
"should still display the list view of action 8");
assert.containsNone(actionManager, '.o_kanban_view',
"should not display action 1");
- assert.verifySteps([
- '/web/action/load', // action 3
- 'load_views', // action 3
- '/web/dataset/search_read', // list for action 3
- 'read', // form for action 3
- 'object', // click on 'Call method' button (this request is blocked)
- '/web/action/load', // action 8
- 'load_views', // action 8
- '/web/dataset/search_read', // list for action 8
- ]);
+ assert.verifySteps([]);
actionManager.destroy();
});
- QUnit.test('execute a new action while switching to another controller', function (assert) {
+ QUnit.test('execute a new action while switching to another controller', async function (assert) {
assert.expect(15);
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1486,26 +1475,27 @@ QUnit.module('ActionManager', {
var result = this._super.apply(this, arguments);
assert.step(args.method || route);
if (args.method === 'read') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view of action 3");
// switch to the form view (this request is blocked)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
+ await testUtils.nextTick();
testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.containsOnce(actionManager, '.o_list_view',
- "should still display the list view of action 3");
+ "should still display the list view of action 3");
// execute another action meanwhile (don't block this request)
- actionManager.doAction(4, {clear_breadcrumbs: true});
+ await actionManager.doAction(4, {clear_breadcrumbs: true});
assert.containsOnce(actionManager, '.o_kanban_view',
"should display the kanban view of action 8");
@@ -1516,38 +1506,31 @@ QUnit.module('ActionManager', {
'/web/action/load', // action 3
'load_views', // action 3
'/web/dataset/search_read', // search read of list view of action 3
- 'read', // read the opened record of action 3 (this request is blocked)
'/web/action/load', // action 4
'load_views', // action 4
+ 'read', // read the opened record of action 3 (this request is blocked)
'/web/dataset/search_read', // search read action 4
]);
// unblock the switch to the form view in action 3
def.resolve();
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_kanban_view',
"should still display the kanban view of action 8");
assert.containsNone(actionManager, '.o_form_view',
"should not display the form view of action 3");
- assert.verifySteps([
- '/web/action/load', // action 3
- 'load_views', // action 3
- '/web/dataset/search_read', // search read of list view of action 3
- 'read', // read the opened record of action 3 (this request is blocked)
- '/web/action/load', // action 4
- 'load_views', // action 4
- '/web/dataset/search_read', // search read action 4
- ]);
+ assert.verifySteps([]);
actionManager.destroy();
});
- QUnit.test('execute a new action while loading views', function (assert) {
+ QUnit.test('execute a new action while loading views', async function (assert) {
assert.expect(10);
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1555,22 +1538,24 @@ QUnit.module('ActionManager', {
var result = this._super.apply(this, arguments);
assert.step(args.method || route);
if (args.method === 'load_views') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
// execute a first action (its 'load_views' RPC is blocked)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
actionManager.doAction(3);
assert.containsNone(actionManager, '.o_list_view',
"should not display the list view of action 3");
+ await testUtils.nextTick();
// execute another action meanwhile (and unlock the RPC)
actionManager.doAction(4);
def.resolve();
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_kanban_view',
"should display the kanban view of action 4");
@@ -1590,11 +1575,11 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('execute a new action while loading data of default view', function (assert) {
+ QUnit.test('execute a new action while loading data of default view', async function (assert) {
assert.expect(11);
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1602,23 +1587,24 @@ QUnit.module('ActionManager', {
var result = this._super.apply(this, arguments);
assert.step(args.method || route);
if (route === '/web/dataset/search_read') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
// execute a first action (its 'search_read' RPC is blocked)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
actionManager.doAction(3);
assert.containsNone(actionManager, '.o_list_view',
"should not display the list view of action 3");
+ await testUtils.nextTick();
// execute another action meanwhile (and unlock the RPC)
actionManager.doAction(4);
def.resolve();
-
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_kanban_view',
"should display the kanban view of action 4");
assert.containsNone(actionManager, '.o_list_view',
@@ -1638,24 +1624,24 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('open a record while reloading the list view', function (assert) {
+ QUnit.test('open a record while reloading the list view', async function (assert) {
assert.expect(12);
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route) {
var result = this._super.apply(this, arguments);
if (route === '/web/dataset/search_read') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view");
@@ -1665,8 +1651,9 @@ QUnit.module('ActionManager', {
"list view buttons should be displayed in control panel");
// reload (the search_read RPC will be blocked)
- def = $.Deferred();
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ def = testUtils.makeTestPromise();
+ await testUtils.nextTick();
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
assert.containsN(actionManager, '.o_list_view .o_data_row', 5,
"list view should still contain 5 records");
@@ -1674,7 +1661,7 @@ QUnit.module('ActionManager', {
"list view buttons should still be displayed in control panel");
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.containsOnce(actionManager, '.o_form_view',
"should display the form view");
@@ -1685,6 +1672,7 @@ QUnit.module('ActionManager', {
// unblock the search_read RPC
def.resolve();
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_form_view',
"should display the form view");
@@ -1700,7 +1688,7 @@ QUnit.module('ActionManager', {
QUnit.module('Client Actions');
- QUnit.test('can execute client actions from tag name', function (assert) {
+ QUnit.test('can execute client actions from tag name', async function (assert) {
assert.expect(3);
var ClientAction = AbstractAction.extend({
@@ -1711,13 +1699,13 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('HelloWorldTest', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
mockRPC: function (route, args) {
assert.step(args.method || route);
return this._super.apply(this, arguments);
}
});
- actionManager.doAction('HelloWorldTest');
+ await actionManager.doAction('HelloWorldTest');
assert.strictEqual($('.o_control_panel:visible').length, 0, // AAB: global selector until the ControlPanel is moved from ActionManager to the Views
"shouldn't have rendered a control panel");
@@ -1729,7 +1717,7 @@ QUnit.module('ActionManager', {
delete core.action_registry.map.HelloWorldTest;
});
- QUnit.test('client action with control panel', function (assert) {
+ QUnit.test('client action with control panel', async function (assert) {
assert.expect(4);
var ClientAction = AbstractAction.extend({
@@ -1743,8 +1731,8 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('HelloWorldTest', ClientAction);
- var actionManager = createActionManager();
- actionManager.doAction('HelloWorldTest');
+ var actionManager = await createActionManager();
+ await actionManager.doAction('HelloWorldTest');
assert.strictEqual($('.o_control_panel:visible').length, 1,
"should have rendered a control panel");
@@ -1759,11 +1747,11 @@ QUnit.module('ActionManager', {
delete core.action_registry.map.HelloWorldTest;
});
- QUnit.test('state is pushed for client actions', function (assert) {
+ QUnit.test('state is pushed for client actions', async function (assert) {
assert.expect(2);
var ClientAction = AbstractAction.extend({});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
intercepts: {
push_state: function () {
assert.step('push state');
@@ -1772,7 +1760,7 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('HelloWorldTest', ClientAction);
- actionManager.doAction('HelloWorldTest');
+ await actionManager.doAction('HelloWorldTest');
assert.verifySteps(['push state']);
@@ -1780,7 +1768,7 @@ QUnit.module('ActionManager', {
delete core.action_registry.map.HelloWorldTest;
});
- QUnit.test('breadcrumb is updated on title change', function (assert) {
+ QUnit.test('breadcrumb is updated on title change', async function (assert) {
assert.expect(2);
var ClientAction = AbstractAction.extend({
@@ -1797,9 +1785,9 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- var actionManager = createActionManager();
+ var actionManager = await createActionManager();
core.action_registry.add('HelloWorldTest', ClientAction);
- actionManager.doAction('HelloWorldTest');
+ await actionManager.doAction('HelloWorldTest');
assert.strictEqual($('ol.breadcrumb').text(), "initial title",
"should have initial title as breadcrumb content");
@@ -1814,10 +1802,10 @@ QUnit.module('ActionManager', {
QUnit.module('Server actions');
- QUnit.test('can execute server actions from db ID', function (assert) {
+ QUnit.test('can execute server actions from db ID', async function (assert) {
assert.expect(9);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1826,12 +1814,12 @@ QUnit.module('ActionManager', {
if (route === '/web/action/run') {
assert.strictEqual(args.action_id, 2,
"should call the correct server action");
- return $.when(1); // execute action 1
+ return Promise.resolve(1); // execute action 1
}
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(2);
+ await actionManager.doAction(2);
assert.strictEqual($('.o_control_panel:visible').length, 1,
"should have rendered a control panel");
@@ -1848,31 +1836,31 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('handle server actions returning false', function (assert) {
+ QUnit.test('handle server actions returning false', async function (assert) {
assert.expect(9);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
assert.step(args.method || route);
if (route === '/web/action/run') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
});
// execute an action in target="new"
- actionManager.doAction(5, {
+ await actionManager.doAction(5, {
on_close: assert.step.bind(assert, 'close handler'),
});
assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
"should have rendered a form view in a modal");
// execute a server action that returns false
- actionManager.doAction(2);
+ await actionManager.doAction(2);
assert.strictEqual($('.o_technical_modal').length, 0,
"should have closed the modal");
assert.verifySteps([
@@ -1889,10 +1877,10 @@ QUnit.module('ActionManager', {
QUnit.module('Report actions');
- QUnit.test('can execute report actions from db ID', function (assert) {
- assert.expect(6);
+ QUnit.test('can execute report actions from db ID', async function (assert) {
+ assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1902,12 +1890,12 @@ QUnit.module('ActionManager', {
mockRPC: function (route, args) {
assert.step(args.method || route);
if (route === '/report/check_wkhtmltopdf') {
- return $.when('ok');
+ return Promise.resolve('ok');
}
return this._super.apply(this, arguments);
},
session: {
- get_file: function (params) {
+ get_file: async function (params) {
assert.step(params.url);
params.success();
params.complete();
@@ -1915,16 +1903,15 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(7, {
+ await actionManager.doAction(7, {
on_close: function () {
assert.step('on_close');
},
});
-
+ await testUtils.nextTick();
assert.verifySteps([
'/web/action/load',
'/report/check_wkhtmltopdf',
- '/web/static/src/img/spin.png', // block UI image
'/report/download',
'on_close',
]);
@@ -1932,10 +1919,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('report actions can close modals and reload views', function (assert) {
+ QUnit.test('report actions can close modals and reload views', async function (assert) {
assert.expect(8);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1944,12 +1931,12 @@ QUnit.module('ActionManager', {
},
mockRPC: function (route, args) {
if (route === '/report/check_wkhtmltopdf') {
- return $.when('ok');
+ return Promise.resolve('ok');
}
return this._super.apply(this, arguments);
},
session: {
- get_file: function (params) {
+ get_file: async function (params) {
assert.step(params.url);
params.success();
params.complete();
@@ -1959,7 +1946,7 @@ QUnit.module('ActionManager', {
});
// load modal
- actionManager.doAction(5, {
+ await actionManager.doAction(5, {
on_close: function () {
assert.step('on_close');
},
@@ -1968,7 +1955,7 @@ QUnit.module('ActionManager', {
assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
"should have rendered a form view in a modal");
- actionManager.doAction(7, {
+ await actionManager.doAction(7, {
on_close: function () {
assert.step('on_printed');
},
@@ -1977,7 +1964,7 @@ QUnit.module('ActionManager', {
assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
"The modal should still exist");
- actionManager.doAction(11);
+ await actionManager.doAction(11);
assert.strictEqual($('.o_technical_modal .o_form_view').length, 0,
"the modal should have been closed after the action report");
@@ -1992,10 +1979,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('should trigger a notification if wkhtmltopdf is to upgrade', function (assert) {
- assert.expect(6);
+ QUnit.test('should trigger a notification if wkhtmltopdf is to upgrade', async function (assert) {
+ assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2010,12 +1997,12 @@ QUnit.module('ActionManager', {
mockRPC: function (route, args) {
assert.step(args.method || route);
if (route === '/report/check_wkhtmltopdf') {
- return $.when('upgrade');
+ return Promise.resolve('upgrade');
}
return this._super.apply(this, arguments);
},
session: {
- get_file: function (params) {
+ get_file: async function (params) {
assert.step(params.url);
params.success();
params.complete();
@@ -2023,19 +2010,18 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(7);
+ await actionManager.doAction(7);
assert.verifySteps([
'/web/action/load',
'/report/check_wkhtmltopdf',
'notification',
- '/web/static/src/img/spin.png', // block UI image
'/report/download',
]);
actionManager.destroy();
});
- QUnit.test('should open the report client action if wkhtmltopdf is broken', function (assert) {
+ QUnit.test('should open the report client action if wkhtmltopdf is broken', async function (assert) {
assert.expect(6);
// patch the report client action to override its iframe's url so that
@@ -2052,7 +2038,7 @@ QUnit.module('ActionManager', {
}
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2067,10 +2053,10 @@ QUnit.module('ActionManager', {
mockRPC: function (route, args) {
assert.step(args.method || route);
if (route === '/report/check_wkhtmltopdf') {
- return $.when('broken');
+ return Promise.resolve('broken');
}
if (route === 'test /report/html/some_report') {
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
@@ -2081,7 +2067,7 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(7);
+ await actionManager.doAction(7);
assert.containsOnce(actionManager, '.o_report_iframe',
"should have opened the report client action");
@@ -2099,10 +2085,10 @@ QUnit.module('ActionManager', {
QUnit.module('Window Actions');
- QUnit.test('can execute act_window actions from db ID', function (assert) {
+ QUnit.test('can execute act_window actions from db ID', async function (assert) {
assert.expect(6);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2111,7 +2097,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.strictEqual($('.o_control_panel').length, 1,
"should have rendered a control panel");
@@ -2126,10 +2112,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('sidebar is present in list view', function (assert) {
+ QUnit.test('sidebar is present in list view', async function (assert) {
assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2148,21 +2134,21 @@ QUnit.module('ActionManager', {
return res;
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.isNotVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Print")'));
assert.isNotVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Action")'));
- testUtils.dom.clickFirst(actionManager.$('input.custom-control-input'));
+ await testUtils.dom.clickFirst(actionManager.$('input.custom-control-input'));
assert.isVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Print")'));
assert.isVisible(actionManager.$('.o_cp_sidebar button.o_dropdown_toggler_btn:contains("Action")'));
actionManager.destroy();
});
- QUnit.test('can switch between views', function (assert) {
+ QUnit.test('can switch between views', async function (assert) {
assert.expect(18);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2171,27 +2157,27 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view");
// switch to kanban view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.containsNone(actionManager, '.o_list_view',
"should no longer display the list view");
assert.containsOnce(actionManager, '.o_kanban_view',
"should display the kanban view");
// switch back to list view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view");
assert.containsNone(actionManager, '.o_kanban_view',
"should no longer display the kanban view");
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.containsNone(actionManager, '.o_list_view',
"should no longer display the list view");
assert.containsOnce(actionManager, '.o_form_view',
@@ -2200,7 +2186,7 @@ QUnit.module('ActionManager', {
"should have opened the correct record");
// go back to list view using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view");
assert.containsNone(actionManager, '.o_form_view',
@@ -2219,7 +2205,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('orderedBy in context is not propagated when executing another action', function (assert) {
+ QUnit.test('orderedBy in context is not propagated when executing another action', async function (assert) {
assert.expect(6);
this.data.partner.fields.foo.sortable = true,
@@ -2229,7 +2215,7 @@ QUnit.module('ActionManager', {
'</header>';
var searchReadCount = 1;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2252,7 +2238,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// Simulate the activation of a filter
var searchData = {
@@ -2264,26 +2250,26 @@ QUnit.module('ActionManager', {
actionManager.trigger_up('search', searchData);
// Sort records
- actionManager.$('.o_list_view th.o_column_sortable').click();
+ await testUtils.dom.click(actionManager.$('.o_list_view th.o_column_sortable'));
// get to the form view of the model, on the first record
- actionManager.$('.o_data_cell:first').click();
+ await testUtils.dom.click(actionManager.$('.o_data_cell:first'));
// Change model by clicking on the button within the form
- actionManager.$('.o_form_view button').click();
+ await testUtils.dom.click(actionManager.$('.o_form_view button'));
actionManager.destroy();
});
- QUnit.test('breadcrumbs are updated when switching between views', function (assert) {
+ QUnit.test('breadcrumbs are updated when switching between views', async function (assert) {
assert.expect(10);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should be one controller in the breadcrumbs");
@@ -2291,28 +2277,28 @@ QUnit.module('ActionManager', {
"breadcrumbs should display the display_name of the action");
// switch to kanban view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should still be one controller in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners',
"breadcrumbs should still display the display_name of the action");
// switch back to list view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should still be one controller in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners',
"breadcrumbs should still display the display_name of the action");
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should be two controllers in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record',
"breadcrumbs should contain the display_name of the opened record");
// go back to list view using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should be one controller in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(), 'Partners',
@@ -2321,15 +2307,15 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('switch buttons are updated when switching between views', function (assert) {
+ QUnit.test('switch buttons are updated when switching between views', async function (assert) {
assert.expect(13);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
"should have two switch buttons (list and kanban)");
@@ -2341,7 +2327,7 @@ QUnit.module('ActionManager', {
"list should be the active view");
// switch to kanban view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
"should still have two switch buttons (list and kanban)");
assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button.active').length, 1,
@@ -2352,19 +2338,19 @@ QUnit.module('ActionManager', {
"kanban should now be the active view");
// switch back to list view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
"should still have two switch buttons (list and kanban)");
assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active',
"list should now be the active view");
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 0,
"should not have any switch buttons");
// go back to list view using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.strictEqual($('.o_control_panel .o_cp_switch_buttons button').length, 2,
"should have two switch buttons (list and kanban)");
assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active',
@@ -2373,15 +2359,15 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('pager is updated when switching between views', function (assert) {
+ QUnit.test('pager is updated when switching between views', async function (assert) {
assert.expect(10);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-5',
"value should be correct for kanban");
@@ -2389,28 +2375,28 @@ QUnit.module('ActionManager', {
"limit should be correct for kanban");
// switch to list view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-3',
"value should be correct for list");
assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5',
"limit should be correct for list");
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1',
"value should be correct for form");
assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '3',
"limit should be correct for form");
// go back to list view using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-3',
"value should be correct for list");
assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5',
"limit should be correct for list");
// switch back to kanban view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.strictEqual($('.o_control_panel .o_pager_value').text(), '1-5',
"value should be correct for kanban");
assert.strictEqual($('.o_control_panel .o_pager_limit').text(), '5',
@@ -2419,50 +2405,52 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('there is no flickering when switching between views', function (assert) {
+ QUnit.test('there is no flickering when switching between views', async function (assert) {
assert.expect(20);
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function () {
var result = this._super.apply(this, arguments);
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// switch to kanban view
- def = $.Deferred();
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.containsOnce(actionManager, '.o_list_view',
"should still display the list view");
assert.containsNone(actionManager, '.o_kanban_view',
"shouldn't display the kanban view yet");
def.resolve();
+ await testUtils.nextTick();
assert.containsNone(actionManager, '.o_list_view',
"shouldn't display the list view anymore");
assert.containsOnce(actionManager, '.o_kanban_view',
"should now display the kanban view");
// switch back to list view
- def = $.Deferred();
- testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_list'));
assert.containsOnce(actionManager, '.o_kanban_view',
"should still display the kanban view");
assert.containsNone(actionManager, '.o_list_view',
"shouldn't display the list view yet");
def.resolve();
+ await testUtils.nextTick();
assert.containsNone(actionManager, '.o_kanban_view',
"shouldn't display the kanban view anymore");
assert.containsOnce(actionManager, '.o_list_view',
"should now display the list view");
// open a record in form view
- def = $.Deferred();
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.containsOnce(actionManager, '.o_list_view',
"should still display the list view");
assert.containsNone(actionManager, '.o_form_view',
@@ -2470,6 +2458,7 @@ QUnit.module('ActionManager', {
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should still be one controller in the breadcrumbs");
def.resolve();
+ await testUtils.nextTick();
assert.containsNone(actionManager, '.o_list_view',
"should no longer display the list view");
assert.containsOnce(actionManager, '.o_form_view',
@@ -2478,8 +2467,8 @@ QUnit.module('ActionManager', {
"there should be two controllers in the breadcrumbs");
// go back to list view using the breadcrumbs
- def = $.Deferred();
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
assert.containsOnce(actionManager, '.o_form_view',
"should still display the form view");
assert.containsNone(actionManager, '.o_list_view',
@@ -2487,6 +2476,7 @@ QUnit.module('ActionManager', {
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should still be two controllers in the breadcrumbs");
def.resolve();
+ await testUtils.nextTick();
assert.containsNone(actionManager, '.o_form_view',
"should no longer display the form view");
assert.containsOnce(actionManager, '.o_list_view',
@@ -2497,27 +2487,27 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('breadcrumbs are updated when display_name changes', function (assert) {
+ QUnit.test('breadcrumbs are updated when display_name changes', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should be two controllers in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record',
"breadcrumbs should contain the display_name of the opened record");
// switch to edit mode and change the display_name
- testUtils.dom.click($('.o_control_panel .o_form_button_edit'));
- testUtils.fields.editInput(actionManager.$('.o_field_widget[name=display_name]'), 'New name');
- testUtils.dom.click($('.o_control_panel .o_form_button_save'));
+ await testUtils.dom.click($('.o_control_panel .o_form_button_edit'));
+ await testUtils.fields.editInput(actionManager.$('.o_field_widget[name=display_name]'), 'New name');
+ await testUtils.dom.click($('.o_control_panel .o_form_button_save'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should still be two controllers in the breadcrumbs");
@@ -2527,10 +2517,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('reload previous controller when discarding a new record', function (assert) {
+ QUnit.test('reload previous controller when discarding a new record', async function (assert) {
assert.expect(8);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2539,15 +2529,15 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// create a new record
- testUtils.dom.click($('.o_control_panel .o_list_button_add'));
+ await testUtils.dom.click($('.o_control_panel .o_list_button_add'));
assert.containsOnce(actionManager, '.o_form_view.o_form_editable',
"should have opened the form view in edit mode");
// discard
- testUtils.dom.click($('.o_control_panel .o_form_button_cancel'));
+ await testUtils.dom.click($('.o_control_panel .o_form_button_cancel'));
assert.containsOnce(actionManager, '.o_list_view',
"should have switched back to the list view");
@@ -2562,11 +2552,11 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('requests for execute_action of type object are handled', function (assert) {
+ QUnit.test('requests for execute_action of type object are handled', async function (assert) {
assert.expect(10);
var self = this;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2580,7 +2570,7 @@ QUnit.module('ActionManager', {
}, "should call route with correct arguments");
var record = _.findWhere(self.data.partner.records, {id: args.args[0][0]});
record.foo = 'value changed';
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
@@ -2588,15 +2578,15 @@ QUnit.module('ActionManager', {
some_key: 2,
}},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop',
"check initial value of 'yop' field");
// click on 'Call method' button (should call an Object method)
- testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)'));
+ await testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)'));
assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'value changed',
"'yop' has been changed by the server, and should be updated in the UI");
@@ -2612,10 +2602,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('requests for execute_action of type action are handled', function (assert) {
+ QUnit.test('requests for execute_action of type action are handled', async function (assert) {
assert.expect(11);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2624,15 +2614,15 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// click on 'Execute action' button (should execute an action)
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should be two parts in the breadcrumbs");
- testUtils.dom.click(actionManager.$('.o_form_view button:contains(Execute action)'));
+ await testUtils.dom.click(actionManager.$('.o_form_view button:contains(Execute action)'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 3,
"the returned action should have been stacked over the previous one");
assert.containsOnce(actionManager, '.o_kanban_view',
@@ -2651,42 +2641,42 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('requests for execute_action of type object: disable buttons', function (assert) {
+ QUnit.test('requests for execute_action of type object: disable buttons', async function (assert) {
assert.expect(2);
- var self = this;
var def;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_button') {
- return $.when(false);
+ return Promise.resolve(false);
} else if (args.method === 'read') {
// Block the 'read' call
var result = this._super.apply(this, arguments);
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// click on 'Call method' button (should call an Object method)
- def = $.Deferred();
- testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click(actionManager.$('.o_form_view button:contains(Call method)'));
// Buttons should be disabled
assert.strictEqual(
actionManager.$('.o_form_view button:contains(Call method)').attr('disabled'),
- 'disabled', 'buttons should be disabled')
+ 'disabled', 'buttons should be disabled');
// Release the 'read' call
def.resolve();
+ await testUtils.nextTick();
// Buttons should be enabled after the reload
assert.strictEqual(
@@ -2696,10 +2686,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('can open different records from a multi record view', function (assert) {
+ QUnit.test('can open different records from a multi record view', async function (assert) {
assert.expect(11);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -2708,20 +2698,20 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open the first record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record',
"breadcrumbs should contain the display_name of the opened record");
assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'yop',
"should have opened the correct record");
// go back to list view using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a'));
// open the second record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:nth(1)'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:nth(1)'));
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Second record',
"breadcrumbs should contain the display_name of the opened record");
assert.strictEqual(actionManager.$('.o_field_widget[name=foo]').text(), 'blip',
@@ -2739,18 +2729,18 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('restore previous view state when switching back', function (assert) {
+ QUnit.test('restore previous view state when switching back', async function (assert) {
assert.expect(5);
this.actions[2].views.unshift([false, 'graph']);
this.archs['partner,false,graph'] = '<graph></graph>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.hasClass($('.o_control_panel .fa-bar-chart-o'),'active',
"bar chart button is active");
@@ -2758,22 +2748,22 @@ QUnit.module('ActionManager', {
"line chart button is not active");
// display line chart
- testUtils.dom.click($('.o_control_panel .fa-area-chart'));
+ await testUtils.dom.click($('.o_control_panel .fa-area-chart'));
assert.hasClass($('.o_control_panel .fa-area-chart'),'active',
"line chart button is now active");
// switch to kanban and back to graph view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.strictEqual($('.o_control_panel .fa-area-chart').length, 0,
"graph buttons are no longer in control panel");
- testUtils.dom.click($('.o_control_panel .o_cp_switch_graph'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_graph'));
assert.hasClass($('.o_control_panel .fa-area-chart'),'active',
"line chart button is still active");
actionManager.destroy();
});
- QUnit.test('view switcher is properly highlighted in graph view', function (assert) {
+ QUnit.test('view switcher is properly highlighted in graph view', async function (assert) {
assert.expect(4);
// note: this test should be moved to graph tests ?
@@ -2781,12 +2771,12 @@ QUnit.module('ActionManager', {
this.actions[2].views.splice(1, 1, [false, 'graph']);
this.archs['partner,false,graph'] = '<graph></graph>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.hasClass($('.o_control_panel .o_cp_switch_list'),'active',
"list button in control panel is active");
@@ -2794,7 +2784,7 @@ QUnit.module('ActionManager', {
"graph button in control panel is not active");
// switch to graph view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_graph'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_graph'));
assert.doesNotHaveClass($('.o_control_panel .o_cp_switch_list'), 'active',
"list button in control panel is not active");
assert.hasClass($('.o_control_panel .o_cp_switch_graph'),'active',
@@ -2802,7 +2792,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('can interact with search view', function (assert) {
+ QUnit.test('can interact with search view', async function (assert) {
assert.expect(2);
this.archs['partner,false,search'] = '<search>'+
@@ -2810,21 +2800,21 @@ QUnit.module('ActionManager', {
'<filter name="foo" string="foo" context="{\'group_by\': \'foo\'}"/>' +
'</group>'+
'</search>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.doesNotHaveClass(actionManager.$('.o_list_view'), 'o_list_view_grouped',
"list view is not grouped");
// open group by dropdown
- testUtils.dom.click($('.o_control_panel .o_cp_right button:contains(Group By)'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_right button:contains(Group By)'));
// click on first link
- testUtils.dom.click($('.o_control_panel .o_group_by_menu a:first'));
+ await testUtils.dom.click($('.o_control_panel .o_group_by_menu a:first'));
assert.hasClass(actionManager.$('.o_list_view'),'o_list_view_grouped',
'list view is now grouped');
@@ -2832,7 +2822,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('can open a many2one external window', function (assert) {
+ QUnit.test('can open a many2one external window', async function (assert) {
// AAB: this test could be merged with 'many2ones in form views' in relational_fields_tests.js
assert.expect(8);
@@ -2849,27 +2839,27 @@ QUnit.module('ActionManager', {
'</group>' +
'</form>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
assert.step(route);
if (args.method === "get_formview_id") {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open first record in form view
- testUtils.dom.click(actionManager.$('.o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_data_row:first'));
// click on edit
- testUtils.dom.click($('.o_control_panel .o_form_button_edit'));
+ await testUtils.dom.click($('.o_control_panel .o_form_button_edit'));
// click on external button for m2o
- testUtils.dom.click(actionManager.$('.o_external_button'));
+ await testUtils.dom.click(actionManager.$('.o_external_button'));
assert.verifySteps([
'/web/action/load', // initial load action
'/web/dataset/call_kw/partner', // load views
@@ -2882,41 +2872,41 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('ask for confirmation when leaving a "dirty" view', function (assert) {
+ QUnit.test('ask for confirmation when leaving a "dirty" view', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(4);
+ await actionManager.doAction(4);
// open record in form view
- testUtils.dom.click(actionManager.$('.o_kanban_record:first'));
+ await testUtils.dom.click(actionManager.$('.o_kanban_record:first'));
// edit record
- testUtils.dom.click($('.o_control_panel button.o_form_button_edit'));
- testUtils.fields.editInput(actionManager.$('input[name="foo"]'), 'pinkypie');
+ await testUtils.dom.click($('.o_control_panel button.o_form_button_edit'));
+ await testUtils.fields.editInput(actionManager.$('input[name="foo"]'), 'pinkypie');
// go back to kanban view
- testUtils.dom.click($('.o_control_panel .breadcrumb-item:first a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb-item:first a'));
assert.strictEqual($('.modal .modal-body').text(),
"The record has been modified, your changes will be discarded. Do you want to proceed?",
"should display a modal dialog to confirm discard action");
// cancel
- testUtils.dom.click($('.modal .modal-footer button.btn-secondary'));
+ await testUtils.dom.click($('.modal .modal-footer button.btn-secondary'));
assert.containsOnce(actionManager, '.o_form_view',
"should still be in form view");
// go back again to kanban view
- testUtils.dom.click($('.o_control_panel .breadcrumb-item:first a'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb-item:first a'));
// confirm discard
- testUtils.dom.click($('.modal .modal-footer button.btn-primary'));
+ await testUtils.dom.click($('.modal .modal-footer button.btn-primary'));
assert.containsNone(actionManager, '.o_form_view',
"should no longer be in form view");
@@ -2926,22 +2916,22 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('limit set in action is passed to each created controller', function (assert) {
+ QUnit.test('limit set in action is passed to each created controller', async function (assert) {
assert.expect(2);
_.findWhere(this.actions, {id: 3}).limit = 2;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.containsN(actionManager, '.o_data_row', 2,
"should only display 2 record");
// switch to kanban view
- testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_switch_kanban'));
assert.strictEqual(actionManager.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2,
"should only display 2 record");
@@ -2949,44 +2939,44 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('go back to a previous action using the breadcrumbs', function (assert) {
+ QUnit.test('go back to a previous action using the breadcrumbs', async function (assert) {
assert.expect(10);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open a record in form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should be two controllers in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record',
"breadcrumbs should contain the display_name of the opened record");
// push another action on top of the first one, and come back to the form view
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 3,
"there should be three controllers in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Partners Action 4',
"breadcrumbs should contain the name of the current action");
// go back using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a:nth(1)'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:nth(1)'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
"there should be two controllers in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'First record',
"breadcrumbs should contain the display_name of the opened record");
// push again the other action on top of the first one, and come back to the list view
- actionManager.doAction(4);
+ await actionManager.doAction(4);
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 3,
"there should be three controllers in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Partners Action 4',
"breadcrumbs should contain the name of the current action");
// go back using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 1,
"there should be one controller in the breadcrumbs");
assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Partners',
@@ -2995,32 +2985,33 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('form views are restored in readonly when coming back in breadcrumbs', function (assert) {
+ QUnit.test('form views are restored in readonly when coming back in breadcrumbs', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open a record in form view
- actionManager.$('.o_list_view .o_data_row:first').click();
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// switch to edit mode
- $('.o_control_panel .o_form_button_edit').click();
+ await testUtils.dom.click($('.o_control_panel .o_form_button_edit'));
- assert.ok(actionManager.$('.o_form_view').hasClass('o_form_editable'));
+ assert.hasClass(actionManager.$('.o_form_view'), 'o_form_editable');
// do some other action
- actionManager.doAction(4);
+ await actionManager.doAction(4);
// go back to form view
- $('.o_control_panel .breadcrumb a').last().click();
- assert.ok(actionManager.$('.o_form_view').hasClass('o_form_readonly'));
+ await testUtils.dom.clickLast($('.o_control_panel .breadcrumb a'));
+ await testUtils.nextTick();
+ assert.hasClass(actionManager.$('.o_form_view'), 'o_form_readonly');
actionManager.destroy();
});
- QUnit.test('honor group_by specified in actions context', function (assert) {
+ QUnit.test('honor group_by specified in actions context', async function (assert) {
assert.expect(5);
_.findWhere(this.actions, {id: 3}).context = "{'group_by': 'bar'}";
@@ -3030,12 +3021,12 @@ QUnit.module('ActionManager', {
'</group>'+
'</search>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.containsOnce(actionManager, '.o_list_view_grouped',
"should be grouped");
@@ -3043,14 +3034,14 @@ QUnit.module('ActionManager', {
"should be grouped by 'bar' (two groups) at first load");
// groupby 'bar' using the searchview
- testUtils.dom.click($('.o_control_panel .o_cp_right button:contains(Group By)'));
- testUtils.dom.click($('.o_control_panel .o_group_by_menu a:first'));
+ await testUtils.dom.click($('.o_control_panel .o_cp_right button:contains(Group By)'));
+ await testUtils.dom.click($('.o_control_panel .o_group_by_menu a:first'));
assert.containsN(actionManager, '.o_group_header', 5,
"should be grouped by 'foo' (five groups)");
// remove the groupby in the searchview
- testUtils.dom.click($('.o_control_panel .o_searchview .o_facet_remove'));
+ await testUtils.dom.click($('.o_control_panel .o_searchview .o_facet_remove'));
assert.containsOnce(actionManager, '.o_list_view_grouped',
"should still be grouped");
@@ -3060,7 +3051,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('switch request to unknown view type', function (assert) {
+ QUnit.test('switch request to unknown view type', async function (assert) {
assert.expect(7);
this.actions.push({
@@ -3071,7 +3062,7 @@ QUnit.module('ActionManager', {
views: [[false, 'list'], [1, 'kanban']], // no form view
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3080,7 +3071,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(33);
+ await actionManager.doAction(33);
assert.containsOnce(actionManager, '.o_list_view',
"should display the list view");
@@ -3101,7 +3092,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('save current search', function (assert) {
+ QUnit.test('save current search', async function (assert) {
assert.expect(4);
testUtils.mock.patch(ListController, {
@@ -3126,7 +3117,7 @@ QUnit.module('ActionManager', {
views: [[false, 'list']],
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3140,59 +3131,59 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(33);
+ await actionManager.doAction(33);
assert.containsN(actionManager, '.o_data_row', 5,
"should contain 5 records");
// filter on bar
- testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Filters)'));
- testUtils.dom.click($('.o_control_panel .o_filters_menu a:contains(Bar)'));
+ await testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Filters)'));
+ await testUtils.dom.click($('.o_control_panel .o_filters_menu a:contains(Bar)'));
assert.containsN(actionManager, '.o_data_row', 2);
// save filter
- testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Favorites)'));
- testUtils.dom.click($('.o_control_panel .o_add_favorite'));
+ await testUtils.dom.click($('.o_control_panel .o_search_options .o_dropdown_toggler_btn:contains(Favorites)'));
+ await testUtils.dom.click($('.o_control_panel .o_add_favorite'));
$('.o_control_panel .o_favorite_name input[type=text]').val('some name'); // name the filter
- testUtils.dom.click($('.o_control_panel .o_save_favorite button'));
+ await testUtils.dom.click($('.o_control_panel .o_save_favorite button'));
testUtils.mock.unpatch(ListController);
actionManager.destroy();
});
- QUnit.test("search menus are still available when switching between actions", function (assert) {
+ QUnit.test("search menus are still available when switching between actions", async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1,
"the search options should be available");
- actionManager.doAction(3);
+ await actionManager.doAction(3);
assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1,
"the search options should be available");
// go back using the breadcrumbs
- testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
assert.strictEqual($('.o_search_options .o_dropdown:visible .o_filters_menu').length, 1,
"the search options should be available");
actionManager.destroy();
});
- QUnit.test("current act_window action is stored in session_storage", function (assert) {
+ QUnit.test("current act_window action is stored in session_storage", async function (assert) {
assert.expect(1);
var expectedAction = _.extend({}, _.findWhere(this.actions, {id: 3}), {
context: {},
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3206,12 +3197,12 @@ QUnit.module('ActionManager', {
},
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
actionManager.destroy();
});
- QUnit.test("store evaluated context of current action in session_storage", function (assert) {
+ QUnit.test("store evaluated context of current action in session_storage", async function (assert) {
// this test ensures that we don't store stringified instances of
// CompoundContext in the session_storage, as they would be meaningless
// once restored
@@ -3225,7 +3216,7 @@ QUnit.module('ActionManager', {
},
});
var checkSessionStorage = false;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3242,22 +3233,50 @@ QUnit.module('ActionManager', {
});
// execute an action and open a record in form view
- actionManager.doAction(3);
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await actionManager.doAction(3);
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
// click on 'Execute action' button (it executes an action with a CompoundContext as context)
checkSessionStorage = true;
- testUtils.dom.click(actionManager.$('.o_form_view button:contains(Execute action)'));
+ await testUtils.dom.click(actionManager.$('.o_form_view button:contains(Execute action)'));
+
+ actionManager.destroy();
+ });
+
+ QUnit.test("destroy action with lazy loaded controller", async function (assert) {
+ assert.expect(6);
+
+ var actionManager = await createActionManager({
+ actions: this.actions,
+ archs: this.archs,
+ data: this.data,
+ });
+ await actionManager.loadState({
+ action: 3,
+ id: 2,
+ view_type: 'form',
+ });
+ assert.containsNone(actionManager, '.o_list_view');
+ assert.containsOnce(actionManager, '.o_form_view');
+ assert.strictEqual($('.o_control_panel .breadcrumb-item').length, 2,
+ "there should be two controllers in the breadcrumbs");
+ assert.strictEqual($('.o_control_panel .breadcrumb-item:last').text(), 'Second record',
+ "breadcrumbs should contain the display_name of the opened record");
+
+ await actionManager.doAction(1, {clear_breadcrumbs: true});
+
+ assert.containsNone(actionManager, '.o_form_view');
+ assert.containsOnce(actionManager, '.o_kanban_view');
actionManager.destroy();
});
QUnit.module('Actions in target="new"');
- QUnit.test('can execute act_window actions in target="new"', function (assert) {
+ QUnit.test('can execute act_window actions in target="new"', async function (assert) {
assert.expect(7);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3266,7 +3285,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(5);
+ await actionManager.doAction(5);
assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
"should have rendered a form view in a modal");
@@ -3284,32 +3303,32 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('chained action on_close', function (assert) {
+ QUnit.test('chained action on_close', async function (assert) {
assert.expect(3);
function on_close() {
assert.step('Close Action');
};
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(5, {on_close: on_close});
+ await actionManager.doAction(5, {on_close: on_close});
// a target=new action shouldn't activate the on_close
- actionManager.doAction(5);
+ await actionManager.doAction(5);
assert.verifySteps([]);
// An act_window_close should trigger the on_close
- actionManager.doAction(10);
+ await actionManager.doAction(10);
assert.verifySteps(['Close Action']);
actionManager.destroy();
});
- QUnit.test('footer buttons are moved to the dialog footer', function (assert) {
+ QUnit.test('footer buttons are moved to the dialog footer', async function (assert) {
assert.expect(3);
this.archs['partner,false,form'] = '<form>' +
@@ -3319,12 +3338,12 @@ QUnit.module('ActionManager', {
'</footer>' +
'</form>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(5);
+ await actionManager.doAction(5);
assert.strictEqual($('.o_technical_modal .modal-body button.infooter').length, 0,
"the button should not be in the body");
@@ -3336,7 +3355,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('on_attach_callback is called for actions in target="new"', function (assert) {
+ QUnit.test('on_attach_callback is called for actions in target="new"', async function (assert) {
assert.expect(4);
var ClientAction = AbstractAction.extend({
@@ -3351,12 +3370,12 @@ QUnit.module('ActionManager', {
});
core.action_registry.add('test', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction({
+ await actionManager.doAction({
tag: 'test',
target: 'new',
type: 'ir.actions.client',
@@ -3372,10 +3391,10 @@ QUnit.module('ActionManager', {
QUnit.module('Actions in target="inline"');
- QUnit.test('form views for actions in target="inline" open in edit mode', function (assert) {
+ QUnit.test('form views for actions in target="inline" open in edit mode', async function (assert) {
assert.expect(5);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3384,7 +3403,7 @@ QUnit.module('ActionManager', {
return this._super.apply(this, arguments);
},
});
- actionManager.doAction(6);
+ await actionManager.doAction(6);
assert.containsOnce(actionManager, '.o_form_view.o_form_editable',
"should have rendered a form view in edit mode");
@@ -3400,11 +3419,11 @@ QUnit.module('ActionManager', {
QUnit.module('Actions in target="fullscreen"');
- QUnit.test('correctly execute act_window actions in target="fullscreen"', function (assert) {
+ QUnit.test('correctly execute act_window actions in target="fullscreen"', async function (assert) {
assert.expect(7);
this.actions[0].target = 'fullscreen';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3418,7 +3437,7 @@ QUnit.module('ActionManager', {
},
},
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.strictEqual($('.o_control_panel').length, 1,
"should have rendered a control panel");
@@ -3434,7 +3453,7 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('fullscreen on action change: back to a "current" action', function (assert) {
+ QUnit.test('fullscreen on action change: back to a "current" action', async function (assert) {
assert.expect(3);
this.actions[0].target = 'fullscreen';
@@ -3442,7 +3461,7 @@ QUnit.module('ActionManager', {
'<button name="1" type="action" class="oe_stat_button" />' +
'</form>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3467,18 +3486,18 @@ QUnit.module('ActionManager', {
});
var toggleFullscreenCalls = 0;
- actionManager.doAction(6);
+ await actionManager.doAction(6);
toggleFullscreenCalls = 1;
- actionManager.$('button[name=1]').click();
+ await testUtils.dom.click(actionManager.$('button[name=1]'));
toggleFullscreenCalls = 2;
- $('.breadcrumb li a:first').click();
+ await testUtils.dom.click(actionManager.$('.breadcrumb li a:first'));
actionManager.destroy();
});
- QUnit.test('fullscreen on action change: all "fullscreen" actions', function (assert) {
+ QUnit.test('fullscreen on action change: all "fullscreen" actions', async function (assert) {
assert.expect(3);
this.actions[5].target = 'fullscreen';
@@ -3486,7 +3505,7 @@ QUnit.module('ActionManager', {
'<button name="1" type="action" class="oe_stat_button" />' +
'</form>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3498,33 +3517,33 @@ QUnit.module('ActionManager', {
},
});
- actionManager.doAction(6);
+ await actionManager.doAction(6);
- actionManager.$('button[name=1]').click();
+ await testUtils.dom.click(actionManager.$('button[name=1]'));
- $('.breadcrumb li a:first').click();
+ await testUtils.dom.click(actionManager.$('.breadcrumb li a:first'));
actionManager.destroy();
});
QUnit.module('"ir.actions.act_window_close" actions');
- QUnit.test('close the currently opened dialog', function (assert) {
+ QUnit.test('close the currently opened dialog', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
// execute an action in target="new"
- actionManager.doAction(5);
+ await actionManager.doAction(5);
assert.strictEqual($('.o_technical_modal .o_form_view').length, 1,
"should have rendered a form view in a modal");
// execute an 'ir.actions.act_window_close' action
- actionManager.doAction({
+ await actionManager.doAction({
type: 'ir.actions.act_window_close',
});
assert.strictEqual($('.o_technical_modal').length, 0,
@@ -3533,37 +3552,37 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('execute "on_close" only if there is no dialog to close', function (assert) {
+ QUnit.test('execute "on_close" only if there is no dialog to close', async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
// execute an action in target="new"
- actionManager.doAction(5);
+ await actionManager.doAction(5);
var options = {
on_close: assert.step.bind(assert, 'on_close'),
};
// execute an 'ir.actions.act_window_close' action
// should not call 'on_close' as there is a dialog to close
- actionManager.doAction({type: 'ir.actions.act_window_close'}, options);
+ await actionManager.doAction({type: 'ir.actions.act_window_close'}, options);
assert.verifySteps([]);
// execute again an 'ir.actions.act_window_close' action
// should call 'on_close' as there is no dialog to close
- actionManager.doAction({type: 'ir.actions.act_window_close'}, options);
+ await actionManager.doAction({type: 'ir.actions.act_window_close'}, options);
assert.verifySteps(['on_close']);
actionManager.destroy();
});
- QUnit.test('doAction resolved with an action', function (assert) {
+ QUnit.test('doAction resolved with an action', async function (assert) {
assert.expect(4);
this.actions.push({
@@ -3572,13 +3591,13 @@ QUnit.module('ActionManager', {
type: 'ir.actions.act_window_close',
});
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(21).then(function (action) {
+ await actionManager.doAction(21).then(function (action) {
assert.ok(action, "doAction should be resolved with an action");
assert.strictEqual(action.id, 21,
"should be resolved with correct action id");
@@ -3590,10 +3609,10 @@ QUnit.module('ActionManager', {
});
});
- QUnit.test('close action with provided infos', function (assert) {
+ QUnit.test('close action with provided infos', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3606,7 +3625,7 @@ QUnit.module('ActionManager', {
}
};
- actionManager.doAction({
+ await actionManager.doAction({
type: 'ir.actions.act_window_close',
infos: 'just for testing',
}, options);
@@ -3614,17 +3633,17 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('history back calls on_close handler of dialog action', function (assert) {
+ QUnit.test('history back calls on_close handler of dialog action', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
// open a new dialog form
- actionManager.doAction(this.actions[4], {
+ await actionManager.doAction(this.actions[4], {
on_close: function () {
assert.step('on_close');
},
@@ -3636,10 +3655,10 @@ QUnit.module('ActionManager', {
actionManager.destroy();
});
- QUnit.test('properly drop client actions after new action is initiated', function (assert) {
+ QUnit.test('properly drop client actions after new action is initiated', async function (assert) {
assert.expect(1);
- var slowWillStartDef = $.Deferred();
+ var slowWillStartDef = testUtils.makeTestPromise();
var ClientAction = AbstractAction.extend({
willStart: function () {
@@ -3649,7 +3668,7 @@ QUnit.module('ActionManager', {
core.action_registry.add('slowAction', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3657,6 +3676,7 @@ QUnit.module('ActionManager', {
actionManager.doAction('slowAction');
actionManager.doAction(4);
slowWillStartDef.resolve();
+ await testUtils.nextTick();
assert.containsOnce(actionManager, '.o_kanban_view',
'should have loaded a kanban view');
@@ -3665,17 +3685,17 @@ QUnit.module('ActionManager', {
});
- QUnit.test('abstract action does not crash on navigation_moves', function (assert) {
+ QUnit.test('abstract action does not crash on navigation_moves', async function (assert) {
assert.expect(1);
var ClientAction = AbstractAction.extend({
});
core.action_registry.add('ClientAction', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction('ClientAction');
+ await actionManager.doAction('ClientAction');
actionManager.trigger_up('navigation_move', {direction:'down'});
assert.ok(true); // no error so it's good
@@ -3683,10 +3703,8 @@ QUnit.module('ActionManager', {
delete core.action_registry.ClientAction;
});
- QUnit.test('fields in abstract action does not crash on navigation_moves', function (assert) {
+ QUnit.test('fields in abstract action does not crash on navigation_moves', async function (assert) {
assert.expect(1);
- var self = this;
-
// create a client action with 2 input field
var inputWidget;
var secondInputWidget;
@@ -3716,12 +3734,12 @@ QUnit.module('ActionManager', {
}
});
core.action_registry.add('ClientAction', ClientAction);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction('ClientAction');
+ await actionManager.doAction('ClientAction');
inputWidget.$el[0].focus();
var event = $.Event('keydown', {
which: $.ui.keyCode.TAB,
@@ -3735,12 +3753,12 @@ QUnit.module('ActionManager', {
delete core.action_registry.ClientAction;
});
- QUnit.test('web client is not deadlocked when a view crashes', function (assert) {
+ QUnit.test('web client is not deadlocked when a view crashes', async function (assert) {
assert.expect(3);
- var readOnFirstRecordDef = $.Deferred();
+ var readOnFirstRecordDef = testUtils.makeTestPromise();
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -3752,11 +3770,11 @@ QUnit.module('ActionManager', {
}
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
// open first record in form view. this will crash and will not
// display a form view
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:first'));
readOnFirstRecordDef.reject("not working as intended");
@@ -3764,7 +3782,7 @@ QUnit.module('ActionManager', {
"there should still be a list view in dom");
// open another record, the read will not crash
- testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:eq(2)'));
+ await testUtils.dom.click(actionManager.$('.o_list_view .o_data_row:eq(2)'));
assert.containsNone(actionManager, '.o_list_view',
"there should not be a list view in dom");
@@ -3777,7 +3795,7 @@ QUnit.module('ActionManager', {
QUnit.module('Search View Action');
- QUnit.test('search view should keep focus during do_search', function (assert) {
+ QUnit.test('search view should keep focus during do_search', async function (assert) {
assert.expect(5);
/* One should be able to type something in the search view, press on enter to
@@ -3787,48 +3805,46 @@ QUnit.module('ActionManager', {
* because of how native events are handled in tests
*/
- var searchDeferred = $.Deferred();
+ var searchPromise = testUtils.makeTestPromise();
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
mockRPC: function (route, args) {
if (route === '/web/dataset/search_read') {
assert.step('search_read ' + args.domain);
- if ( _.isEqual(args.domain, [['foo', 'ilike', 'm']])) {
- return searchDeferred.then(this._super.bind(this, route, args));
+ if (_.isEqual(args.domain, [['foo', 'ilike', 'm']])) {
+ return searchPromise.then(this._super.bind(this, route, args));
}
}
return this._super.apply(this, arguments);
- }
+ },
});
- actionManager.doAction(3);
+ await actionManager.doAction(3);
var $searchInput = $('.o_searchview input');
- $searchInput.val('m');
- $searchInput.trigger($.Event('keypress', {key: 'm', which: 109, keyCode: 109}));
- $searchInput.trigger($.Event('keydown', {key: 'Enter', which: 13, keyCode: 13}));
+ $searchInput.val('m'); // the searchbar checks the contents of the input on keypress events
+ await testUtils.fields.triggerKey('press', $searchInput, 'm');
+ await testUtils.fields.triggerKeydown($searchInput, 'enter');
assert.verifySteps(["search_read ",
"search_read foo,ilike,m"]);
// Triggering the do_search above will kill the current searchview Input
$searchInput = $('.o_searchview input');
- $searchInput.val('o');
- $searchInput.trigger($.Event('keypress', {key: 'o', which: 111, keyCode: 111}));
+ $searchInput.val('o'); // the searchbar checks the contents of the input on keypress events
+ await testUtils.fields.triggerKey('press', $searchInput, 'o');
// We have something in the input of the search view. Making the search_read
// return at this point will trigger the redraw of the view.
// However we want to hold on to what we just typed
- searchDeferred.resolve();
+ searchPromise.resolve();
+ await testUtils.nextTick();
+ await testUtils.fields.triggerKeydown($searchInput, 'enter');
- $searchInput.trigger($.Event('keydown', {key: 'Enter', which: 13, keyCode: 13}));
-
- assert.verifySteps(["search_read ",
- "search_read foo,ilike,m",
- "search_read |,foo,ilike,m,foo,ilike,o"]);
+ assert.verifySteps(["search_read |,foo,ilike,m,foo,ilike,o"]);
actionManager.destroy();
});
diff --git a/addons/web/static/tests/chrome/keyboard_navigation_mixin_tests.js b/addons/web/static/tests/chrome/keyboard_navigation_mixin_tests.js
index e26451cd268..da417deddf5 100644
--- a/addons/web/static/tests/chrome/keyboard_navigation_mixin_tests.js
+++ b/addons/web/static/tests/chrome/keyboard_navigation_mixin_tests.js
@@ -6,10 +6,14 @@ var testUtils = require('web.test_utils');
var Widget = require('web.Widget');
QUnit.module('KeyboardNavigationMixin', function () {
- QUnit.test('aria-keyshortcuts is added on elements with accesskey', function (assert) {
+ QUnit.test('aria-keyshortcuts is added on elements with accesskey', async function (assert) {
assert.expect(1);
var $target = $('#qunit-fixture');
var KeyboardWidget = Widget.extend(KeyboardNavigationMixin, {
+ init: function () {
+ this._super.apply(this, arguments);
+ KeyboardNavigationMixin.init.call(this);
+ },
start: function () {
var $button = $('<button>').text('Click Me!').attr('accesskey', 'o');
// we need to define the accesskey because it will not be assigned on invisible buttons
@@ -19,7 +23,7 @@ QUnit.module('KeyboardNavigationMixin', function () {
});
var parent = testUtils.createParent({});
var w = new KeyboardWidget(parent);
- w.appendTo($target);
+ await w.appendTo($target);
// minimum set of attribute to generate a native event that works with the mixin
var e = new Event("keydown");
@@ -32,7 +36,7 @@ QUnit.module('KeyboardNavigationMixin', function () {
parent.destroy();
});
- QUnit.test('keep CSS position absolute for parent of overlay', function (assert) {
+ QUnit.test('keep CSS position absolute for parent of overlay', async function (assert) {
// If we change the CSS position of an 'absolute' element to 'relative',
// we may likely change its position on the document. Since the overlay
// CSS position is 'absolute', it will match the size and cover the
@@ -42,6 +46,10 @@ QUnit.module('KeyboardNavigationMixin', function () {
var $target = $('#qunit-fixture');
var $button;
var KeyboardWidget = Widget.extend(KeyboardNavigationMixin, {
+ init: function () {
+ this._super.apply(this, arguments);
+ KeyboardNavigationMixin.init.call(this);
+ },
start: function () {
$button = $('<button>').text('Click Me!').attr('accesskey', 'o');
// we need to define the accesskey because it will not be assigned on invisible buttons
@@ -51,7 +59,7 @@ QUnit.module('KeyboardNavigationMixin', function () {
});
var parent = testUtils.createParent({});
var w = new KeyboardWidget(parent);
- w.appendTo($target);
+ await w.appendTo($target);
$button.css('position', 'absolute');
diff --git a/addons/web/static/tests/chrome/pager_tests.js b/addons/web/static/tests/chrome/pager_tests.js
index e089929abbc..18a4ae7fc37 100644
--- a/addons/web/static/tests/chrome/pager_tests.js
+++ b/addons/web/static/tests/chrome/pager_tests.js
@@ -9,40 +9,41 @@ QUnit.module('chrome', {}, function () {
QUnit.module('Pager');
- QUnit.test('basic stuff', function (assert) {
+ QUnit.test('basic stuff', async function (assert) {
assert.expect(2);
var pager = new Pager(null, 10, 1, 4);
pager.appendTo($('#qunit-fixture'));
+ await testUtils.nextTick();
assert.strictEqual(pager.state.current_min, 1,
"current_min should be set to 1");
// click on next
- testUtils.dom.click(pager.$('.o_pager_next'));
+ await testUtils.dom.click(pager.$('.o_pager_next'));
assert.strictEqual(pager.state.current_min, 5,
"current_min should now be 5");
pager.destroy();
});
- QUnit.test('edit the pager', function (assert) {
+ QUnit.test('edit the pager', async function (assert) {
assert.expect(5);
var pager = new Pager(null, 10, 1, 4);
pager.appendTo($('#qunit-fixture'));
+ await testUtils.nextTick();
// enter edition
- testUtils.dom.click(pager.$('.o_pager_value'));
+ await testUtils.dom.click(pager.$('.o_pager_value'));
assert.containsOnce(pager, 'input',
"the pager should contain an input");
assert.strictEqual(pager.$('input').val(), '1-4',
"the input should have correct value");
// change the limit
- pager.$('input')
- .val('1-6')
- .trigger($.Event('keydown', {which: $.ui.keyCode.ENTER})); // trigger the change
+ await testUtils.fields.editInput(pager.$('input'), '1-6');
+ await testUtils.fields.triggerKeydown(pager.$('input'), 'enter');
assert.strictEqual(pager.state.limit, 6,
"the limit should have been updated");
assert.strictEqual(pager.state.current_min, 1,
@@ -53,43 +54,40 @@ QUnit.module('chrome', {}, function () {
pager.destroy();
});
- QUnit.test('disabling the pager', function (assert) {
- var done = assert.async();
+ QUnit.test('disabling the pager', async function (assert) {
assert.expect(4);
var pager = new Pager(null, 10, 1, 4);
pager.appendTo($('#qunit-fixture'));
-
- pager.disable();
+ await testUtils.nextTick();
+ await pager.disable();
// try to go to the next or previous pages
- testUtils.dom.click(pager.$('.o_pager_next'));
+ await testUtils.dom.click(pager.$('.o_pager_next'));
assert.strictEqual(pager.state.current_min, 1,
"current_min should still be 1");
- testUtils.dom.click(pager.$('.o_pager_previous'));
+ await testUtils.dom.click(pager.$('.o_pager_previous'));
assert.strictEqual(pager.state.current_min, 1,
"current_min should still be 1");
// try to change the limit
- testUtils.dom.click(pager.$('.o_pager_value'));
+ await testUtils.dom.click(pager.$('.o_pager_value'));
assert.containsNone(pager, 'input',
"the pager should not contain an input");
// a common use is to disable the pager before reloading the data, and
// re-enable it once they have been loaded
- // the following imulates this situation
+ // the following emulates this situation
pager.on('pager_changed', null, function () {
pager.disable();
concurrency.delay(0).then(function () {
assert.ok(pager.disabled, "pager should still be disabled");
pager.destroy();
- done();
});
});
pager.enable();
- testUtils.dom.click(pager.$('.o_pager_next'));
-
+ await testUtils.dom.click(pager.$('.o_pager_next'));
});
});
-}); \ No newline at end of file
+});
diff --git a/addons/web/static/tests/chrome/user_menu_tests.js b/addons/web/static/tests/chrome/user_menu_tests.js
index 0151afdf6d6..73c74b0753c 100644
--- a/addons/web/static/tests/chrome/user_menu_tests.js
+++ b/addons/web/static/tests/chrome/user_menu_tests.js
@@ -8,14 +8,14 @@ var Widget = require('web.Widget');
QUnit.module('chrome', {}, function () {
QUnit.module('UserMenu');
- QUnit.test('basic rendering', function (assert) {
+ QUnit.test('basic rendering', async function (assert) {
assert.expect(3);
var parent = new Widget();
testUtils.mock.addMockEnvironment(parent, {});
var userMenu = new UserMenu(parent);
- userMenu.appendTo($('body'));
+ await userMenu.appendTo($('body'));
assert.strictEqual($('.o_user_menu').length, 1,
"should have a user menu in the DOM");
diff --git a/addons/web/static/tests/core/concurrency_tests.js b/addons/web/static/tests/core/concurrency_tests.js
index 516ce6a1b8f..1e195fde67d 100644
--- a/addons/web/static/tests/core/concurrency_tests.js
+++ b/addons/web/static/tests/core/concurrency_tests.js
@@ -2,166 +2,197 @@ odoo.define('web.concurrency_tests', function (require) {
"use strict";
var concurrency = require('web.concurrency');
+var testUtils = require('web.test_utils');
+
+var makeTestPromise = testUtils.makeTestPromise;
+var makeTestPromiseWithAssert = testUtils.makeTestPromiseWithAssert;
QUnit.module('core', {}, function () {
QUnit.module('concurrency');
+ QUnit.test('mutex: simple scheduling', async function (assert) {
+ assert.expect(5);
+ var mutex = new concurrency.Mutex();
- QUnit.test('mutex: simple scheduling', function (assert) {
- assert.expect(6);
+ var prom1 = makeTestPromiseWithAssert(assert, 'prom1');
+ var prom2 = makeTestPromiseWithAssert(assert, 'prom2');
- var m = new concurrency.Mutex();
+ mutex.exec(function () { return prom1; });
+ mutex.exec(function () { return prom2; });
- var def1 = $.Deferred(),
- def2 = $.Deferred();
+ assert.verifySteps([]);
- var p1 = m.exec(function () { return def1; });
- var p2 = m.exec(function () { return def2; });
+ await prom1.resolve();
- assert.strictEqual(p1.state(), "pending");
- assert.strictEqual(p2.state(), "pending");
+ assert.verifySteps(['ok prom1']);
- def1.resolve();
- assert.strictEqual(p1.state(), "resolved");
- assert.strictEqual(p2.state(), "pending");
+ await prom2.resolve();
- def2.resolve();
- assert.strictEqual(p1.state(), "resolved");
- assert.strictEqual(p2.state(), "resolved");
+ assert.verifySteps(['ok prom2']);
});
- QUnit.test('mutex: simpleScheduling2', function (assert) {
- assert.expect(6);
+ QUnit.test('mutex: simpleScheduling2', async function (assert) {
+ assert.expect(5);
+ var mutex = new concurrency.Mutex();
+
+ var prom1 = makeTestPromiseWithAssert(assert, 'prom1');
+ var prom2 = makeTestPromiseWithAssert(assert, 'prom2');
- var m = new concurrency.Mutex();
+ mutex.exec(function () { return prom1; });
+ mutex.exec(function () { return prom2; });
- var def1 = $.Deferred(),
- def2 = $.Deferred();
+ assert.verifySteps([]);
- var p1 = m.exec(function() { return def1; });
- var p2 = m.exec(function() { return def2; });
+ await prom2.resolve();
- assert.strictEqual(p1.state(), "pending");
- assert.strictEqual(p2.state(), "pending");
- def2.resolve();
+ assert.verifySteps(['ok prom2']);
- assert.strictEqual(p1.state(), "pending");
- assert.strictEqual(p2.state(), "pending");
+ await prom1.resolve();
- def1.resolve();
- assert.strictEqual(p1.state(), "resolved");
- assert.strictEqual(p2.state(), "resolved");
+ assert.verifySteps(['ok prom1']);
});
- QUnit.test('mutex: reject', function (assert) {
- assert.expect(12);
+ QUnit.test('mutex: reject', async function (assert) {
+ assert.expect(7);
+ var mutex = new concurrency.Mutex();
- var m = new concurrency.Mutex();
+ var prom1 = makeTestPromiseWithAssert(assert, 'prom1');
+ var prom2 = makeTestPromiseWithAssert(assert, 'prom2');
+ var prom3 = makeTestPromiseWithAssert(assert, 'prom3');
- var def1 = $.Deferred(),
- def2 = $.Deferred(),
- def3 = $.Deferred();
+ mutex.exec(function () { return prom1; }).catch(function () {});
+ mutex.exec(function () { return prom2; }).catch(function () {});
+ mutex.exec(function () { return prom3; }).catch(function () {});
- var p1 = m.exec(function() {return def1;});
- var p2 = m.exec(function() {return def2;});
- var p3 = m.exec(function() {return def3;});
+ assert.verifySteps([]);
- assert.strictEqual(p1.state(), "pending");
- assert.strictEqual(p2.state(), "pending");
- assert.strictEqual(p3.state(), "pending");
+ prom1.resolve();
+ await testUtils.nextMicrotaskTick();
- def1.resolve();
- assert.strictEqual(p1.state(), "resolved");
- assert.strictEqual(p2.state(), "pending");
- assert.strictEqual(p3.state(), "pending");
+ assert.verifySteps(['ok prom1']);
- def2.reject();
- assert.strictEqual(p1.state(), "resolved");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "pending");
+ prom2.catch(function () {
+ assert.verifySteps(['ko prom2']);
+ });
+ prom2.reject({name: "sdkjfmqsjdfmsjkdfkljsdq"});
+ await testUtils.nextMicrotaskTick();
+
+ prom3.resolve();
+ await testUtils.nextMicrotaskTick();
- def3.resolve();
- assert.strictEqual(p1.state(), "resolved");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "resolved");
+ assert.verifySteps(['ok prom3']);
});
- QUnit.test('mutex: getUnlockedDef checks', function (assert) {
- assert.expect(5);
+ QUnit.test('mutex: getUnlockedDef checks', async function (assert) {
+ assert.expect(9);
+
+ var mutex = new concurrency.Mutex();
- var m = new concurrency.Mutex();
+ var prom1 = makeTestPromiseWithAssert(assert, 'prom1');
+ var prom2 = makeTestPromiseWithAssert(assert, 'prom2');
- var def1 = $.Deferred();
- var def2 = $.Deferred();
+ mutex.getUnlockedDef().then(function () {
+ assert.step('mutex unlocked (1)');
+ });
+
+ await testUtils.nextMicrotaskTick();
- assert.strictEqual(m.getUnlockedDef().state(), "resolved");
+ assert.verifySteps(['mutex unlocked (1)']);
- m.exec(function() { return def1; });
+ mutex.exec(function () { return prom1; });
+ await testUtils.nextMicrotaskTick();
- var unlockedDef = m.getUnlockedDef();
+ mutex.getUnlockedDef().then(function () {
+ assert.step('mutex unlocked (2)');
+ });
- assert.strictEqual(unlockedDef.state(), "pending");
+ assert.verifySteps([]);
- m.exec(function() { return def2; });
+ mutex.exec(function () { return prom2; });
+ await testUtils.nextMicrotaskTick();
- assert.strictEqual(unlockedDef.state(), "pending");
+ assert.verifySteps([]);
- def1.resolve();
+ await prom1.resolve();
- assert.strictEqual(unlockedDef.state(), "pending");
+ assert.verifySteps(['ok prom1']);
- def2.resolve();
+ prom2.resolve();
+ await testUtils.nextTick();
- assert.strictEqual(unlockedDef.state(), "resolved");
+ assert.verifySteps(['ok prom2', 'mutex unlocked (2)']);
});
- QUnit.test('DropPrevious: basic usecase', function (assert) {
- assert.expect(5);
+ QUnit.test('DropPrevious: basic usecase', async function (assert) {
+ assert.expect(4);
+
+ var dp = new concurrency.DropPrevious();
+
+ var prom1 = makeTestPromise(assert, 'prom1');
+ var prom2 = makeTestPromise(assert, 'prom2');
+
+ dp.add(prom1).then(() => assert.step('should not go here'))
+ .catch(()=> assert.step("rejected dp1"));
+ dp.add(prom2).then(() => assert.step("ok dp2"));
+
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['rejected dp1']);
+
+ prom2.resolve();
+ await testUtils.nextMicrotaskTick();
+
+ assert.verifySteps(['ok dp2']);
+ });
+
+ QUnit.test('DropPrevious: resolve first before last', async function (assert) {
+ assert.expect(4);
var dp = new concurrency.DropPrevious();
- var def1 = $.Deferred();
- var def2 = $.Deferred();
+ var prom1 = makeTestPromise(assert, 'prom1');
+ var prom2 = makeTestPromise(assert, 'prom2');
- var r1 = dp.add(def1);
+ dp.add(prom1).then(() => assert.step('should not go here'))
+ .catch(()=> assert.step("rejected dp1"));
+ dp.add(prom2).then(() => assert.step("ok dp2"));
- assert.strictEqual(r1.state(), "pending");
- var r2 = dp.add(def2);
+ await testUtils.nextMicrotaskTick();
- assert.strictEqual(r1.state(), "rejected");
- assert.strictEqual(r2.state(), "pending");
+ assert.verifySteps(['rejected dp1']);
- def2.resolve();
+ prom1.resolve();
+ prom2.resolve();
+ await testUtils.nextMicrotaskTick();
- assert.strictEqual(r1.state(), "rejected");
- assert.strictEqual(r2.state(), "resolved");
+ assert.verifySteps(['ok dp2']);
});
- QUnit.test('DropMisordered: resolve all correctly ordered, sync', function (assert) {
+ QUnit.test('DropMisordered: resolve all correctly ordered, sync', async function (assert) {
assert.expect(1);
var dm = new concurrency.DropMisordered(),
flag = false;
- var d1 = $.Deferred(),
- d2 = $.Deferred();
+ var d1 = makeTestPromise();
+ var d2 = makeTestPromise();
var r1 = dm.add(d1),
r2 = dm.add(d2);
- $.when(r1, r2).done(function () {
+ Promise.all([r1, r2]).then(function () {
flag = true;
});
d1.resolve();
d2.resolve();
+ await testUtils.nextTick();
assert.ok(flag);
});
- QUnit.test("DropMisordered: don't resolve mis-ordered, sync", function (assert) {
+ QUnit.test("DropMisordered: don't resolve mis-ordered, sync", async function (assert) {
assert.expect(4);
var dm = new concurrency.DropMisordered(),
@@ -170,45 +201,47 @@ QUnit.module('core', {}, function () {
fail1 = false,
fail2 = false;
- var d1 = $.Deferred(),
- d2 = $.Deferred();
+ var d1 = makeTestPromise();
+ var d2 = makeTestPromise();
- dm.add(d1).done(function () { done1 = true; })
- .fail(function () { fail1 = true; });
- dm.add(d2).done(function () { done2 = true; })
- .fail(function () { fail2 = true; });
+ dm.add(d1).then(function () { done1 = true; })
+ .catch(function () { fail1 = true; });
+ dm.add(d2).then(function () { done2 = true; })
+ .catch(function () { fail2 = true; });
d2.resolve();
d1.resolve();
+ await testUtils.nextMicrotaskTick();
// d1 is in limbo
assert.ok(!done1);
assert.ok(!fail1);
- // d2 is resolved
+ // d2 is fulfilled
assert.ok(done2);
assert.ok(!fail2);
});
- QUnit.test('DropMisordered: fail mis-ordered flag, sync', function (assert) {
+ QUnit.test('DropMisordered: fail mis-ordered flag, sync', async function (assert) {
assert.expect(4);
- var dm = new concurrency.DropMisordered(true),
+ var dm = new concurrency.DropMisordered(true/* failMisordered */),
done1 = false,
done2 = false,
fail1 = false,
fail2 = false;
- var d1 = $.Deferred(),
- d2 = $.Deferred();
+ var d1 = makeTestPromise();
+ var d2 = makeTestPromise();
- dm.add(d1).done(function () { done1 = true; })
- .fail(function () { fail1 = true; });
- dm.add(d2).done(function () { done2 = true; })
- .fail(function () { fail2 = true; });
+ dm.add(d1).then(function () { done1 = true; })
+ .catch(function () { fail1 = true; });
+ dm.add(d2).then(function () { done2 = true; })
+ .catch(function () { fail2 = true; });
d2.resolve();
d1.resolve();
+ await testUtils.nextMicrotaskTick();
// d1 is in limbo
assert.ok(!done1);
@@ -225,8 +258,8 @@ QUnit.module('core', {}, function () {
var dm = new concurrency.DropMisordered();
- var d1 = $.Deferred(),
- d2 = $.Deferred();
+ var d1 = makeTestPromise();
+ var d2 = makeTestPromise();
var r1 = dm.add(d1),
r2 = dm.add(d2);
@@ -234,7 +267,7 @@ QUnit.module('core', {}, function () {
setTimeout(function () { d1.resolve(); }, 10);
setTimeout(function () { d2.resolve(); }, 20);
- $.when(r1, r2).done(function () {
+ Promise.all([r1, r2]).then(function () {
assert.ok(true);
done();
});
@@ -248,13 +281,13 @@ QUnit.module('core', {}, function () {
done1 = false, done2 = false,
fail1 = false, fail2 = false;
- var d1 = $.Deferred(),
- d2 = $.Deferred();
+ var d1 = makeTestPromise();
+ var d2 = makeTestPromise();
- dm.add(d1).done(function () { done1 = true; })
- .fail(function () { fail1 = true; });
- dm.add(d2).done(function () { done2 = true; })
- .fail(function () { fail2 = true; });
+ dm.add(d1).then(function () { done1 = true; })
+ .catch(function () { fail1 = true; });
+ dm.add(d2).then(function () { done2 = true; })
+ .catch(function () { fail2 = true; });
setTimeout(function () { d1.resolve(); }, 20);
setTimeout(function () { d2.resolve(); }, 10);
@@ -279,13 +312,13 @@ QUnit.module('core', {}, function () {
done1 = false, done2 = false,
fail1 = false, fail2 = false;
- var d1 = $.Deferred(),
- d2 = $.Deferred();
+ var d1 = makeTestPromise();
+ var d2 = makeTestPromise();
- dm.add(d1).done(function () { done1 = true; })
- .fail(function () { fail1 = true; });
- dm.add(d2).done(function () { done2 = true; })
- .fail(function () { fail2 = true; });
+ dm.add(d1).then(function () { done1 = true; })
+ .catch(function () { fail1 = true; });
+ dm.add(d2).then(function () { done2 = true; })
+ .catch(function () { fail2 = true; });
setTimeout(function () { d1.resolve(); }, 20);
setTimeout(function () { d2.resolve(); }, 10);
@@ -302,230 +335,242 @@ QUnit.module('core', {}, function () {
}, 30);
});
- QUnit.test('MutexedDropPrevious: simple', function (assert) {
- assert.expect(3);
+ QUnit.test('MutexedDropPrevious: simple', async function (assert) {
+ assert.expect(5);
var m = new concurrency.MutexedDropPrevious();
+ var d1 = makeTestPromise();
- var d1 = $.Deferred();
- var p1 = m.exec(function () { return d1; }).then(function (result) {
+ d1.then(function () {
+ assert.step("d1 resolved");
+ });
+ m.exec(function () { return d1; }).then(function (result) {
+ assert.step("p1 done");
assert.strictEqual(result, 'd1');
});
- assert.strictEqual(p1.state(), "pending");
-
+ assert.verifySteps([]);
d1.resolve('d1');
- assert.strictEqual(p1.state(), "resolved");
+ await testUtils.nextMicrotaskTick();
+
+ assert.verifySteps(["d1 resolved","p1 done"]);
});
- QUnit.test('MutexedDropPrevious: 2 arrives after 1 resolution', function (assert) {
- assert.expect(6);
+ QUnit.test('MutexedDropPrevious: d2 arrives after d1 resolution', async function (assert) {
+ assert.expect(8);
var m = new concurrency.MutexedDropPrevious();
+ var d1 = makeTestPromiseWithAssert(assert, 'd1');
- var d1 = $.Deferred();
- var p1 = m.exec(function () { return d1; }).then(function (result) {
- assert.strictEqual(result, 'd1');
+ m.exec(function () { return d1; }).then(function () {
+ assert.step("p1 resolved");
});
- assert.strictEqual(p1.state(), "pending");
-
+ assert.verifySteps([]);
d1.resolve('d1');
- assert.strictEqual(p1.state(), "resolved");
+ await testUtils.nextMicrotaskTick();
- var d2 = $.Deferred();
- var p2 = m.exec(function () { return d2; }).then(function (result) {
- assert.strictEqual(result, 'd2');
- });
+ assert.verifySteps(['ok d1','p1 resolved']);
- assert.strictEqual(p2.state(), "pending");
+ var d2 = makeTestPromiseWithAssert(assert, 'd2');
+ m.exec(function () { return d2; }).then(function () {
+ assert.step("p2 resolved");
+ });
+ assert.verifySteps([]);
d2.resolve('d2');
- assert.strictEqual(p2.state(), "resolved");
+ await testUtils.nextMicrotaskTick();
+
+ assert.verifySteps(['ok d2','p2 resolved']);
});
- QUnit.test('MutexedDropPrevious: 1 does not return a deferred', function (assert) {
- assert.expect(5);
+ QUnit.test('MutexedDropPrevious: p1 does not return a deferred', async function (assert) {
+ assert.expect(7);
var m = new concurrency.MutexedDropPrevious();
- var p1 = m.exec(function () { return 42; }).then(function (result) {
- assert.strictEqual(result, 42);
+ m.exec(function () { return 42; }).then(function () {
+ assert.step("p1 resolved");
});
- assert.strictEqual(p1.state(), "resolved");
+ assert.verifySteps([]);
+ await testUtils.nextMicrotaskTick();
- var d2 = $.Deferred();
- var p2 = m.exec(function () { return d2; }).then(function (result) {
- assert.strictEqual(result, 'd2');
- });
+ assert.verifySteps(['p1 resolved']);
- assert.strictEqual(p2.state(), "pending");
+ var d2 = makeTestPromiseWithAssert(assert, 'd2');
+ m.exec(function () { return d2; }).then(function () {
+ assert.step("p2 resolved");
+ });
+ assert.verifySteps([]);
d2.resolve('d2');
- assert.strictEqual(p2.state(), "resolved");
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['ok d2','p2 resolved']);
});
- QUnit.test('MutexedDropPrevious: 2 arrives before 1 resolution', function (assert) {
- assert.expect(13);
+ QUnit.test('MutexedDropPrevious: p2 arrives before p1 resolution', async function (assert) {
+ assert.expect(8);
var m = new concurrency.MutexedDropPrevious();
+ var d1 = makeTestPromiseWithAssert(assert, 'd1');
- var d1 = $.Deferred();
- var d2 = $.Deferred();
-
- var p1 = m.exec(function () {
- assert.step('p1');
- return d1;
+ m.exec(function () { return d1; }).catch(function () {
+ assert.step("p1 rejected");
});
- assert.strictEqual(p1.state(), "pending");
+ assert.verifySteps([]);
- var p2 = m.exec(function () {
- assert.step('p2');
- return d2;
- }).then(function (result) {
- assert.strictEqual(result, 'd2');
+ var d2 = makeTestPromiseWithAssert(assert, 'd2');
+ m.exec(function () { return d2; }).then(function () {
+ assert.step("p2 resolved");
});
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "pending");
-
- assert.step('d1 resolved');
+ assert.verifySteps([]);
d1.resolve('d1');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "pending");
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['p1 rejected', 'ok d1']);
- assert.step('d2 resolved');
d2.resolve('d2');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "resolved");
-
- assert.verifySteps(['p1', 'd1 resolved', 'p2', 'd2 resolved']);
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['ok d2', 'p2 resolved']);
});
- QUnit.test('MutexedDropPrevious: 3 arrives before 2 initialization', function (assert) {
- assert.expect(13);
-
+ QUnit.test('MutexedDropPrevious: 3 arrives before 2 initialization', async function (assert) {
+ assert.expect(10);
var m = new concurrency.MutexedDropPrevious();
- var d1 = $.Deferred();
- var d2 = $.Deferred();
- var d3 = $.Deferred();
+ var d1 = makeTestPromiseWithAssert(assert, 'd1');
+ var d3 = makeTestPromiseWithAssert(assert, 'd3');
- var p1 = m.exec(function () { return d1; });
- assert.strictEqual(p1.state(), "pending");
+ m.exec(function () { return d1; }).catch(function () {
+ assert.step('p1 rejected');
+ });
- var p2 = m.exec(function () {
+ m.exec(function () {
assert.ok(false, "should not execute this function");
- return d2;
+ }).catch(function () {
+ assert.step('p2 rejected');
});
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "pending");
- var p3 = m.exec(function () { return d3; }).then(function (result) {
+ m.exec(function () { return d3; }).then(function (result) {
assert.strictEqual(result, 'd3');
+ assert.step('p3 resolved');
});
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "pending");
+
+ assert.verifySteps([]);
+
+ await testUtils.nextMicrotaskTick();
+
+ assert.verifySteps(['p1 rejected', 'p2 rejected']);
d1.resolve('d1');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "pending");
+ await testUtils.nextMicrotaskTick();
+
+ assert.verifySteps(['ok d1']);
d3.resolve('d3');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "resolved");
- });
+ await testUtils.nextTick();
- QUnit.test('MutexedDropPrevious: 3 arrives after 2 initialization', function (assert) {
- assert.expect(19);
+ assert.verifySteps(['ok d3','p3 resolved']);
+ });
+
+ QUnit.test('MutexedDropPrevious: 3 arrives after 2 initialization', async function (assert) {
+ assert.expect(15);
var m = new concurrency.MutexedDropPrevious();
- var d1 = $.Deferred();
- var d2 = $.Deferred();
- var d3 = $.Deferred();
+ var d1 = makeTestPromiseWithAssert(assert, 'd1');
+ var d2 = makeTestPromiseWithAssert(assert, 'd2');
+ var d3 = makeTestPromiseWithAssert(assert, 'd3');
- var p1 = m.exec(function () {
- assert.step('p1');
+ m.exec(function () {
+ assert.step('execute d1');
return d1;
+ }).catch(function () {
+ assert.step('p1 rejected');
});
- assert.strictEqual(p1.state(), "pending");
- var p2 = m.exec(function () {
- assert.step('p2');
+ m.exec(function () {
+ assert.step('execute d2');
return d2;
+ }).catch(function () {
+ assert.step('p2 rejected');
});
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "pending");
+ assert.verifySteps(['execute d1']);
+
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['p1 rejected']);
- assert.step('d1 resolved');
d1.resolve('d1');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "pending");
+ await testUtils.nextMicrotaskTick();
+
+ assert.verifySteps(['ok d1', 'execute d2']);
- var p3 = m.exec(function () {
- assert.step('p3');
+ m.exec(function () {
+ assert.step('execute d3');
return d3;
- }).then(function (result) {
- assert.strictEqual(result, 'd3');
+ }).then(function () {
+ assert.step('p3 resolved');
});
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['p2 rejected']);
- assert.step('d2 resolved');
- d2.resolve('d2');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "pending");
+ d2.resolve();
+ await testUtils.nextMicrotaskTick();
+ assert.verifySteps(['ok d2', 'execute d3']);
- assert.step('d3 resolved');
- d3.resolve('d3');
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "rejected");
- assert.strictEqual(p3.state(), "resolved");
+ d3.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['ok d3', 'p3 resolved']);
- assert.verifySteps(['p1', 'd1 resolved', 'p2', 'd2 resolved', 'p3', 'd3 resolved']);
- });
+ });
- QUnit.test('MutexedDropPrevious: 2 in then of 1 with 3', function (assert) {
- assert.expect(6);
+ QUnit.test('MutexedDropPrevious: 2 in then of 1 with 3', async function (assert) {
+ assert.expect(9);
var m = new concurrency.MutexedDropPrevious();
- var d1 = $.Deferred();
- var d2 = $.Deferred();
- var d3 = $.Deferred();
+ var d1 = makeTestPromiseWithAssert(assert, 'd1');
+ var d2 = makeTestPromiseWithAssert(assert, 'd2');
+ var d3 = makeTestPromiseWithAssert(assert, 'd3');
var p3;
- var p1 = m.exec(function () { return d1; })
- .always(function () {
+ m.exec(function () { return d1; })
+ .catch(function () {
+ assert.step('p1 rejected');
p3 = m.exec(function () {
return d3;
- }).then(function (result) {
- assert.strictEqual(result, 'd3');
+ }).then(function () {
+ assert.step('p3 resolved');
});
return p3;
});
- assert.strictEqual(p1.state(), "pending");
+ await testUtils.nextTick();
+ assert.verifySteps([]);
- var p2 = m.exec(function () {
- assert.ok(false, "should not execute this function");
+ m.exec(function () {
+ assert.ok(false, 'should not execute this function');
return d2;
+ }).catch(function () {
+ assert.step('p2 rejected');
});
- assert.strictEqual(p1.state(), "rejected");
- assert.strictEqual(p2.state(), "rejected");
+
+ await testUtils.nextTick();
+ assert.verifySteps(['p1 rejected', 'p2 rejected']);
d1.resolve('d1');
- assert.strictEqual(p3.state(), "pending");
+ await testUtils.nextTick();
+
+ assert.verifySteps(['ok d1']);
d3.resolve('d3');
- assert.strictEqual(p3.state(), "resolved");
+ await testUtils.nextTick();
+
+ assert.verifySteps(['ok d3', 'p3 resolved']);
});
});
-}); \ No newline at end of file
+});
diff --git a/addons/web/static/tests/core/dom_tests.js b/addons/web/static/tests/core/dom_tests.js
index ab10bbb78f8..c57ced52099 100644
--- a/addons/web/static/tests/core/dom_tests.js
+++ b/addons/web/static/tests/core/dom_tests.js
@@ -30,7 +30,11 @@ function prepareAutoresizeTextArea(options) {
QUnit.module('core', {}, function () {
QUnit.module('dom', {}, function () {
- QUnit.module('autoresize');
+ QUnit.module('autoresize', {
+ afterEach: function () {
+ $('#qunit-fixture').find('textarea').remove();
+ },
+ });
QUnit.test('autoresize (border-box): no padding + no border', function (assert) {
assert.expect(3);
diff --git a/addons/web/static/tests/core/mixins_tests.js b/addons/web/static/tests/core/mixins_tests.js
index 27c87870876..8c71a2592ce 100644
--- a/addons/web/static/tests/core/mixins_tests.js
+++ b/addons/web/static/tests/core/mixins_tests.js
@@ -10,6 +10,7 @@ QUnit.module('core', {}, function () {
QUnit.test('perform a do_action properly', function (assert) {
assert.expect(3);
+ var done = assert.async();
var widget = new Widget();
@@ -22,9 +23,10 @@ QUnit.module('core', {}, function () {
});
widget.do_action('test.some_action_id', {clear_breadcrumbs: true}).then(function () {
- assert.step('deferred should have been resolved');
+ assert.ok(true, 'deferred should have been resolved');
+ widget.destroy();
+ done();
});
- widget.destroy();
});
diff --git a/addons/web/static/tests/core/widget_tests.js b/addons/web/static/tests/core/widget_tests.js
index 0eb4192c4a1..440cc97b524 100644
--- a/addons/web/static/tests/core/widget_tests.js
+++ b/addons/web/static/tests/core/widget_tests.js
@@ -2,7 +2,6 @@ odoo.define('web.widget_tests', function (require) {
"use strict";
var AjaxService = require('web.AjaxService');
-var concurrency = require('web.concurrency');
var core = require('web.core');
var QWeb = require('web.QWeb');
var Widget = require('web.Widget');
@@ -86,8 +85,6 @@ QUnit.module('core', {}, function () {
w.destroy();
});
-
-
QUnit.test('renderElement, no template, default', function (assert) {
assert.expect(7);
@@ -206,7 +203,7 @@ QUnit.module('core', {}, function () {
widget.destroy();
});
- QUnit.test('repeated', function (assert) {
+ QUnit.test('repeated', async function (assert) {
assert.expect(4);
var $fix = $( "#qunit-fixture");
@@ -222,17 +219,16 @@ QUnit.module('core', {}, function () {
}))();
widget.value = 42;
- return widget.appendTo($fix)
- .done(function () {
+ await widget.appendTo($fix)
+ .then(function () {
assert.strictEqual($fix.find('p').text(), '42', "DOM fixture should contain initial value");
assert.strictEqual(widget.$el.text(), '42', "should set initial value");
widget.value = 36;
widget.renderElement();
assert.strictEqual($fix.find('p').text(), '36', "DOM fixture should use new value");
assert.strictEqual(widget.$el.text(), '36', "should set new value");
- }).always(function () {
- widget.destroy();
});
+ widget.destroy();
});
@@ -274,7 +270,7 @@ QUnit.module('core', {}, function () {
});
- QUnit.test('delegate', function (assert) {
+ QUnit.test('delegate', async function (assert) {
assert.expect(5);
var a = [];
@@ -292,9 +288,9 @@ QUnit.module('core', {}, function () {
}))();
widget.renderElement();
- widget.$el.click();
- widget.$('li:eq(3)').click();
- widget.$('input:last').val('foo').change();
+ await testUtils.dom.click(widget.$el, {allowInvisible: true});
+ await testUtils.dom.click(widget.$('li:eq(3)'), {allowInvisible: true});
+ await testUtils.fields.editAndTrigger(widget.$('input:last'), 'foo', 'change');
for(var i=0; i<3; ++i) {
assert.ok(a[i], "should pass test " + i);
@@ -302,7 +298,7 @@ QUnit.module('core', {}, function () {
widget.destroy();
});
- QUnit.test('undelegate', function (assert) {
+ QUnit.test('undelegate', async function (assert) {
assert.expect(4);
var clicked = false;
@@ -316,13 +312,13 @@ QUnit.module('core', {}, function () {
widget.renderElement();
widget.$el.on('click', 'li', function () { newclicked = true; });
- widget.$('li').click();
+ await testUtils.dom.clickFirst(widget.$('li'), {allowInvisible: true});
assert.ok(clicked, "should trigger bound events");
assert.ok(newclicked, "should trigger bound events");
clicked = newclicked = false;
widget._undelegateEvents();
- widget.$('li').click();
+ await testUtils.dom.clickFirst(widget.$('li'), {allowInvisible: true});
assert.ok(!clicked, "undelegate should unbind events delegated");
assert.ok(newclicked, "undelegate should only unbind events it created");
widget.destroy();
@@ -330,50 +326,54 @@ QUnit.module('core', {}, function () {
QUnit.module('Widget, and async stuff');
- QUnit.test("alive(alive)", function (assert) {
+ QUnit.test("alive(alive)", async function (assert) {
assert.expect(1);
var widget = new (Widget.extend({}));
- return concurrency.asyncWhen(widget.start())
- .then(function () { return widget.alive(concurrency.asyncWhen()); })
- .then(function () { assert.ok(true); })
- .always(function () { widget.destroy(); });
+ await widget.start()
+ .then(function () {return widget.alive(Promise.resolve()) ;})
+ .then(function () { assert.ok(true); });
+
+ widget.destroy();
});
QUnit.test("alive(dead)", function (assert) {
assert.expect(1);
var widget = new (Widget.extend({}));
- return $.Deferred(function (d) {
- concurrency.asyncWhen(widget.start())
+ return new Promise(function (resolve, reject) {
+ widget.start()
.then(function () {
// destroy widget
widget.destroy();
- var promise = concurrency.asyncWhen();
+ var promise = Promise.resolve();
// leave time for alive() to do its stuff
promise.then(function () {
- return concurrency.asyncWhen();
+ return Promise.resolve();
}).then(function () {
assert.ok(true);
- d.resolve();
+ resolve();
});
// ensure that widget.alive() refuses to resolve or reject
return widget.alive(promise);
- }).always(function () {
- d.reject();
+ }).then(function () {
+ reject();
+ assert.ok(false, "alive() should not terminate by default");
+ }).catch(function() {
+ reject();
assert.ok(false, "alive() should not terminate by default");
});
});
});
- QUnit.test("alive(alive, true)", function (assert) {
+ QUnit.test("alive(alive, true)", async function (assert) {
assert.expect(1);
var widget = new (Widget.extend({}));
- return concurrency.asyncWhen(widget.start())
- .then(function () { return widget.alive(concurrency.asyncWhen(), true) })
- .then(function () { assert.ok(true); })
- .always(function () { widget.destroy(); });
+ await widget.start()
+ .then(function () { return widget.alive(Promise.resolve(), true); })
+ .then(function () { assert.ok(true); });
+ widget.destroy();
});
QUnit.test("alive(dead, true)", function (assert) {
@@ -382,11 +382,11 @@ QUnit.module('core', {}, function () {
var widget = new (Widget.extend({}));
- concurrency.asyncWhen(widget.start())
+ widget.start()
.then(function () {
// destroy widget
widget.destroy();
- return widget.alive(concurrency.asyncWhen(), true);
+ return widget.alive(Promise.resolve(), true);
}).then(function () {
assert.ok(false, "alive(p, true) should fail its promise");
done();
@@ -396,7 +396,7 @@ QUnit.module('core', {}, function () {
});
});
- QUnit.test("calling _rpc on destroyed widgets", function (assert) {
+ QUnit.test("calling _rpc on destroyed widgets", async function (assert) {
assert.expect(3);
var def;
@@ -404,7 +404,7 @@ QUnit.module('core', {}, function () {
testUtils.mock.addMockEnvironment(parent, {
session: {
rpc: function () {
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
def.abort = def.reject;
return def;
},
@@ -419,23 +419,30 @@ QUnit.module('core', {}, function () {
assert.ok(true, "The ajax call should be resolve");
});
def.resolve();
+ await testUtils.nextMicrotaskTick();
def = null;
- widget._rpc({route: '/a/route'}).always(function () {
+ widget._rpc({route: '/a/route'}).then(function () {
throw Error("Calling _rpc on a destroyed widget should return a " +
- "deferred that is never resolved nor rejected");
+ "promise that remains pending forever");
+ }).catch(function () {
+ throw Error("Calling _rpc on a destroyed widget should return a " +
+ "promise that remains pending forever");
});
widget.destroy();
def.resolve();
+ await testUtils.nextMicrotaskTick();
def = null;
- widget._rpc({route: '/a/route'}).always(function () {
+ widget._rpc({route: '/a/route'}).then(function () {
+ throw Error("Calling _rpc on a destroyed widget should return a " +
+ "promise that remains pending forever");
+ }).catch(function () {
throw Error("Calling _rpc on a destroyed widget should return a " +
- "deferred that is never resolved nor rejected");
+ "promise that remains pending forever");
});
- assert.ok(!def,
- "The trigger_up is not performed and the call returns a deferred "+
- "never resolved nor rejected");
+ assert.ok(!def, "trigger_up is not performed and the call returns a " +
+ "promise that remains pending forever");
assert.ok(true,
"there should be no crash when calling _rpc on a destroyed widget");
@@ -444,12 +451,12 @@ QUnit.module('core', {}, function () {
QUnit.test('start is not called when widget is destroyed', function (assert) {
assert.expect(0);
- var slowWillStartDef = $.Deferred();
+ var slowWillStartPromise = testUtils.makeTestPromise();
var $fix = $( "#qunit-fixture");
var widget = new (Widget.extend({
willStart: function () {
- return slowWillStartDef;
+ return slowWillStartPromise;
},
start: function () {
throw new Error('Should not call start method');
@@ -458,7 +465,7 @@ QUnit.module('core', {}, function () {
widget.appendTo($fix);
widget.destroy();
- slowWillStartDef.resolve();
+ slowWillStartPromise.resolve();
});
});
diff --git a/addons/web/static/tests/fields/basic_fields_mobile_tests.js b/addons/web/static/tests/fields/basic_fields_mobile_tests.js
index fd302ebeb36..a58957ebfca 100644
--- a/addons/web/static/tests/fields/basic_fields_mobile_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_mobile_tests.js
@@ -53,10 +53,10 @@ QUnit.module('basic_fields', {
QUnit.module('PhoneWidget');
- QUnit.test('phone field in form view on extra small screens', function (assert) {
+ QUnit.test('phone field in form view on extra small screens', async function (assert) {
assert.expect(7);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -79,17 +79,17 @@ QUnit.module('basic_fields', {
"should have proper tel prefix");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[type="text"].o_field_widget',
"should have an int for the phone field");
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
"input should contain field value in edit mode");
// change value in edit mode
- testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new');
+ await testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
$phoneLink = form.$('a.o_form_uri.o_field_widget');
assert.strictEqual($phoneLink.text(), 'new',
"new value should be displayed properly");
@@ -99,10 +99,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('phone field in editable list view on extra small screens', function (assert) {
+ QUnit.test('phone field in editable list view on extra small screens', async function (assert) {
assert.expect(10);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -122,14 +122,14 @@ QUnit.module('basic_fields', {
// Edit a line and check the result
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode');
assert.strictEqual($cell.find('input').val(), 'yop',
'should have the corect value in internal input');
- testUtils.fields.editInput($cell.find('input'), 'new');
+ await testUtils.fields.editInput($cell.find('input'), 'new');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore');
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new',
@@ -143,10 +143,10 @@ QUnit.module('basic_fields', {
list.destroy();
});
- QUnit.test('phone field does not allow html injections', function (assert) {
+ QUnit.test('phone field does not allow html injections', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -164,10 +164,10 @@ QUnit.module('basic_fields', {
});
var val = '<script>throw Error();</script><script>throw Error();</script>';
- testUtils.fields.editInput(form.$('input.o_field_widget[name="foo"]'), val);
+ await testUtils.fields.editInput(form.$('input.o_field_widget[name="foo"]'), val);
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), val,
"value should have been correctly escaped");
diff --git a/addons/web/static/tests/fields/basic_fields_tests.js b/addons/web/static/tests/fields/basic_fields_tests.js
index 33f18558917..223e1e5764c 100644
--- a/addons/web/static/tests/fields/basic_fields_tests.js
+++ b/addons/web/static/tests/fields/basic_fields_tests.js
@@ -13,7 +13,7 @@ var testUtils = require('web.test_utils');
var field_registry = require('web.field_registry');
var createView = testUtils.createView;
-var createAsyncView = testUtils.createAsyncView;
+var createView = testUtils.createView;
var DebouncedField = basicFields.DebouncedField;
var JournalDashboardGraph = basicFields.JournalDashboardGraph;
var _t = core._t;
@@ -128,11 +128,10 @@ QUnit.module('basic_fields', {
QUnit.module('DebouncedField');
- QUnit.test('debounced fields do not trigger call _setValue once destroyed', function (assert) {
- var done = assert.async();
+ QUnit.test('debounced fields do not trigger call _setValue once destroyed', async function (assert) {
assert.expect(4);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
var _doAction = DebouncedField.prototype._doAction;
DebouncedField.prototype._doAction = function () {
_doAction.apply(this, arguments);
@@ -144,7 +143,7 @@ QUnit.module('basic_fields', {
_setValue.apply(this, arguments);
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -167,31 +166,28 @@ QUnit.module('basic_fields', {
assert.verifySteps([], "_setValue shouldn't have been called yet");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps(['_setValue'], "_setValue should have been called once");
// destroy the form view
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
form.destroy();
+ await testUtils.nextMicrotaskTick();
// wait for the debounced callback to be called
- def.then(function () {
- assert.verifySteps(['_setValue'],
- "_setValue should not have been called after widget destruction");
-
- DebouncedField.prototype._doAction = _doAction;
- DebouncedField.prototype._setValue = _setValue;
- done();
- });
+ assert.verifySteps([],
+ "_setValue should not have been called after widget destruction");
+ DebouncedField.prototype._doAction = _doAction;
+ DebouncedField.prototype._setValue = _setValue;
});
QUnit.module('FieldBoolean');
- QUnit.test('boolean field in form view', function (assert) {
- assert.expect(12);
+ QUnit.test('boolean field in form view', async function (assert) {
+ assert.expect(13);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -203,70 +199,73 @@ QUnit.module('basic_fields', {
"checkbox should be checked");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should still be checked");
// uncheck the checkbox
- testUtils.dom.click(form.$('.o_field_boolean input:checked'));
+ await testUtils.dom.click(form.$('.o_field_boolean input:checked'));
assert.containsNone(form, '.o_field_boolean input:checked',
"checkbox should no longer be checked");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsNone(form, '.o_field_boolean input:checked',
"checkbox should still no longer be checked");
// switch to edit mode and test the opposite change
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, '.o_field_boolean input:checked',
"checkbox should still be unchecked");
// check the checkbox
- testUtils.dom.click(form.$('.o_field_boolean input'));
+ await testUtils.dom.click(form.$('.o_field_boolean input'));
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should now be checked");
// uncheck it back
- testUtils.dom.click(form.$('.o_field_boolean input'));
+ await testUtils.dom.click(form.$('.o_field_boolean input'));
assert.containsNone(form, '.o_field_boolean input:checked',
"checkbox should now be unchecked");
// check the checkbox by clicking on label
- testUtils.dom.click(form.$('.o_form_view label:first'));
+ await testUtils.dom.click(form.$('.o_form_view label:first'));
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should now be checked");
// uncheck it back
- testUtils.dom.click(form.$('.o_form_view label:first'));
+ await testUtils.dom.click(form.$('.o_form_view label:first'));
assert.containsNone(form, '.o_field_boolean input:checked',
"checkbox should now be unchecked");
// check the checkbox by hitting the "enter" key after focusing it
- form.$('.o_field_boolean input')
- .trigger("focusin")
- .trigger({type: "keydown", which: $.ui.keyCode.ENTER})
- .trigger({type: "keyup", which: $.ui.keyCode.ENTER});
+ await testUtils.dom.triggerEvents(form.$('.o_field_boolean input'), [
+ "focusin",
+ {type: "keydown", which: $.ui.keyCode.ENTER},
+ {type: "keyup", which: $.ui.keyCode.ENTER}]);
assert.containsOnce(form, '.o_field_boolean input:checked',
- "checkbox should now be checked");
+ "checkbox should now be checked");
// blindly press enter again, it should uncheck the checkbox
$(document.activeElement).trigger({type: "keydown", which: $.ui.keyCode.ENTER});
assert.containsNone(form, '.o_field_boolean input:checked',
- "checkbox should not be checked");
+ "checkbox should not be checked");
+ await testUtils.nextTick();
// blindly press enter again, it should check the checkbox back
$(document.activeElement).trigger({type: "keydown", which: $.ui.keyCode.ENTER});
+ assert.containsOnce(form, '.o_field_boolean input:checked',
+ "checkbox should still be checked");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_field_boolean input:checked',
"checkbox should still be checked");
form.destroy();
});
- QUnit.test('boolean field in editable list view', function (assert) {
+ QUnit.test('boolean field in editable list view', async function (assert) {
assert.expect(11);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -282,13 +281,13 @@ QUnit.module('basic_fields', {
var $cell = list.$('tr.o_data_row:has(.custom-checkbox input:checked) td:not(.o_list_record_selector)').first();
assert.ok($cell.find('.custom-checkbox input:checked').prop('disabled'),
"input should be disabled in readonly mode");
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.ok(!$cell.find('.custom-checkbox input:checked').prop('disabled'),
"input should not have the disabled property in edit mode");
- testUtils.dom.click($cell.find('.custom-checkbox input:checked'));
+ await testUtils.dom.click($cell.find('.custom-checkbox input:checked'));
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
$cell = list.$('tr.o_data_row:has(.custom-checkbox input:not(:checked)) td:not(.o_list_record_selector)').first();
assert.ok($cell.find('.custom-checkbox input:not(:checked)').prop('disabled'),
"input should be disabled again");
@@ -298,12 +297,12 @@ QUnit.module('basic_fields', {
"should now have only 3 checked input");
// Re-Edit the line and fake-check the checkbox
- testUtils.dom.click($cell);
- testUtils.dom.click($cell.find('.custom-checkbox input'));
- testUtils.dom.click($cell.find('.custom-checkbox input'));
+ await testUtils.dom.click($cell);
+ await testUtils.dom.click($cell.find('.custom-checkbox input'));
+ await testUtils.dom.click($cell.find('.custom-checkbox input'));
// Save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5,
"should still have 5 checkboxes");
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input:checked').length, 3,
@@ -312,7 +311,7 @@ QUnit.module('basic_fields', {
// Re-Edit the line to check the checkbox back but this time click on
// the checkbox directly in readonly mode !
$cell = list.$('tr.o_data_row:has(.custom-checkbox input:not(:checked)) td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell.find('.custom-checkbox .custom-control-label'));
+ await testUtils.dom.click($cell.find('.custom-checkbox .custom-control-label'));
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector) .custom-checkbox input').length, 5,
"should still have 5 checkboxes");
@@ -324,7 +323,7 @@ QUnit.module('basic_fields', {
QUnit.module('FieldBooleanButton');
- QUnit.test('use custom terminology in form view', function (assert) {
+ QUnit.test('use custom terminology in form view', async function (assert) {
assert.expect(2);
var terminology = {
string_true: "Production Environment",
@@ -332,7 +331,7 @@ QUnit.module('basic_fields', {
string_false: "Test Environment",
hover_false: "Switch to production environment"
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -356,10 +355,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldBooleanToggle');
- QUnit.test('use boolean toggle widget in form view', function (assert) {
+ QUnit.test('use boolean toggle widget in form view', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -373,10 +372,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldToggleButton');
- QUnit.test('use toggle_button in list view', function (assert) {
+ QUnit.test('use toggle_button in list view', async function (assert) {
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -397,20 +396,20 @@ QUnit.module('basic_fields', {
"To Report in Payslip", "inactive buttons should have proper tooltip");
// clicking on first button to check the state is properly changed
- testUtils.dom.click(list.$('.o_list_view button').first());
+ await testUtils.dom.click(list.$('.o_list_view button').first());
assert.containsN(list, 'button i.fa.fa-circle.o_toggle_button_success', 3,
"should have 3 green buttons");
- testUtils.dom.click(list.$('.o_list_view button').first());
+ await testUtils.dom.click(list.$('.o_list_view button').first());
assert.containsN(list, 'button i.fa.fa-circle.o_toggle_button_success', 4,
"should have 4 green buttons");
list.destroy();
});
- QUnit.test('toggle_button in form view (edit mode)', function (assert) {
+ QUnit.test('toggle_button in form view (edit mode)', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -434,14 +433,14 @@ QUnit.module('basic_fields', {
1, "should be green");
// click on the button to toggle the value
- testUtils.dom.click(form.$('.o_field_widget[name=bar]'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=bar]'));
assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length,
1, "should be gray");
assert.verifySteps([]);
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length,
1, "should still be gray");
@@ -450,10 +449,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('toggle_button in form view (readonly mode)', function (assert) {
+ QUnit.test('toggle_button in form view (readonly mode)', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -474,7 +473,7 @@ QUnit.module('basic_fields', {
1, "should be green");
// click on the button to toggle the value
- testUtils.dom.click(form.$('.o_field_widget[name=bar]'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=bar]'));
assert.strictEqual(form.$('.o_field_widget[name=bar] i.text-muted:not(.o_toggle_button_success)').length,
1, "should be gray");
@@ -485,10 +484,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldFloat');
- QUnit.test('float field when unset', function (assert) {
+ QUnit.test('float field when unset', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -508,10 +507,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('float fields use correct digit precision', function (assert) {
+ QUnit.test('float fields use correct digit precision', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -529,10 +528,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('float field in form view', function (assert) {
+ QUnit.test('float field in form view', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -549,26 +548,26 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '0.000',
'The value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=qux]').val(), '0.000',
'The value should be rendered with correct precision.');
- testUtils.fields.editInput(form.$('input[name=qux]'), '108.2458938598598');
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '108.2458938598598');
assert.strictEqual(form.$('input[name=qux]').val(), '108.2458938598598',
'The value should not be formated yet.');
- testUtils.fields.editInput(form.$('input[name=qux]'), '18.8958938598598');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '18.8958938598598');
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').first().text(), '18.896',
'The new value should be rounded properly.');
form.destroy();
});
- QUnit.test('float field in editable list view', function (assert) {
+ QUnit.test('float field in editable list view', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -583,29 +582,29 @@ QUnit.module('basic_fields', {
// switch to edit mode
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.containsOnce(list, 'input[name="qux"]',
'The view should have 1 input for editable float.');
- testUtils.fields.editInput(list.$('input[name="qux"]'), '108.2458938598598');
+ await testUtils.fields.editInput(list.$('input[name="qux"]'), '108.2458938598598');
assert.strictEqual(list.$('input[name="qux"]').val(), '108.2458938598598',
'The value should not be formated yet.');
- testUtils.fields.editInput(list.$('input[name="qux"]'), '18.8958938598598');
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.fields.editInput(list.$('input[name="qux"]'), '18.8958938598598');
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('.o_field_widget').first().text(), '18.896',
'The new value should be rounded properly.');
list.destroy();
});
- QUnit.test('do not trigger a field_changed if they have not changed', function (assert) {
+ QUnit.test('do not trigger a field_changed if they have not changed', async function (assert) {
assert.expect(2);
this.data.partner.records[1].qux = false;
this.data.partner.records[1].int_field = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -622,22 +621,22 @@ QUnit.module('basic_fields', {
}
});
- testUtils.form.clickEdit(form);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps(['read']); // should not have save as nothing changed
form.destroy();
});
- QUnit.test('float widget on monetary field', function (assert) {
+ QUnit.test('float widget on monetary field', async function (assert) {
assert.expect(1);
this.data.partner.fields.monetary = {string: "Monetary", type: 'monetary'};
this.data.partner.records[0].monetary = 9.99;
this.data.partner.records[0].currency_id = 1;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -659,7 +658,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('float field with monetary widget and decimal precision', function (assert) {
+ QUnit.test('float field with monetary widget and decimal precision', async function (assert) {
assert.expect(5);
this.data.partner.records = [{
@@ -667,7 +666,7 @@ QUnit.module('basic_fields', {
qux: -8.89859,
currency_id: 1,
}];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -687,17 +686,17 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0-8.9',
'The value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '-8.9',
'The input should be rendered without the currency symbol.');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').parent().children().first().text(), '$',
'The input should be preceded by a span containing the currency symbol.');
- testUtils.fields.editInput(form.$('.o_field_monetary input'), '109.2458938598598');
+ await testUtils.fields.editInput(form.$('.o_field_monetary input'), '109.2458938598598');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '109.2458938598598',
'The value should not be formated yet.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// Non-breaking space between the currency and the amount
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0109.2',
'The new value should be rounded properly.');
@@ -705,10 +704,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('float field with type number option', function (assert) {
+ QUnit.test('float field with type number option', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -722,27 +721,27 @@ QUnit.module('basic_fields', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'),
'Float field with option type must have a type attribute.');
assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'number',
'Float field with option type must have a type attribute equals to "number".');
- testUtils.fields.editInput(form.$('input[name=qux]'), '123456.7890');
- testUtils.form.clickSave(form);
- testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '123456.7890');
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget').val(), '123456.789',
'Float value must be not formatted if input type is number.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), '123,456.8',
'Float value must be formatted in readonly view even if the input type is number.');
form.destroy();
});
- QUnit.test('float field without type number option', function (assert) {
+ QUnit.test('float field without type number option', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -756,13 +755,13 @@ QUnit.module('basic_fields', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'text',
'Float field with option type must have a text type (default type).');
- testUtils.fields.editInput(form.$('input[name=qux]'), '123456.7890');
- testUtils.form.clickSave(form);
- testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '123456.7890');
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget').val(), '123,456.8',
'Float value must be formatted if input type isn\'t number.');
@@ -772,10 +771,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldEmail');
- QUnit.test('email field in form view', function (assert) {
+ QUnit.test('email field in form view', async function (assert) {
assert.expect(7);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -798,17 +797,17 @@ QUnit.module('basic_fields', {
"should have proper mailto prefix");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[type="text"].o_field_widget',
"should have an input for the email field");
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
"input should contain field value in edit mode");
// change value in edit mode
- testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new');
+ await testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
$mailtoLink = form.$('a.o_form_uri.o_field_widget.o_text_overflow');
assert.strictEqual($mailtoLink.text(), 'new',
"new value should be displayed properly");
@@ -818,10 +817,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('email field in editable list view', function (assert) {
+ QUnit.test('email field in editable list view', async function (assert) {
assert.expect(10);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -841,14 +840,14 @@ QUnit.module('basic_fields', {
// Edit a line and check the result
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode');
assert.strictEqual($cell.find('input').val(), 'yop',
'should have the corect value in internal input');
- testUtils.fields.editInput($cell.find('input'), 'new');
+ await testUtils.fields.editInput($cell.find('input'), 'new');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore');
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new',
@@ -865,11 +864,11 @@ QUnit.module('basic_fields', {
QUnit.module('FieldChar');
- QUnit.test('char widget isValid method works', function (assert) {
+ QUnit.test('char widget isValid method works', async function (assert) {
assert.expect(1);
this.data.partner.fields.foo.required = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -884,10 +883,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('char field in form view', function (assert) {
+ QUnit.test('char field in form view', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -905,26 +904,26 @@ QUnit.module('basic_fields', {
"the value should be displayed properly");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[type="text"].o_field_widget',
"should have an input for the char field");
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
"input should contain field value in edit mode");
// change value in edit mode
- testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'limbo');
+ await testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'limbo');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), 'limbo',
'the new value should be displayed');
form.destroy();
});
- QUnit.test('setting a char field to empty string is saved as a false value', function (assert) {
+ QUnit.test('setting a char field to empty string is saved as a false value', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -946,18 +945,18 @@ QUnit.module('basic_fields', {
}
});
- testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), '');
+ await testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), '');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('char field with size attribute', function (assert) {
+ QUnit.test('char field with size attribute', async function (assert) {
assert.expect(1);
this.data.partner.fields.foo.size = 5; // max length
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -978,10 +977,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('char field in editable list view', function (assert) {
+ QUnit.test('char field in editable list view', async function (assert) {
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -995,14 +994,14 @@ QUnit.module('basic_fields', {
// Edit a line and check the result
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode');
assert.strictEqual($cell.find('input').val(), 'yop',
'should have the corect value in internal input');
- testUtils.fields.editInput($cell.find('input'), 'brolo');
+ await testUtils.fields.editInput($cell.find('input'), 'brolo');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore');
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'brolo',
@@ -1010,7 +1009,7 @@ QUnit.module('basic_fields', {
list.destroy();
});
- QUnit.test('char field translatable', function (assert) {
+ QUnit.test('char field translatable', async function (assert) {
assert.expect(3);
this.data.partner.fields.foo.translate = true;
@@ -1018,7 +1017,7 @@ QUnit.module('basic_fields', {
var multiLang = _t.database.multi_lang;
_t.database.multi_lang = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1033,18 +1032,18 @@ QUnit.module('basic_fields', {
mockRPC: function (route, args) {
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
assert.deepEqual(args.args, ["partner",1,"foo",{}], 'should call "call_button" route');
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $button = form.$('input[type="text"].o_field_char + .o_field_translate');
assert.strictEqual($button.length, 1, "should have a translate button");
- testUtils.dom.click($button);
+ await testUtils.dom.click($button);
form.destroy();
- form = createView({
+ form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1063,10 +1062,10 @@ QUnit.module('basic_fields', {
_t.database.multi_lang = multiLang;
});
- QUnit.test('char field does not allow html injections', function (assert) {
+ QUnit.test('char field does not allow html injections', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1083,20 +1082,20 @@ QUnit.module('basic_fields', {
},
});
- testUtils.fields.editInput(form.$('input[name=foo]'), '<script>throw Error();</script>');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), '<script>throw Error();</script>');
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), '<script>throw Error();</script>',
'the value should have been properly escaped');
form.destroy();
});
- QUnit.test('char field trim (or not) characters', function (assert) {
+ QUnit.test('char field trim (or not) characters', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo2 = {string: "Foo2", type: "char", trim: false};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1114,13 +1113,13 @@ QUnit.module('basic_fields', {
},
});
- testUtils.fields.editInput(form.$('input[name="foo"]'), ' abc ');
- testUtils.fields.editInput(form.$('input[name="foo2"]'), ' def ');
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), ' abc ');
+ await testUtils.fields.editInput(form.$('input[name="foo2"]'), ' def ');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name="foo"]').val(), 'abc', 'Foo value should have been trimmed');
assert.strictEqual(form.$('input[name="foo2"]').val(), ' def ', 'Foo2 value should not have been trimmed');
@@ -1128,7 +1127,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('input field: change value before pending onchange returns', function (assert) {
+ QUnit.test('input field: change value before pending onchange returns', async function (assert) {
assert.expect(3);
this.data.partner.onchanges = {
@@ -1136,7 +1135,7 @@ QUnit.module('basic_fields', {
};
var def;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1154,7 +1153,7 @@ QUnit.module('basic_fields', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === "onchange") {
- return $.when(def).then(function () {
+ return Promise.resolve(def).then(function () {
return result;
});
} else {
@@ -1166,29 +1165,31 @@ QUnit.module('basic_fields', {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('input[name="foo"]').val(), 'My little Foo Value',
'should contain the default value');
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
// set foo before onchange
- testUtils.fields.editInput(form.$('input[name="foo"]'), "tralala");
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "tralala");
assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala',
'input should contain tralala');
// complete the onchange
def.resolve();
+ await testUtils.nextTick();
+
assert.strictEqual(form.$('input[name="foo"]').val(), 'tralala',
'input should contain the same value as before onchange');
form.destroy();
});
- QUnit.test('input field: change value before pending onchange renaming', function (assert) {
+ QUnit.test('input field: change value before pending onchange renaming', async function (assert) {
assert.expect(3);
this.data.partner.onchanges = {
@@ -1197,8 +1198,8 @@ QUnit.module('basic_fields', {
},
};
- var def = $.Deferred();
- var form = createView({
+ var def = testUtils.makeTestPromise();
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1212,7 +1213,7 @@ QUnit.module('basic_fields', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === "onchange") {
- return $.when(def).then(function () {
+ return def.then(function () {
return result;
});
} else {
@@ -1227,8 +1228,8 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('input[name="foo"]').val(), 'yop',
'should contain the correct value');
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
// set foo before onchange
testUtils.fields.editInput(form.$('input[name="foo"]'), "tralala");
@@ -1243,10 +1244,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('input field: change password value', function (assert) {
+ QUnit.test('input field: change password value', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1261,7 +1262,7 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_char').text(), "***",
"password field value should be hidden with '*' in read mode");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasAttrValue(form.$('input.o_field_char'), 'type', 'password',
"password field input should be with type 'password' in edit mode");
@@ -1271,12 +1272,12 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('input field: empty password', function (assert) {
+ QUnit.test('input field: empty password', async function (assert) {
assert.expect(3);
this.data.partner.records[0].foo = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1289,7 +1290,7 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_char').text(), "",
"password field value should be empty in read mode");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasAttrValue(form.$('input.o_field_char'), 'type', 'password',
"password field input should be with type 'password' in edit mode");
@@ -1301,10 +1302,10 @@ QUnit.module('basic_fields', {
QUnit.module('UrlWidget');
- QUnit.test('url widget in form view', function (assert) {
+ QUnit.test('url widget in form view', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1328,7 +1329,7 @@ QUnit.module('basic_fields', {
"the value should be displayed properly");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[type="text"].o_field_widget',
"should have an input for the char field");
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
@@ -1338,7 +1339,7 @@ QUnit.module('basic_fields', {
testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'limbo');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, 'a.o_form_uri.o_field_widget.o_text_overflow',
"should still have a anchor with correct classes");
assert.hasAttrValue(form.$('a.o_form_uri.o_field_widget.o_text_overflow'), 'href', 'limbo',
@@ -1349,10 +1350,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('url widget takes text from proper attribute', function (assert) {
+ QUnit.test('url widget takes text from proper attribute', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1367,10 +1368,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('char field in editable list view', function (assert) {
+ QUnit.test('char field in editable list view', async function (assert) {
assert.expect(10);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -1388,14 +1389,14 @@ QUnit.module('basic_fields', {
// Edit a line and check the result
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode');
assert.strictEqual($cell.find('input').val(), 'yop',
'should have the corect value in internal input');
- testUtils.fields.editInput($cell.find('input'), 'brolo');
+ await testUtils.fields.editInput($cell.find('input'), 'brolo');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore');
assert.containsN(list, 'a.o_form_uri.o_field_widget.o_text_overflow', 5,
@@ -1426,10 +1427,10 @@ QUnit.module('basic_fields', {
}
});
- QUnit.test('Char & Text Fields: Copy to clipboard button', function (assert) {
+ QUnit.test('Char & Text Fields: Copy to clipboard button', async function (assert) {
assert.expect(2);
var done = assert.async();
- testUtils.createAsyncView({
+ testUtils.createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1451,11 +1452,11 @@ QUnit.module('basic_fields', {
QUnit.module('FieldText');
- QUnit.test('text fields are correctly rendered', function (assert) {
+ QUnit.test('text fields are correctly rendered', async function (assert) {
assert.expect(7);
this.data.partner.fields.foo.type = 'text';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1469,7 +1470,7 @@ QUnit.module('basic_fields', {
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');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $textarea = form.$('textarea.o_field_text');
assert.ok($textarea.length, "should have a text area");
@@ -1481,19 +1482,19 @@ QUnit.module('basic_fields', {
testUtils.fields.editInput($textarea, 'hello world');
assert.strictEqual($textarea.val(), 'hello world', 'should be "hello world" after second edition');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_text').text(), 'hello world',
'should be "hello world" after save');
form.destroy();
});
- QUnit.test('text fields in edit mode have correct height', function (assert) {
+ QUnit.test('text fields in edit mode have correct height', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.type = 'text';
this.data.partner.records[0].foo = "f\nu\nc\nk\nm\ni\nl\ng\nr\no\nm";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1505,23 +1506,23 @@ QUnit.module('basic_fields', {
var $field = form.$('.o_field_text');
- assert.strictEqual($field.outerHeight(), $field[0].scrollHeight,
+ assert.strictEqual($field[0].offsetHeight, $field[0].scrollHeight,
"text field should not have a scroll bar");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $textarea = form.$('textarea:first');
// the difference is to take small calculation errors into account
- assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight,
+ assert.strictEqual($textarea[0].clientHeight, $textarea[0].scrollHeight,
"textarea should not have a scroll bar");
form.destroy();
});
- QUnit.test('text fields in edit mode, no vertical resize', function (assert) {
+ QUnit.test('text fields in edit mode, no vertical resize', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1531,7 +1532,7 @@ QUnit.module('basic_fields', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $textarea = form.$('textarea:first');
@@ -1541,12 +1542,12 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('text fields in editable list have correct height', function (assert) {
+ QUnit.test('text fields in editable list have correct height', async function (assert) {
assert.expect(2);
this.data.partner.records[0].txt = "a\nb\nc\nd\ne\nf";
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -1560,20 +1561,20 @@ QUnit.module('basic_fields', {
// the focus on the textarea by clicking on another column.
// The main goal is to test the resize is actually triggered in this
// particular case.
- testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
var $textarea = list.$('textarea:first');
// make sure the correct data is there
assert.strictEqual($textarea.val(), this.data.partner.records[0].txt);
// make sure there is no scroll bar
- assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight,
+ assert.strictEqual($textarea[0].clientHeight, $textarea[0].scrollHeight,
"textarea should not have a scroll bar");
list.destroy();
});
- QUnit.test('text fields in edit mode should resize on reset', function (assert) {
+ QUnit.test('text fields in edit mode should resize on reset', async function (assert) {
assert.expect(1);
this.data.partner.fields.foo.type = 'text';
@@ -1584,7 +1585,7 @@ QUnit.module('basic_fields', {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1598,9 +1599,9 @@ QUnit.module('basic_fields', {
// edit the form
// trigger a textarea reset (through onchange) by clicking the box
// then check there is no scroll bar
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('div[name="bar"] input'));
+ await testUtils.dom.click(form.$('div[name="bar"] input'));
var $textarea = form.$('textarea:first');
assert.strictEqual($textarea.innerHeight(), $textarea[0].scrollHeight,
@@ -1609,7 +1610,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('text field translatable', function (assert) {
+ QUnit.test('text field translatable', async function (assert) {
assert.expect(3);
this.data.partner.fields.txt.translate = true;
@@ -1617,7 +1618,7 @@ QUnit.module('basic_fields', {
var multiLang = _t.database.multi_lang;
_t.database.multi_lang = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1632,18 +1633,18 @@ QUnit.module('basic_fields', {
mockRPC: function (route, args) {
if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
assert.deepEqual(args.args, ["partner",1,"txt",{}], 'should call "call_button" route');
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $button = form.$('textarea + .o_field_translate');
assert.strictEqual($button.length, 1, "should have a translate button");
- testUtils.dom.click($button);
+ await testUtils.dom.click($button);
form.destroy();
- form = createView({
+ form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1662,11 +1663,11 @@ QUnit.module('basic_fields', {
_t.database.multi_lang = multiLang;
});
- QUnit.test('go to next line (and not the next row) when pressing enter', function (assert) {
+ QUnit.test('go to next line (and not the next row) when pressing enter', async function (assert) {
assert.expect(4);
this.data.partner.fields.foo.type = 'text';
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -1677,7 +1678,7 @@ QUnit.module('basic_fields', {
'</list>',
});
- testUtils.dom.click(list.$('tbody tr:first .o_list_text'));
+ await testUtils.dom.click(list.$('tbody tr:first .o_list_text'));
var $textarea = list.$('textarea.o_field_text');
assert.strictEqual($textarea.length, 1, "should have a text area");
assert.strictEqual($textarea.val(), 'yop', 'should still be "yop" in edit');
@@ -1699,10 +1700,10 @@ QUnit.module('basic_fields', {
// 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) {
+ QUnit.test('copying text fields in RO mode should preserve line breaks', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1725,7 +1726,7 @@ QUnit.module('basic_fields', {
QUnit.module('FieldBinary');
- QUnit.test('binary fields are correctly rendered', function (assert) {
+ QUnit.test('binary fields are correctly rendered', async function (assert) {
assert.expect(16);
// save the session function
@@ -1736,11 +1737,11 @@ QUnit.module('basic_fields', {
assert.strictEqual(option.data.data, 'coucou==\n',
"we should download the correct data");
option.complete();
- return $.when();
+ return Promise.resolve();
};
this.data.partner.records[0].foo = 'coucou.txt';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1758,9 +1759,9 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_char').text(), 'coucou.txt',
"the filename field should have the file name as value");
- testUtils.dom.click(form.$('a.o_field_widget[name="document"]'));
+ await testUtils.dom.click(form.$('a.o_field_widget[name="document"]'));
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, 'a.o_field_widget[name="document"] > .fa-download',
"the binary field should not be rendered as a downloadable link in edit");
@@ -1774,7 +1775,7 @@ QUnit.module('basic_fields', {
"the filename field should have the file name as value");
- testUtils.dom.click(form.$('.o_field_binary_file > .o_clear_file_button'));
+ await testUtils.dom.click(form.$('.o_field_binary_file > .o_clear_file_button'));
assert.isNotVisible(form.$('.o_field_binary_file > input'),
"the input should be hidden");
@@ -1783,7 +1784,7 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('input.o_field_char').val(), '',
"the filename field should be empty since we removed the file");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsNone(form, 'a.o_field_widget[name="document"] > .fa-download',
"the binary field should not render as a downloadable link since we removed the file");
assert.strictEqual(form.$('a.o_field_widget[name="document"]').text().trim(), '',
@@ -1797,7 +1798,7 @@ QUnit.module('basic_fields', {
session.get_file = oldGetFile;
});
- QUnit.test('binary fields that are readonly in create mode do not download', function (assert) {
+ QUnit.test('binary fields that are readonly in create mode do not download', async function (assert) {
assert.expect(2);
// save the session function
@@ -1815,7 +1816,7 @@ QUnit.module('basic_fields', {
this.data.partner.fields.document.readonly = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1826,9 +1827,9 @@ QUnit.module('basic_fields', {
res_id: 1,
});
- testUtils.form.clickCreate(form);
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.form.clickCreate(form);
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
assert.containsOnce(form, 'a.o_field_widget[name="document"] > .fa-download',
'The link to download the binary should be present');
@@ -1843,10 +1844,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldPdfViewer');
- QUnit.test("pdf_viewer without data", function (assert) {
+ QUnit.test("pdf_viewer without data", async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1867,10 +1868,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test("pdf_viewer: basic rendering", function (assert) {
+ QUnit.test("pdf_viewer: basic rendering", async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1881,7 +1882,7 @@ QUnit.module('basic_fields', {
'</form>',
mockRPC: function (route) {
if (route.indexOf('/web/static/lib/pdfjs/web/viewer.html') !== -1) {
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
}
@@ -1899,7 +1900,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test("pdf_viewer: upload rendering", function (assert) {
+ QUnit.test("pdf_viewer: upload rendering", async function (assert) {
assert.expect(6);
testUtils.mock.patch(field_registry.map.pdf_viewer, {
@@ -1908,7 +1909,7 @@ QUnit.module('basic_fields', {
this._super.apply(this, arguments);
},
_getURI: function (fileURI) {
- var res = this._super.apply(this, arguments);
+ this._super.apply(this, arguments);
assert.step('_getURI');
assert.ok(_.str.startsWith(fileURI, 'blob:'));
this.PDFViewerApplication = {
@@ -1921,7 +1922,7 @@ QUnit.module('basic_fields', {
},
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1936,13 +1937,13 @@ QUnit.module('basic_fields', {
assert.verifySteps(['_getURI']);
// second upload call pdfjs method inside iframe
form.$('input[type="file"]').trigger('change');
- assert.verifySteps(['_getURI', 'open']);
+ assert.verifySteps(['open']);
testUtils.mock.unpatch(field_registry.map.pdf_viewer);
form.destroy();
});
- QUnit.test('text field rendering in list view', function (assert) {
+ QUnit.test('text field rendering in list view', async function (assert) {
assert.expect(1);
var data = {
@@ -1951,7 +1952,7 @@ QUnit.module('basic_fields', {
records: [{id: 1, foo: "some text"}]
},
};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: data,
@@ -1963,12 +1964,12 @@ QUnit.module('basic_fields', {
list.destroy();
});
- QUnit.test('field text in editable list view', function (assert) {
+ QUnit.test('field text in editable list view', async function (assert) {
assert.expect(1);
this.data.partner.fields.foo.type = 'text';
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -1977,22 +1978,22 @@ QUnit.module('basic_fields', {
'</tree>',
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.strictEqual(list.$('textarea').first().get(0), document.activeElement,
"text area should have the focus");
list.destroy();
});
- QUnit.test('field changes are correctly debounced in text fields', function (assert) {
+ QUnit.test('field changes are correctly debounced in text fields', async function (assert) {
var done = assert.async();
assert.expect(5);
this.data.partner.fields.foo.type = 'text';
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
var nbNotifyChanges = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2010,7 +2011,7 @@ QUnit.module('basic_fields', {
def.resolve();
};
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
testUtils.fields.editInput(form.$('textarea').first(), "1");
assert.strictEqual(nbNotifyChanges, 0,
@@ -2019,13 +2020,12 @@ QUnit.module('basic_fields', {
assert.strictEqual(nbNotifyChanges, 0,
"no event should have been triggered");
- return waitForChangeTriggered().then(function () {
+ return waitForChangeTriggered().then(async function () {
assert.strictEqual(nbNotifyChanges, 1,
"one event should have been triggered");
// add something in the textarea, then focus another input
- testUtils.fields.editInput(form.$('textarea').first(), "123");
- form.$('textarea').first().change();
+ await testUtils.fields.editInput(form.$('textarea').first(), "123");
assert.strictEqual(nbNotifyChanges, 2,
"one event should have been triggered immediately");
@@ -2040,7 +2040,7 @@ QUnit.module('basic_fields', {
function waitForChangeTriggered() {
return def.then(function () {
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
return concurrency.delay(0);
});
}
@@ -2048,13 +2048,13 @@ QUnit.module('basic_fields', {
QUnit.module('FieldImage');
- QUnit.test('image fields are correctly rendered', function (assert) {
+ QUnit.test('image fields are correctly rendered', async function (assert) {
assert.expect(7);
this.data.partner.records[0].__last_update = '2017-02-08 10:00:00';
this.data.partner.records[0].document = 'myimage';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2068,7 +2068,7 @@ QUnit.module('basic_fields', {
}
if (route === 'data:image/png;base64,myimage') {
assert.ok(true, "should called the correct route");
- return $.when('wow');
+ return Promise.resolve('wow');
}
return this._super.apply(this, arguments);
},
@@ -2087,7 +2087,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('image fields in subviews are loaded correctly', function (assert) {
+ QUnit.test('image fields in subviews are loaded correctly', async function (assert) {
assert.expect(6);
this.data.partner.records[0].__last_update = '2017-02-08 10:00:00';
@@ -2096,7 +2096,7 @@ QUnit.module('basic_fields', {
this.data.partner_type.records[0].image = 'product_image';
this.data.partner.records[0].timmy = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2112,14 +2112,14 @@ QUnit.module('basic_fields', {
'</field>' +
'</form>',
res_id: 1,
- mockRPC: function (route, args) {
+ mockRPC: function (route) {
if (route === 'data:image/png;base64,myimage') {
assert.step("The view's image should have been fetched");
- return $.when('wow');
+ return Promise.resolve('wow');
}
if (route === 'data:image/png;base64,product_image') {
assert.step("The dialog's image should have been fetched");
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
@@ -2130,25 +2130,22 @@ QUnit.module('basic_fields', {
'There should be one record in the many2many');
// Actual flow: click on an element of the m2m to get its form view
- testUtils.dom.click(form.$('tbody td:contains(gold)'));
+ await testUtils.dom.click(form.$('tbody td:contains(gold)'));
assert.strictEqual($('.modal').length, 1,
'The modal should have opened');
- assert.verifySteps([
- "The view's image should have been fetched",
- "The dialog's image should have been fetched",
- ]);
+ assert.verifySteps(["The dialog's image should have been fetched"]);
form.destroy();
});
- QUnit.test('image fields in x2many list are loaded correctly', function (assert) {
+ QUnit.test('image fields in x2many list are loaded correctly', async 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({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2160,10 +2157,10 @@ QUnit.module('basic_fields', {
'</field>' +
'</form>',
res_id: 1,
- mockRPC: function (route, args) {
+ mockRPC: function (route) {
if (route === 'data:image/png;base64,product_image') {
assert.ok(true, "The list's image should have been fetched");
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
@@ -2175,10 +2172,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('image fields with required attribute', function (assert) {
+ QUnit.test('image fields with required attribute', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2193,7 +2190,7 @@ QUnit.module('basic_fields', {
},
});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.hasClass(form.$('.o_form_view'),'o_form_editable',
"form view should still be editable");
@@ -2237,7 +2234,7 @@ QUnit.module('basic_fields', {
},
});
- QUnit.test('graph dashboard widget attach/detach callbacks', function (assert) {
+ QUnit.test('graph dashboard widget attach/detach callbacks', async function (assert) {
// This widget is rendered with nvd3, and nvd3 renders the graphs when
// the svg is in the DOM. The intent of this test is to determine when
// the field widgets are in the DOM, so that we can tell nvd3 to render
@@ -2254,7 +2251,7 @@ QUnit.module('basic_fields', {
},
});
- createAsyncView({
+ createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2276,8 +2273,6 @@ QUnit.module('basic_fields', {
kanban.on_detach_callback();
assert.verifySteps([
- 'on_attach_callback',
- 'on_attach_callback',
'on_detach_callback',
'on_detach_callback'
]);
@@ -2288,12 +2283,12 @@ QUnit.module('basic_fields', {
});
});
- QUnit.test('graph dashboard widget is rendered correctly', function (assert) {
+ QUnit.test('graph dashboard widget is rendered correctly', async function (assert) {
var done = assert.async();
assert.expect(4);
var graph_key = JSON.parse(this.data.partner.records[0].graph_data)[0].key;
- createAsyncView({
+ createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2343,7 +2338,7 @@ QUnit.module('basic_fields', {
});
});
- QUnit.test('graph dashboard widget does not need nv to be destroyed', function (assert) {
+ QUnit.test('graph dashboard widget does not need nv to be destroyed', async function (assert) {
// this test ensures that the JournalDashboardGraph widget doesn't crash
// when being destroyed before nv has been loaded
assert.expect(2);
@@ -2358,7 +2353,7 @@ QUnit.module('basic_fields', {
}
});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2382,7 +2377,7 @@ QUnit.module('basic_fields', {
return concurrency.delay(0);
});
- QUnit.test('graph dashboard widget can be destroyed when nv is partially loaded', function (assert) {
+ QUnit.test('graph dashboard widget can be destroyed when nv is partially loaded', async function (assert) {
// this test ensures that the JournalDashboardGraph widget doesn't crash
// when being destroyed before nv has been completely loaded
assert.expect(2);
@@ -2400,7 +2395,7 @@ QUnit.module('basic_fields', {
},
});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2424,12 +2419,12 @@ QUnit.module('basic_fields', {
return concurrency.delay(0);
});
- QUnit.test('rendering of a field with dashboard_graph widget in an updated kanban view (ungrouped)', function (assert) {
+ QUnit.test('rendering of a field with dashboard_graph widget in an updated kanban view (ungrouped)', async function (assert) {
var done = assert.async();
assert.expect(2);
- createAsyncView({
+ createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2460,12 +2455,12 @@ QUnit.module('basic_fields', {
});
});
- QUnit.test('rendering of a field with dashboard_graph widget in an updated kanban view (grouped)', function (assert) {
+ QUnit.test('rendering of a field with dashboard_graph widget in an updated kanban view (grouped)', async function (assert) {
var done = assert.async();
assert.expect(2);
- createAsyncView({
+ createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2496,12 +2491,12 @@ QUnit.module('basic_fields', {
QUnit.module('AceEditor');
- QUnit.test('ace widget on text fields works', function (assert) {
+ QUnit.test('ace widget on text fields works', async function (assert) {
assert.expect(2);
var done = assert.async();
this.data.partner.fields.foo.type = 'text';
- testUtils.createAsyncView({
+ testUtils.createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2519,11 +2514,11 @@ QUnit.module('basic_fields', {
QUnit.module('HandleWidget');
- QUnit.test('handle widget in x2m', function (assert) {
+ QUnit.test('handle widget in x2m', async function (assert) {
assert.expect(6);
this.data.partner.records[0].p = [2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2546,7 +2541,7 @@ QUnit.module('basic_fields', {
assert.containsN(form, 'span.o_row_handle', 2, "should have 2 handles");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasClass(form.$('td:first'),'o_handle_cell',
"column widget should be displayed in css class");
@@ -2560,10 +2555,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('handle widget with falsy values', function (assert) {
+ QUnit.test('handle widget with falsy values', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -2581,10 +2576,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldDate');
- QUnit.test('date field: toggle datepicker', function (assert) {
+ QUnit.test('date field: toggle datepicker [REQUIRE FOCUS]', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2597,13 +2592,13 @@ QUnit.module('basic_fields', {
assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0,
"datepicker should be closed initially");
- testUtils.dom.openDatepicker(form.$('.o_datepicker'));
+ await testUtils.dom.openDatepicker(form.$('.o_datepicker'));
assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 1,
"datepicker should be opened");
// focus another field
- testUtils.dom.click(form.$('.o_field_widget[name=foo]').focus().mouseenter());
+ await testUtils.dom.click(form.$('.o_field_widget[name=foo]').focus().mouseenter());
assert.strictEqual($('.bootstrap-datetimepicker-widget:visible').length, 0,
"datepicker should close itself when the user clicks outside");
@@ -2611,10 +2606,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field is empty if no date is set', function (assert) {
+ QUnit.test('date field is empty if no date is set', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2627,10 +2622,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field value should not set on first click', function (assert) {
+ QUnit.test('date field value should not set on first click', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2638,7 +2633,7 @@ QUnit.module('basic_fields', {
res_id: 4,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// open datepicker and select a date
testUtils.dom.openDatepicker(form.$('.o_datepicker'));
@@ -2653,10 +2648,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field in form view (with positive time zone offset)', function (assert) {
+ QUnit.test('date field in form view (with positive time zone offset)', async function (assert) {
assert.expect(8);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2682,7 +2677,7 @@ QUnit.module('basic_fields', {
'the date should be correctly displayed in readonly');
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
'the date should be correct in edit mode');
@@ -2700,16 +2695,16 @@ QUnit.module('basic_fields', {
'the selected date should be displayed in the input');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_date').text(), '02/22/2017',
'the selected date should be displayed after saving');
form.destroy();
});
- QUnit.test('date field in form view (with negative time zone offset)', function (assert) {
+ QUnit.test('date field in form view (with negative time zone offset)', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2729,17 +2724,17 @@ QUnit.module('basic_fields', {
'the date should be correctly displayed in readonly');
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
'the date should be correct in edit mode');
form.destroy();
});
- QUnit.test('date field with warn_future option', function (assert) {
+ QUnit.test('date field with warn_future option', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2750,7 +2745,7 @@ QUnit.module('basic_fields', {
});
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// open datepicker and select another value
testUtils.dom.openDatepicker(form.$('.o_datepicker'));
testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
@@ -2770,7 +2765,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field with warn_future option: do not overwrite datepicker option', function (assert) {
+ QUnit.test('date field with warn_future option: do not overwrite datepicker option', async function (assert) {
assert.expect(2);
// Making sure we don't have a legit default value
@@ -2778,7 +2773,7 @@ QUnit.module('basic_fields', {
this.data.partner.fields.date.default = undefined;
this.data.partner.onchanges = {};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2790,15 +2785,15 @@ QUnit.module('basic_fields', {
});
// switch to edit mode
- form.$buttons.find('.o_form_button_edit').click();
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name="date"]').val(), '02/03/2017',
- 'The existing record should have a value for the date field');
+ 'The existing record should have a value for the date field');
// save with no changes
- form.$buttons.find('.o_form_button_save').click();
+ await testUtils.form.clickSave(form);
//Create a new record
- form.$buttons.find('.o_form_button_create').click();
+ await testUtils.form.clickCreate(form);
assert.notOk(form.$('input[name="date"]').val(),
'The new record should not have a value that the framework would have set');
@@ -2806,10 +2801,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field in editable list view', function (assert) {
+ QUnit.test('date field in editable list view', async function (assert) {
assert.expect(8);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -2829,7 +2824,7 @@ QUnit.module('basic_fields', {
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
assert.strictEqual($cell.text(), '02/03/2017',
'the date should be displayed correctly in readonly');
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.containsOnce(list, 'input.o_datepicker_input',
"the view should have a date input for editable mode");
@@ -2841,29 +2836,29 @@ QUnit.module('basic_fields', {
'the date should be correct in edit mode');
// open datepicker and select another value
- testUtils.dom.openDatepicker(list.$('.o_datepicker'));
+ await testUtils.dom.openDatepicker(list.$('.o_datepicker'));
assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open');
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1));
- testUtils.dom.click($('.day:contains(22)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1));
+ await testUtils.dom.click($('.day:contains(22)'));
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
assert.strictEqual(list.$('.o_datepicker_input').val(), '02/22/2017',
'the selected date should be displayed in the input');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector)').text(), '02/22/2017',
'the selected date should be displayed after saving');
list.destroy();
});
- QUnit.test('date field remove value', function (assert) {
+ QUnit.test('date field remove value', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2881,7 +2876,7 @@ QUnit.module('basic_fields', {
});
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/03/2017',
'the date should be correct in edit mode');
@@ -2890,17 +2885,17 @@ QUnit.module('basic_fields', {
'should have correctly removed the value');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_date').text(), '',
'the selected date should be displayed after saving');
form.destroy();
});
- QUnit.test('do not trigger a field_changed for datetime field with date widget', function (assert) {
+ QUnit.test('do not trigger a field_changed for datetime field with date widget', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2923,18 +2918,18 @@ QUnit.module('basic_fields', {
'the date should be correct');
testUtils.fields.editAndTrigger(form.$('input[name="datetime"]'),'02/08/2017', ['input', 'change', 'focusout']);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps(['read']); // should not have save as nothing changed
form.destroy();
});
- QUnit.test('field date should select its content onclick when there is one', function (assert) {
+ QUnit.test('field date should select its content onclick when there is one', async function (assert) {
assert.expect(2);
var done = assert.async();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2962,7 +2957,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('date field support internalization', function (assert) {
+ QUnit.test('date field support internalization', async function (assert) {
assert.expect(2);
var originalLocale = moment.locale();
@@ -2976,7 +2971,7 @@ QUnit.module('basic_fields', {
ordinal: '%d.',
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2985,14 +2980,14 @@ QUnit.module('basic_fields', {
});
var dateViewForm = form.$('.o_field_date').text();
- testUtils.dom.click(form.$buttons.find('.o_form_button_edit'));
- testUtils.openDatepicker(form.$('.o_datepicker'));
+ await testUtils.dom.click(form.$buttons.find('.o_form_button_edit'));
+ await testUtils.openDatepicker(form.$('.o_datepicker'));
assert.strictEqual(form.$('.o_datepicker_input').val(), dateViewForm,
"input date field should be the same as it was in the view form");
- testUtils.dom.click($('.day:contains(30)'));
- var dateEditForm = form.$('.o_datepicker_input').val()
- testUtils.dom.click(form.$buttons.find('.o_form_button_save'));
+ await testUtils.dom.click($('.day:contains(30)'));
+ var dateEditForm = form.$('.o_datepicker_input').val();
+ await testUtils.dom.click(form.$buttons.find('.o_form_button_save'));
assert.strictEqual(form.$('.o_field_date').text(), dateEditForm,
"date field should be the same as the one selected in the view form");
@@ -3005,10 +3000,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldDatetime');
- QUnit.test('datetime field in form view', function (assert) {
+ QUnit.test('datetime field in form view', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3030,23 +3025,23 @@ QUnit.module('basic_fields', {
'the datetime should be correctly displayed in readonly');
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_datepicker_input').val(), expectedDateString,
'the datetime should be correct in edit mode');
// select 22 February at 8:23:33
assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open');
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(3));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .day:contains(22)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .fa-clock-o'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hour'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .hour:contains(08)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-minute'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .minute:contains(25)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-second'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .second:contains(35)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(3));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .day:contains(22)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .fa-clock-o'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hour'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .hour:contains(08)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-minute'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .minute:contains(25)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-second'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .second:contains(35)'));
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
var newExpectedDateString = "04/22/2017 08:25:35";
@@ -3054,7 +3049,7 @@ QUnit.module('basic_fields', {
'the selected date should be displayed in the input');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_date').text(), newExpectedDateString,
'the selected date should be displayed after saving');
@@ -3062,10 +3057,10 @@ QUnit.module('basic_fields', {
});
- QUnit.test('datetime field not visible in form view should not capture the focus on keyboard navigation', function (assert) {
+ QUnit.test('datetime field not visible in form view should not capture the focus on keyboard navigation', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3086,13 +3081,13 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('datetime field with datetime formatted without second', function (assert) {
+ QUnit.test('datetime field with datetime formatted without second', async 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({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3107,7 +3102,7 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_date input').val(), expectedDateString,
'the datetime should be correctly displayed in readonly');
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.strictEqual($('.modal').length, 0,
"there should not be a Warning dialog");
@@ -3115,10 +3110,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('datetime field in editable list view', function (assert) {
+ QUnit.test('datetime field in editable list view', async function (assert) {
assert.expect(8);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -3142,7 +3137,7 @@ QUnit.module('basic_fields', {
'the datetime should be correctly displayed in readonly');
// switch to edit mode
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.containsOnce(list, 'input.o_datepicker_input',
"the view should have a date input for editable mode");
@@ -3154,18 +3149,18 @@ QUnit.module('basic_fields', {
// select 22 February at 8:23:33
assert.ok($('.bootstrap-datetimepicker-widget').length, 'datepicker should be open');
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(3));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .day:contains(22)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .fa-clock-o'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hour'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .hour:contains(08)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-minute'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .minute:contains(25)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-second'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .second:contains(35)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(3));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .day:contains(22)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .fa-clock-o'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hour'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .hour:contains(08)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-minute'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .minute:contains(25)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-second'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .second:contains(35)'));
assert.ok(!$('.bootstrap-datetimepicker-widget').length, 'datepicker should be closed');
var newExpectedDateString = "04/22/2017 08:25:35";
@@ -3173,17 +3168,17 @@ QUnit.module('basic_fields', {
'the selected datetime should be displayed in the input');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector)').text(), newExpectedDateString,
'the selected datetime should be displayed after saving');
list.destroy();
});
- QUnit.test('datetime field remove value', function (assert) {
+ QUnit.test('datetime field remove value', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3207,29 +3202,29 @@ QUnit.module('basic_fields', {
});
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_datepicker_input').val(), '02/08/2017 12:00:00',
'the date time should be correct in edit mode');
- testUtils.fields.editAndTrigger($('.o_datepicker_input'), '', ['input', 'change', 'focusout']);
+ await testUtils.fields.editAndTrigger($('.o_datepicker_input'), '', ['input', 'change', 'focusout']);
assert.strictEqual(form.$('.o_datepicker_input').val(), '',
"should have an empty input");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_date').text(), '',
'the selected date should be displayed after saving');
form.destroy();
});
- QUnit.test('datetime field with date/datetime widget (with day change)', function (assert) {
+ QUnit.test('datetime field with date/datetime widget (with day change)', async 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({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3260,20 +3255,20 @@ QUnit.module('basic_fields', {
'the datetime (datetime widget) should be correctly displayed in tree view');
// switch to form view
- testUtils.dom.click(form.$('.o_field_widget[name=p] .o_data_row'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=p] .o_data_row'));
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) {
+ QUnit.test('datetime field with date/datetime widget (without day change)', async 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({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3304,20 +3299,20 @@ QUnit.module('basic_fields', {
'the datetime (datetime widget) should be correctly displayed in tree view');
// switch to form view
- testUtils.dom.click(form.$('.o_field_widget[name=p] .o_data_row'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=p] .o_data_row'));
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.test('datepicker option: daysOfWeekDisabled', function (assert) {
+ QUnit.test('datepicker option: daysOfWeekDisabled', async function (assert) {
assert.expect(42);
this.data.partner.fields.datetime.default = "2017-08-02 12:00:05";
this.data.partner.fields.datetime.required = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3328,7 +3323,7 @@ QUnit.module('basic_fields', {
res_id: 1,
});
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
$.each($('.day:last-child(),.day:nth-child(2)'), function (index, value) {
assert.hasClass(value, 'disabled', 'first and last days must be disabled');
});
@@ -3343,10 +3338,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldMonetary');
- QUnit.test('monetary field in form view', function (assert) {
+ QUnit.test('monetary field in form view', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3366,17 +3361,17 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a09.10',
'The value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '9.10',
'The input should be rendered without the currency symbol.');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').parent().children().first().text(), '$',
'The input should be preceded by a span containing the currency symbol.');
- testUtils.fields.editInput(form.$('.o_field_monetary input'), '108.2458938598598');
+ await testUtils.fields.editInput(form.$('.o_field_monetary input'), '108.2458938598598');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '108.2458938598598',
'The value should not be formated yet.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// Non-breaking space between the currency and the amount
assert.strictEqual(form.$('.o_field_widget').first().text(), '$\u00a0108.25',
'The new value should be rounded properly.');
@@ -3384,10 +3379,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('monetary field with currency symbol after', function (assert) {
+ QUnit.test('monetary field with currency symbol after', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3407,17 +3402,17 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '0.00\u00a0€',
'The value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '0.00',
'The input should be rendered without the currency symbol.');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').parent().children().eq(1).text(), '€',
'The input should be followed by a span containing the currency symbol.');
- testUtils.fields.editInput(form.$('.o_field_widget[name=qux] input'), '108.2458938598598');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=qux] input'), '108.2458938598598');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '108.2458938598598',
'The value should not be formated yet.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// Non-breaking space between the currency and the amount
assert.strictEqual(form.$('.o_field_widget').first().text(), '108.25\u00a0€',
'The new value should be rounded properly.');
@@ -3425,7 +3420,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('monetary field with currency digits != 2', function (assert) {
+ QUnit.test('monetary field with currency digits != 2', async function (assert) {
assert.expect(5);
this.data.partner.records = [{
@@ -3444,7 +3439,7 @@ QUnit.module('basic_fields', {
digits: [16, 4],
}];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3464,17 +3459,17 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '99.1234\u00a0Bs.F',
'The value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '99.1234',
'The input should be rendered without the currency symbol.');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').parent().children().eq(1).text(), 'Bs.F',
'The input should be followed by a span containing the currency symbol.');
- testUtils.fields.editInput(form.$('.o_field_widget[name=qux] input'), '99.111111111');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=qux] input'), '99.111111111');
assert.strictEqual(form.$('.o_field_widget[name=qux] input').val(), '99.111111111',
'The value should not be formated yet.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// Non-breaking space between the currency and the amount
assert.strictEqual(form.$('.o_field_widget').first().text(), '99.1111\u00a0Bs.F',
'The new value should be rounded properly.');
@@ -3482,10 +3477,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('monetary field in editable list view', function (assert) {
+ QUnit.test('monetary field in editable list view', async function (assert) {
assert.expect(9);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -3512,7 +3507,7 @@ QUnit.module('basic_fields', {
// switch to edit mode
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector):contains($)');
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.strictEqual($cell.children().length, 1,
'The cell td should only contain the special div of monetary widget.');
@@ -3523,18 +3518,18 @@ QUnit.module('basic_fields', {
assert.strictEqual(list.$('[name="qux"] input').parent().children().first().text(), '$',
'The input should be preceded by a span containing the currency symbol.');
- testUtils.fields.editInput(list.$('[name="qux"] input'), '108.2458938598598');
+ await testUtils.fields.editInput(list.$('[name="qux"] input'), '108.2458938598598');
assert.strictEqual(list.$('[name="qux"] input').val(), '108.2458938598598',
'The typed value should be correctly displayed.');
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('tr.o_data_row td:not(.o_list_record_selector):contains($)').text(), '$\u00a0108.25',
'The new value should be rounded properly.');
list.destroy();
});
- QUnit.test('monetary field with real monetary field in model', function (assert) {
+ QUnit.test('monetary field with real monetary field in model', async function (assert) {
assert.expect(7);
this.data.partner.fields.qux.type = "monetary";
@@ -3542,7 +3537,7 @@ QUnit.module('basic_fields', {
string: "Quux", type: "monetary", digits: [16,1], searchable: true, readonly: true,
};
- (_.find(this.data.partner.records, function (record) { return record.id === 5 })).quux = 4.2;
+ (_.find(this.data.partner.records, function (record) { return record.id === 5; })).quux = 4.2;
this.data.partner.onchanges = {
bar: function (obj) {
@@ -3550,7 +3545,7 @@ QUnit.module('basic_fields', {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3573,19 +3568,19 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_monetary').first().next().html(), "$&nbsp;4.20",
"readonly value should contain the currency");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_monetary > input').val(), "9.10",
"input value in edition should only contain the value, without the currency");
- testUtils.dom.click(form.$('input[type="checkbox"]'));
+ await testUtils.dom.click(form.$('input[type="checkbox"]'));
assert.containsOnce(form, '.o_field_monetary > input',
"After the onchange, the monetary <input/> should not have been duplicated");
assert.containsOnce(form, '.o_field_monetary[name=quux]',
"After the onchange, the monetary readonly field should not have been duplicated");
- testUtils.fields.many2one.clickOpenDropdown('currency_id');
- testUtils.fields.many2one.clickItem('currency_id','€');
+ await testUtils.fields.many2one.clickOpenDropdown('currency_id');
+ await testUtils.fields.many2one.clickItem('currency_id','€');
assert.strictEqual(form.$('.o_field_monetary > span').html(), "€",
"After currency change, the monetary field currency should have been updated");
assert.strictEqual(form.$('.o_field_monetary').first().next().html(), "4.20&nbsp;€",
@@ -3594,7 +3589,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('monetary field with monetary field given in options', function (assert) {
+ QUnit.test('monetary field with monetary field given in options', async function (assert) {
assert.expect(1);
this.data.partner.fields.qux.type = "monetary";
@@ -3603,7 +3598,7 @@ QUnit.module('basic_fields', {
};
this.data.partner.records[4].company_currency_id = 2;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3625,14 +3620,14 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('should keep the focus when being edited in x2many lists', function (assert) {
+ QUnit.test('should keep the focus when being edited in x2many lists', async function (assert) {
assert.expect(6);
this.data.partner.fields.currency_id.default = 1;
this.data.partner.fields.m2m = {
string: "m2m", type: "many2many", relation: 'partner', default: [[6, false, [2]]],
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3655,30 +3650,30 @@ QUnit.module('basic_fields', {
// test the monetary field inside the one2many
var $o2m = form.$('.o_field_widget[name=p]');
- testUtils.dom.click($o2m.find('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($o2m.find('.o_field_widget input'), "22");
+ await testUtils.dom.click($o2m.find('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($o2m.find('.o_field_widget input'), "22");
assert.strictEqual($o2m.find('.o_field_widget input').get(0), document.activeElement,
"the focus should still be on the input");
assert.strictEqual($o2m.find('.o_field_widget input').val(), "22",
"the value should not have been formatted yet");
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$el);
assert.strictEqual($o2m.find('.o_field_widget[name=qux]').html(), "$&nbsp;22.00",
"the value should have been formatted after losing the focus");
// test the monetary field inside the many2many
var $m2m = form.$('.o_field_widget[name=m2m]');
- testUtils.dom.click($m2m.find('.o_data_row td:first'));
- testUtils.fields.editInput($m2m.find('.o_field_widget input'), "22");
+ await testUtils.dom.click($m2m.find('.o_data_row td:first'));
+ await testUtils.fields.editInput($m2m.find('.o_field_widget input'), "22");
assert.strictEqual($m2m.find('.o_field_widget input').get(0), document.activeElement,
"the focus should still be on the input");
assert.strictEqual($m2m.find('.o_field_widget input').val(), "22",
"the value should not have been formatted yet");
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$el);
assert.strictEqual($m2m.find('.o_field_widget[name=qux]').html(), "22.00&nbsp;€",
"the value should have been formatted after losing the focus");
@@ -3698,7 +3693,7 @@ QUnit.module('basic_fields', {
},
};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -3712,33 +3707,32 @@ QUnit.module('basic_fields', {
},
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.containsOnce(list, 'div.o_field_widget[name=qux] input',
"monetary field should have been rendered correctly (without currency)");
assert.containsNone(list, '.o_field_widget[name=qux] span',
"monetary field should have been rendered correctly (without currency)");
// set a value for int_field -> should set the currency and re-render qux
- testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'),'7');
+ await testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'),'7');
assert.containsOnce(list, 'div.o_field_widget[name=qux] input',
"monetary field should have been re-rendered correctly (with currency)");
assert.strictEqual(list.$('.o_field_widget[name=qux] span:contains(€)').length, 1,
"monetary field should have been re-rendered correctly (with currency)");
var $quxInput = list.$('.o_field_widget[name=qux] input');
- testUtils.dom.click($quxInput);
+ await testUtils.dom.click($quxInput);
assert.strictEqual(document.activeElement, $quxInput[0],
"focus should be on the qux field's input");
// unset the value of int_field -> should unset the currency and re-render qux
- testUtils.dom.click(list.$('.o_field_widget[name=int_field]'));
- testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'),'0');
+ await testUtils.dom.click(list.$('.o_field_widget[name=int_field]'));
+ await testUtils.fields.editInput(list.$('.o_field_widget[name=int_field]'),'0');
$quxInput = list.$('div.o_field_widget[name=qux] input');
assert.strictEqual($quxInput.length, 1,
"monetary field should have been re-rendered correctly (without currency)");
assert.containsNone(list, '.o_field_widget[name=qux] span',
"monetary field should have been re-rendered correctly (without currency)");
- await concurrency.delay(0);
- testUtils.dom.click($quxInput);
+ await testUtils.dom.click($quxInput);
assert.strictEqual(document.activeElement, $quxInput[0],
"focus should be on the qux field's input");
@@ -3747,10 +3741,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldInteger');
- QUnit.test('integer field when unset', function (assert) {
+ QUnit.test('integer field when unset', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3766,10 +3760,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('integer field in form view', function (assert) {
+ QUnit.test('integer field in form view', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3780,22 +3774,22 @@ QUnit.module('basic_fields', {
assert.doesNotHaveClass(form.$('.o_field_widget'), 'o_field_empty',
'Integer field should be considered set for value 0.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=int_field]').val(), '0',
'The value should be rendered correctly in edit mode.');
- testUtils.fields.editInput(form.$('input[name=int_field]'), '-18');
+ await testUtils.fields.editInput(form.$('input[name=int_field]'), '-18');
assert.strictEqual(form.$('input[name=int_field]').val(), '-18',
'The value should be correctly displayed in the input.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), '-18',
'The new value should be saved and displayed properly.');
form.destroy();
});
- QUnit.test('integer field in form view with virtual id', function (assert) {
+ QUnit.test('integer field in form view with virtual id', async function (assert) {
assert.expect(1);
var params = {
View: FormView,
@@ -3805,17 +3799,17 @@ QUnit.module('basic_fields', {
};
params.res_id = this.data.partner.records[1].id = "2-20170808020000";
- var form = createView(params);
+ var form = await createView(params);
assert.strictEqual(form.$('.o_field_widget').text(), "2-20170808020000",
"Should display virtual id");
form.destroy();
});
- QUnit.test('integer field in editable list view', function (assert) {
+ QUnit.test('integer field in editable list view', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -3830,26 +3824,26 @@ QUnit.module('basic_fields', {
// switch to edit mode
var $cell = list.$('tr.o_data_row td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.containsOnce(list, 'input[name="int_field"]',
'The view should have 1 input for editable integer.');
- testUtils.fields.editInput(list.$('input[name="int_field"]'), '-28');
+ await testUtils.fields.editInput(list.$('input[name="int_field"]'), '-28');
assert.strictEqual(list.$('input[name="int_field"]').val(), '-28',
'The value should be displayed properly in the input.');
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('td:not(.o_list_record_selector)').first().text(), '-28',
'The new value should be saved and displayed properly.');
list.destroy();
});
- QUnit.test('integer field with type number option', function (assert) {
+ QUnit.test('integer field with type number option', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3863,28 +3857,28 @@ QUnit.module('basic_fields', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('.o_field_widget')[0].hasAttribute('type'),
'Integer field with option type must have a type attribute.');
assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'number',
'Integer field with option type must have a type attribute equals to "number".');
- testUtils.fields.editInput(form.$('input[name=int_field]'), '1234567890');
- testUtils.form.clickSave(form);
- testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=int_field]'), '1234567890');
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget').val(), '1234567890',
'Integer value must be not formatted if input type is number.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), '1,234,567,890',
'Integer value must be formatted in readonly view even if the input type is number.');
form.destroy();
});
- QUnit.test('integer field without type number option', function (assert) {
+ QUnit.test('integer field without type number option', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3898,13 +3892,13 @@ QUnit.module('basic_fields', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasAttrValue(form.$('.o_field_widget'), 'type', 'text',
'Integer field without option type must have a text type (default type).');
- testUtils.fields.editInput(form.$('input[name=int_field]'), '1234567890');
- testUtils.form.clickSave(form);
- testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=int_field]'), '1234567890');
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget').val(), '1,234,567,890',
'Integer value must be formatted if input type isn\'t number.');
@@ -3914,10 +3908,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldFloatTime');
- QUnit.test('float_time field in form view', function (assert) {
+ QUnit.test('float_time field in form view', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3940,15 +3934,15 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '09:06',
'The formatted time value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=qux]').val(), '09:06',
'The value should be rendered correctly in the input.');
- testUtils.fields.editInput(form.$('input[name=qux]'), '-11:48');
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '-11:48');
assert.strictEqual(form.$('input[name=qux]').val(), '-11:48',
'The new value should be displayed properly in the input.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').first().text(), '-11:48',
'The new value should be saved and displayed properly.');
@@ -3958,10 +3952,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldFloatFactor');
- QUnit.test('float_factor field in form view', function (assert) {
+ QUnit.test('float_factor field in form view', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3982,13 +3976,13 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '4.55', // 9.1 / 0.5
'The formatted value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=qux]').val(), '4.55',
'The value should be rendered correctly in the input.');
- testUtils.fields.editInput(form.$('input[name=qux]'), '2.3');
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '2.3');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').first().text(), '2.30',
'The new value should be saved and displayed properly.');
@@ -3997,10 +3991,10 @@ QUnit.module('basic_fields', {
QUnit.module('FieldFloatToggle');
- QUnit.test('float_toggle field in form view', function (assert) {
+ QUnit.test('float_toggle field in form view', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4021,17 +4015,17 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget').first().text(), '0.056',
'The formatted time value should be displayed properly.');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('button.o_field_float_toggle').text(), '0.056',
'The value should be rendered correctly on the button.');
- testUtils.dom.click(form.$('button.o_field_float_toggle'));
+ await testUtils.dom.click(form.$('button.o_field_float_toggle'));
assert.strictEqual(form.$('button.o_field_float_toggle').text(), '1.000',
'The value should be rendered correctly on the button.');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').first().text(), '1.000',
'The new value should be saved and displayed properly.');
@@ -4042,10 +4036,10 @@ QUnit.module('basic_fields', {
QUnit.module('PhoneWidget');
- QUnit.test('phone field in form view on normal screens', function (assert) {
+ QUnit.test('phone field in form view on normal screens', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4071,27 +4065,27 @@ QUnit.module('basic_fields', {
"value should be displayed properly");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[type="text"].o_field_widget',
"should have an input for the phone field");
assert.strictEqual(form.$('input[type="text"].o_field_widget').val(), 'yop',
"input should contain field value in edit mode");
// change value in edit mode
- testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new');
+ await testUtils.fields.editInput(form.$('input[type="text"].o_field_widget'), 'new');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('a.o_field_widget.o_form_uri').text(), 'new',
"new value should be displayed properly");
form.destroy();
});
- QUnit.test('phone field in editable list view on normal screens', function (assert) {
+ QUnit.test('phone field in editable list view on normal screens', async function (assert) {
assert.expect(8);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -4103,8 +4097,7 @@ QUnit.module('basic_fields', {
},
});
- assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').length, 5,
- "should have 5 cells");
+ assert.containsN(list, 'tbody td:not(.o_list_record_selector)', 5);
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'yop',
"value should be displayed properly");
@@ -4113,14 +4106,14 @@ QUnit.module('basic_fields', {
// Edit a line and check the result
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.hasClass($cell.parent(),'o_selected_row', 'should be set as edit mode');
assert.strictEqual($cell.find('input').val(), 'yop',
'should have the corect value in internal input');
- testUtils.fields.editInput($cell.find('input'), 'new');
+ await testUtils.fields.editInput($cell.find('input'), 'new');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
assert.doesNotHaveClass($cell.parent(), 'o_selected_row', 'should not be in edit mode anymore');
assert.strictEqual(list.$('tbody td:not(.o_list_record_selector)').first().text(), 'new',
@@ -4131,10 +4124,10 @@ QUnit.module('basic_fields', {
list.destroy();
});
- QUnit.test('use TAB to navigate to a phone field', function (assert) {
+ QUnit.test('use TAB to navigate to a phone field', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4160,10 +4153,10 @@ QUnit.module('basic_fields', {
QUnit.module('PriorityWidget');
- QUnit.test('priority widget when not set', function (assert) {
+ QUnit.test('priority widget when not set', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4189,10 +4182,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('priority widget in form view', function (assert) {
+ QUnit.test('priority widget in form view', async function (assert) {
assert.expect(22);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4228,7 +4221,7 @@ QUnit.module('basic_fields', {
// occurs in a setTimeout after 200ms so it's not trivial to test it here.
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
"should still have two stars");
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
@@ -4237,7 +4230,7 @@ QUnit.module('basic_fields', {
"should still have one empty star since the value is the second value");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
"should still have two stars");
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
@@ -4246,7 +4239,7 @@ QUnit.module('basic_fields', {
"should still have one empty star since the value is the second value");
// switch to edit mode to check that the new value was properly written
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
"should still have two stars");
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 1,
@@ -4255,7 +4248,7 @@ QUnit.module('basic_fields', {
"should still have one empty star since the value is the second value");
// click on the second star in edit mode
- testUtils.dom.click(form.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').last());
+ await testUtils.dom.click(form.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').last());
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
"should still have two stars");
@@ -4265,7 +4258,7 @@ QUnit.module('basic_fields', {
"should now have no empty star since the value is the third value");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star').length, 2,
"should still have two stars");
assert.strictEqual(form.$('.o_field_widget.o_priority').find('a.o_priority_star.fa-star').length, 2,
@@ -4276,10 +4269,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('priority widget in editable list view', function (assert) {
+ QUnit.test('priority widget in editable list view', async function (assert) {
assert.expect(25);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -4300,7 +4293,7 @@ QUnit.module('basic_fields', {
// switch to edit mode and check the result
var $cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
"should have two stars for representing each possible value: no star, one star and two stars");
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1,
@@ -4309,7 +4302,7 @@ QUnit.module('basic_fields', {
"should have one empty star since the value is the second value");
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
"should have two stars for representing each possible value: no star, one star and two stars");
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star.fa-star').length, 1,
@@ -4327,7 +4320,7 @@ QUnit.module('basic_fields', {
"should temporary have no empty star since we are hovering the third value");
// click on the first star in readonly mode
- testUtils.dom.click(list.$('.o_priority a.o_priority_star.fa-star').first());
+ await testUtils.dom.click(list.$('.o_priority a.o_priority_star.fa-star').first());
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
"should still have two stars");
@@ -4338,7 +4331,7 @@ QUnit.module('basic_fields', {
// re-enter edit mode to force re-rendering the widget to check if the value was correctly saved
$cell = list.$('tbody td:not(.o_list_record_selector)').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.strictEqual(list.$('.o_data_row').first().find('.o_priority a.o_priority_star').length, 2,
"should still have two stars");
@@ -4348,7 +4341,7 @@ QUnit.module('basic_fields', {
"should now have two empty stars since the value is the first value");
// Click on second star in edit mode
- testUtils.dom.click(list.$('.o_priority a.o_priority_star.fa-star-o').last());
+ await testUtils.dom.click(list.$('.o_priority a.o_priority_star.fa-star-o').last());
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star').length, 2,
"should still have two stars");
@@ -4358,7 +4351,7 @@ QUnit.module('basic_fields', {
"should now have no empty star since the value is the third value");
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star').length, 2,
"should still have two stars");
assert.strictEqual(list.$('.o_data_row').last().find('.o_priority a.o_priority_star.fa-star').length, 2,
@@ -4372,10 +4365,10 @@ QUnit.module('basic_fields', {
QUnit.module('StateSelection Widget');
- QUnit.test('state_selection widget in form view', function (assert) {
+ QUnit.test('state_selection widget in form view', async function (assert) {
assert.expect(21);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4400,14 +4393,14 @@ QUnit.module('basic_fields', {
"there should not be a dropdown");
// Click on the status button to make the dropdown appear
- testUtils.dom.click(form.$('.o_field_widget.o_selection .o_status').first());
+ await testUtils.dom.click(form.$('.o_field_widget.o_selection .o_status').first());
assert.containsOnce(form, '.dropdown-menu.state:visible',
"there should be a dropdown");
assert.containsN(form, '.dropdown-menu.state:visible .dropdown-item', 2,
"there should be two options in the dropdown");
// Click on the first option, "Normal"
- testUtils.dom.click(form.$('.dropdown-menu.state:visible .dropdown-item').first());
+ await testUtils.dom.click(form.$('.dropdown-menu.state:visible .dropdown-item').first());
assert.containsNone(form, '.dropdown-menu.state:visible',
"there should not be a dropdown anymore");
assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red',
@@ -4418,7 +4411,7 @@ QUnit.module('basic_fields', {
"should have one grey status since selection is the first, normal state");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, '.dropdown-menu.state:visible',
"there should still not be a dropdown");
assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red',
@@ -4429,14 +4422,14 @@ QUnit.module('basic_fields', {
"should still have one grey status since selection is the first, normal state");
// Click on the status button to make the dropdown appear
- testUtils.dom.click(form.$('.o_field_widget.o_selection .o_status').first());
+ await testUtils.dom.click(form.$('.o_field_widget.o_selection .o_status').first());
assert.containsOnce(form, '.dropdown-menu.state:visible',
"there should be a dropdown");
assert.containsN(form, '.dropdown-menu.state:visible .dropdown-item', 2,
"there should be two options in the dropdown");
// Click on the last option, "Done"
- testUtils.dom.click(form.$('.dropdown-menu.state:visible .dropdown-item').last());
+ await testUtils.dom.click(form.$('.dropdown-menu.state:visible .dropdown-item').last());
assert.containsNone(form, '.dropdown-menu.state:visible',
"there should not be a dropdown anymore");
assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red',
@@ -4445,7 +4438,7 @@ QUnit.module('basic_fields', {
"should have one green status since selection is the third, done state");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsNone(form, '.dropdown-menu.state:visible',
"there should still not be a dropdown anymore");
assert.containsNone(form, '.o_field_widget.o_selection > a span.o_status.o_status_red',
@@ -4456,10 +4449,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('state_selection widget with readonly modifier', function (assert) {
+ QUnit.test('state_selection widget with readonly modifier', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4471,16 +4464,16 @@ QUnit.module('basic_fields', {
assert.hasClass(form.$('.o_selection > a'), 'disabled');
assert.isNotVisible(form.$('.dropdown-menu.state'));
- testUtils.dom.click(form.$('.o_selection > a'));
+ await testUtils.dom.click(form.$('.o_selection > a'));
assert.isNotVisible(form.$('.dropdown-menu.state'));
form.destroy();
});
- QUnit.test('state_selection widget in editable list view', function (assert) {
+ QUnit.test('state_selection widget in editable list view', async function (assert) {
assert.expect(32);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -4501,7 +4494,7 @@ QUnit.module('basic_fields', {
// Click on the status button to make the dropdown appear
var $cell = list.$('tbody td.o_state_selection_cell').first();
- testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').first());
+ await testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').first());
assert.doesNotHaveClass($cell.parent(), 'o_selected_row',
'should not be in edit mode since we clicked on the state selection widget');
assert.containsOnce(list, '.dropdown-menu.state:visible',
@@ -4510,7 +4503,7 @@ QUnit.module('basic_fields', {
"there should be two options in the dropdown");
// Click on the first option, "Normal"
- testUtils.dom.click(list.$('.dropdown-menu.state:visible .dropdown-item').first());
+ await testUtils.dom.click(list.$('.dropdown-menu.state:visible .dropdown-item').first());
assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5,
"should still have five status selection widgets");
assert.containsNone(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red',
@@ -4522,7 +4515,7 @@ QUnit.module('basic_fields', {
// switch to edit mode and check the result
$cell = list.$('tbody td.o_state_selection_cell').first();
- testUtils.dom.click($cell);
+ await testUtils.dom.click($cell);
assert.hasClass($cell.parent(),'o_selected_row',
'should now be in edit mode');
assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5,
@@ -4535,7 +4528,7 @@ QUnit.module('basic_fields', {
"there should not be a dropdown");
// Click on the status button to make the dropdown appear
- testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').first());
+ await testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').first());
assert.containsOnce(list, '.dropdown-menu.state:visible',
"there should be a dropdown");
assert.containsN(list, '.dropdown-menu.state:visible .dropdown-item', 2,
@@ -4543,7 +4536,7 @@ QUnit.module('basic_fields', {
// Click on another row
var $lastCell = list.$('tbody td.o_state_selection_cell').last();
- testUtils.dom.click($lastCell);
+ await testUtils.dom.click($lastCell);
assert.containsNone(list, '.dropdown-menu.state:visible',
"there should not be a dropdown anymore");
var $firstCell = list.$('tbody td.o_state_selection_cell').first();
@@ -4553,14 +4546,14 @@ QUnit.module('basic_fields', {
'last row should be in edit mode');
// Click on the last status button to make the dropdown appear
- testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').last());
+ await testUtils.dom.click(list.$('.o_state_selection_cell .o_selection > a span.o_status').last());
assert.containsOnce(list, '.dropdown-menu.state:visible',
"there should be a dropdown");
assert.containsN(list, '.dropdown-menu.state:visible .dropdown-item', 2,
"there should be two options in the dropdown");
// Click on the last option, "Done"
- testUtils.dom.click(list.$('.dropdown-menu.state:visible .dropdown-item').last());
+ await testUtils.dom.click(list.$('.dropdown-menu.state:visible .dropdown-item').last());
assert.containsNone(list, '.dropdown-menu.state:visible',
"there should not be a dropdown anymore");
assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5,
@@ -4573,7 +4566,7 @@ QUnit.module('basic_fields', {
"there should not be a dropdown");
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.containsN(list, '.o_state_selection_cell .o_selection > a span.o_status', 5,
"should have five status selection widgets");
assert.containsNone(list, '.o_state_selection_cell .o_selection > a span.o_status.o_status_red',
@@ -4589,10 +4582,10 @@ QUnit.module('basic_fields', {
QUnit.module('FavoriteWidget');
- QUnit.test('favorite widget in kanban view', function (assert) {
+ QUnit.test('favorite widget in kanban view', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4614,7 +4607,7 @@ QUnit.module('basic_fields', {
'the label should say "Remove from Favorites"');
// click on favorite
- testUtils.dom.click(kanban.$('.o_field_widget.o_favorite'));
+ await testUtils.dom.click(kanban.$('.o_field_widget.o_favorite'));
assert.containsNone(kanban, '.o_kanban_record .o_field_widget.o_favorite > a i.fa.fa-star',
'should not be favorite');
assert.strictEqual(kanban.$('.o_kanban_record .o_field_widget.o_favorite > a').text(), ' Add to Favorites',
@@ -4623,10 +4616,10 @@ QUnit.module('basic_fields', {
kanban.destroy();
});
- QUnit.test('favorite widget in form view', function (assert) {
+ QUnit.test('favorite widget in form view', async function (assert) {
assert.expect(10);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4646,28 +4639,28 @@ QUnit.module('basic_fields', {
'the label should say "Remove from Favorites"');
// click on favorite
- testUtils.dom.click(form.$('.o_field_widget.o_favorite'));
+ await testUtils.dom.click(form.$('.o_field_widget.o_favorite'));
assert.containsNone(form, '.o_field_widget.o_favorite > a i.fa.fa-star',
'should not be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites',
'the label should say "Add to Favorites"');
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star-o',
'should not be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Add to Favorites',
'the label should say "Add to Favorites"');
// click on favorite
- testUtils.dom.click(form.$('.o_field_widget.o_favorite'));
+ await testUtils.dom.click(form.$('.o_field_widget.o_favorite'));
assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star',
'should be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
'the label should say "Remove from Favorites"');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_field_widget.o_favorite > a i.fa.fa-star',
'should be favorite');
assert.strictEqual(form.$('.o_field_widget.o_favorite > a').text(), ' Remove from Favorites',
@@ -4676,10 +4669,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('favorite widget in editable list view without label', function (assert) {
+ QUnit.test('favorite widget in editable list view without label', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -4692,17 +4685,17 @@ QUnit.module('basic_fields', {
'should be favorite');
// switch to edit mode
- testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector)').first());
+ await testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector)').first());
assert.containsOnce(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star',
'should be favorite');
// click on favorite
- testUtils.dom.click(list.$('.o_data_row:first .o_field_widget.o_favorite'));
+ await testUtils.dom.click(list.$('.o_data_row:first .o_field_widget.o_favorite'));
assert.containsNone(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star',
'should not be favorite');
// save
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.containsOnce(list, '.o_data_row:first .o_field_widget.o_favorite > a i.fa.fa-star-o',
'should not be favorite');
@@ -4712,10 +4705,10 @@ QUnit.module('basic_fields', {
QUnit.module('LabelSelectionWidget');
- QUnit.test('label_selection widget in form view', function (assert) {
+ QUnit.test('label_selection widget in form view', async function (assert) {
assert.expect(12);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4740,7 +4733,7 @@ QUnit.module('basic_fields', {
"the label should say 'Blocked' since this is the label value for that state");
// // switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_widget.badge.badge-warning',
"should have a warning status label since selection is the second, blocked state");
assert.containsNone(form, '.o_field_widget.badge.badge-secondary',
@@ -4751,7 +4744,7 @@ QUnit.module('basic_fields', {
"the label should say 'Blocked' since this is the label value for that state");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_field_widget.badge.badge-warning',
"should have a warning status label since selection is the second, blocked state");
assert.containsNone(form, '.o_field_widget.badge.badge-secondary',
@@ -4764,10 +4757,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('label_selection widget in editable list view', function (assert) {
+ QUnit.test('label_selection widget in editable list view', async function (assert) {
assert.expect(21);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -4794,7 +4787,7 @@ QUnit.module('basic_fields', {
"the success label should read 'Done'");
// switch to edit mode and check the result
- testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector)').first());
+ await testUtils.dom.clickFirst(list.$('tbody td:not(.o_list_record_selector)'));
assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3,
"should have three visible status labels");
assert.containsOnce(list, '.o_field_widget.badge.badge-warning',
@@ -4811,7 +4804,7 @@ QUnit.module('basic_fields', {
"the success label should read 'Done'");
// save and check the result
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('.o_field_widget.badge:not(:empty)').length, 3,
"should have three visible status labels");
assert.containsOnce(list, '.o_field_widget.badge.badge-warning',
@@ -4833,7 +4826,7 @@ QUnit.module('basic_fields', {
QUnit.module('StatInfo');
- QUnit.test('statinfo widget formats decimal precision', function (assert) {
+ QUnit.test('statinfo widget formats decimal precision', async function (assert) {
// sometimes the round method can return numbers such as 14.000001
// when asked to round a number to 2 decimals, as such is the behaviour of floats.
// we check that even in that eventuality, only two decimals are displayed
@@ -4843,7 +4836,7 @@ QUnit.module('basic_fields', {
this.data.partner.records[0].monetary = 9.999999;
this.data.partner.records[0].currency_id = 1;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4867,10 +4860,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('statinfo widget in form view', function (assert) {
+ QUnit.test('statinfo widget in form view', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4897,7 +4890,7 @@ QUnit.module('basic_fields', {
'int_field', "should have 'int_field' as text");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info',
"should still have one stat button");
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
@@ -4906,7 +4899,7 @@ QUnit.module('basic_fields', {
'int_field', "should have 'int_field' as text");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info',
"should have one stat button");
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
@@ -4917,10 +4910,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('statinfo widget in form view with specific label_field', function (assert) {
+ QUnit.test('statinfo widget in form view with specific label_field', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4949,7 +4942,7 @@ QUnit.module('basic_fields', {
'yop', "should have 'yop' as text, since it is the value of field foo");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info',
"should still have one stat button");
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
@@ -4958,7 +4951,7 @@ QUnit.module('basic_fields', {
'yop', "should have 'yop' as text, since it is the value of field foo");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info',
"should have one stat button");
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
@@ -4969,10 +4962,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('statinfo widget in form view with no label', function (assert) {
+ QUnit.test('statinfo widget in form view with no label', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5000,7 +4993,7 @@ QUnit.module('basic_fields', {
'', "should not have any label");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info',
"should still have one stat button");
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
@@ -5009,7 +5002,7 @@ QUnit.module('basic_fields', {
'', "should not have any label");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.oe_stat_button .o_field_widget.o_stat_info',
"should have one stat button");
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').text(),
@@ -5023,10 +5016,10 @@ QUnit.module('basic_fields', {
QUnit.module('PercentPie');
- QUnit.test('percentpie widget in form view with value < 50%', function (assert) {
+ QUnit.test('percentpie widget in form view with value < 50%', async function (assert) {
assert.expect(12);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5050,7 +5043,7 @@ QUnit.module('basic_fields', {
'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie',
"should have a pie chart");
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
@@ -5061,7 +5054,7 @@ QUnit.module('basic_fields', {
'transform: rotate(36deg);'), "right mask should be rotated from 360*(10/100) = 36 degrees");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie',
"should have a pie chart");
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
@@ -5074,10 +5067,10 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('percentpie widget in form view with value > 50%', function (assert) {
+ QUnit.test('percentpie widget in form view with value > 50%', async function (assert) {
assert.expect(12);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5101,7 +5094,7 @@ QUnit.module('basic_fields', {
"right mask should be hidden since the value > 50%");
// switch to edit mode and check the result
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie',
"should have a pie chart");
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
@@ -5112,7 +5105,7 @@ QUnit.module('basic_fields', {
"right mask should be hidden since the value > 50%");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_field_percent_pie.o_field_widget .o_pie',
"should have a pie chart");
assert.strictEqual(form.$('.o_field_percent_pie.o_field_widget .o_pie .o_pie_value').text(),
@@ -5131,10 +5124,10 @@ QUnit.module('basic_fields', {
// applies inside the form view, the widget is unusable. This test can
// be uncommented when we refactor the scss files so that this widget
// stylesheet applies in both form and list view.
- // QUnit.test('percentpie widget in editable list view', function(assert) {
+ // QUnit.test('percentpie widget in editable list view', async function(assert) {
// assert.expect(10);
//
- // var list = createView({
+ // var list = await createView({
// View: ListView,
// model: 'partner',
// data: this.data,
@@ -5177,14 +5170,14 @@ QUnit.module('basic_fields', {
QUnit.module('FieldDomain');
- QUnit.test('The domain editor should not crash the view when given a dynamic filter', function (assert) {
+ QUnit.test('The domain editor should not crash the view when given a dynamic filter', async function (assert) {
//dynamic filters (containing variables, such as uid, parent or today)
//are not handled by the domain editor, but it shouldn't crash the view
assert.expect(1);
this.data.partner.records[0].foo = '[["int_field", "=", uid]]';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5204,12 +5197,12 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('basic domain field usage is ok', function (assert) {
+ QUnit.test('basic domain field usage is ok', async function (assert) {
assert.expect(7);
this.data.partner.records[0].foo = "[]";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5223,7 +5216,7 @@ QUnit.module('basic_fields', {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// As the domain is empty, there should be a button to add the first
// domain part
@@ -5234,14 +5227,14 @@ QUnit.module('basic_fields', {
// Clicking on the button should add the [["id", "=", "1"]] domain, so
// there should be a field selector in the DOM
- testUtils.dom.click($domainAddFirstNodeButton);
+ await testUtils.dom.click($domainAddFirstNodeButton);
var $fieldSelector = $domain.find(".o_field_selector");
assert.equal($fieldSelector.length, 1,
"there should be a field selector");
// Focusing the field selector input should open the field selector
// popover
- $fieldSelector.trigger('focusin');
+ await testUtils.dom.triggerEvents($fieldSelector, ['focusin']);
var $fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover");
assert.ok($fieldSelectorPopover.is(":visible"),
"field selector popover should be visible");
@@ -5264,28 +5257,28 @@ QUnit.module('basic_fields', {
// Clicking on this field should close the popover, then changing the
// associated value should reveal one matched record
- testUtils.dom.click($colorIndex);
- $domain.find(".o_domain_leaf_value_input").val(2).change();
+ await testUtils.dom.click($colorIndex);
+ await testUtils.fields.editAndTrigger($('.o_domain_leaf_value_input'), 2, ['change']);
assert.equal($domain.find(".o_domain_show_selection_button").text().trim().substr(0, 2), "1 ",
"changing color value to 2 should reveal only one record");
// Saving the form view should show a readonly domain containing the
// "color" field
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
$domain = form.$(".o_field_domain");
assert.ok($domain.html().indexOf("Color index") >= 0,
"field selector readonly value should now contain 'Color index'");
form.destroy();
});
- QUnit.test('domain field is correctly reset on every view change', function (assert) {
+ QUnit.test('domain field is correctly reset on every view change', async function (assert) {
assert.expect(7);
this.data.partner.records[0].foo = '[["id","=",1]]';
this.data.partner.fields.bar.type = "char";
this.data.partner.records[0].bar = "product";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5300,7 +5293,7 @@ QUnit.module('basic_fields', {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// As the domain is equal to [["id", "=", 1]] there should be a field
// selector to change this
@@ -5310,7 +5303,7 @@ QUnit.module('basic_fields', {
"there should be a field selector");
// Focusing its input should open the field selector popover
- $fieldSelector.trigger('focusin');
+ await testUtils.dom.triggerEvents($fieldSelector, ['focusin']);
var $fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover");
assert.ok($fieldSelectorPopover.is(":visible"),
"field selector popover should be visible");
@@ -5331,8 +5324,8 @@ QUnit.module('basic_fields', {
"field selector popover should contain 'Product Name' field");
// Now change the value of the "bar" field to "partner_type"
- testUtils.dom.click(form.$("input.o_field_widget"));
- testUtils.fields.editInput(form.$("input.o_field_widget"), "partner_type");
+ await testUtils.dom.click(form.$("input.o_field_widget"));
+ await testUtils.fields.editInput(form.$("input.o_field_widget"), "partner_type");
// Refocusing the field selector input should open the popover again
$fieldSelector = form.$(".o_field_selector");
@@ -5357,7 +5350,7 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('domain field can be reset with a new domain (from onchange)', function (assert) {
+ QUnit.test('domain field can be reset with a new domain (from onchange)', async function (assert) {
assert.expect(2);
this.data.partner.records[0].foo = '[]';
@@ -5367,7 +5360,7 @@ QUnit.module('basic_fields', {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5386,7 +5379,7 @@ QUnit.module('basic_fields', {
"the domain being empty, there should be 5 records");
// update display_name to trigger the onchange and reset foo
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value');
assert.equal(form.$('.o_domain_show_selection_button').text().trim(), '1 record(s)',
"the domain has changed, there should be only 1 record");
@@ -5394,14 +5387,14 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('domain field: handle false domain as []', function (assert) {
+ QUnit.test('domain field: handle false domain as []', async function (assert) {
assert.expect(3);
this.data.partner.records[0].foo = false;
this.data.partner.fields.bar.type = "char";
this.data.partner.records[0].bar = "product";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5426,7 +5419,7 @@ QUnit.module('basic_fields', {
assert.strictEqual(form.$('.o_field_widget[name=foo]:not(.o_field_empty)').length, 1,
"there should be a domain field, not considered empty");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $warning = form.$('.o_field_widget[name=foo] .text-warning');
assert.strictEqual($warning.length, 0, "should not display that the domain is invalid");
@@ -5434,12 +5427,12 @@ QUnit.module('basic_fields', {
form.destroy();
});
- QUnit.test('basic domain field: show the selection', function (assert) {
+ QUnit.test('basic domain field: show the selection', async function (assert) {
assert.expect(2);
this.data.partner.records[0].foo = "[]";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5462,21 +5455,21 @@ QUnit.module('basic_fields', {
"selection should contain 2 records");
// open the selection
- testUtils.dom.click(form.$(".o_domain_show_selection_button"));
+ await testUtils.dom.click(form.$(".o_domain_show_selection_button"));
assert.strictEqual($('.modal .o_list_view .o_data_row').length, 2,
"should have open a list view with 2 records in a dialog");
// click on a record -> should not open the record
// we don't actually check that it doesn't open the record because even
// if it tries to, it will crash as we don't define an arch in this test
- testUtils.dom.click($('.modal .o_list_view .o_data_row:first .o_data_cell'));
+ await testUtils.dom.click($('.modal .o_list_view .o_data_row:first .o_data_cell'));
form.destroy();
});
QUnit.module('FieldProgressBar');
- QUnit.test('Field ProgressBar: max_value should update', function (assert) {
+ QUnit.test('Field ProgressBar: max_value should update', async function (assert) {
assert.expect(2);
this.data.partner.records = this.data.partner.records.slice(0,1);
@@ -5489,7 +5482,7 @@ QUnit.module('basic_fields', {
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5508,7 +5501,7 @@ QUnit.module('basic_fields', {
'The initial value of the progress bar should be correct');
// trigger the onchange
- form.$('.o_input[name=display_name]').val('new name').trigger('input');
+ await testUtils.fields.editInput(form.$('.o_input[name=display_name]'), 'new name');
assert.strictEqual(form.$('.o_progressbar_value').text(), '999 / 5',
'The value of the progress bar should be correct after the update');
diff --git a/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js
index 949af90fafe..e20ad604c98 100644
--- a/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js
+++ b/addons/web/static/tests/fields/relational_fields/field_many2many_tests.js
@@ -111,11 +111,11 @@ QUnit.module('fields', {}, function () {
}]
},
};
- }
+ },
}, function () {
QUnit.module('FieldMany2Many');
- QUnit.test('many2many kanban: edition', function (assert) {
+ QUnit.test('many2many kanban: edition', async function (assert) {
assert.expect(32);
this.data.partner.records[0].timmy = [12, 14];
@@ -123,7 +123,7 @@ QUnit.module('fields', {}, function () {
this.data.partner_type.records.push({ id: 18, display_name: "yellow", color: 4 });
this.data.partner_type.records.push({ id: 21, display_name: "blue", color: 1 });
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -187,7 +187,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_many2many .o-kanban-button-new').length,
'"Add" button should not be visible in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2,
'should contain 2 records');
@@ -201,20 +201,20 @@ QUnit.module('fields', {}, function () {
'Create button should have "Add" label');
// edit existing subrecord
- testUtils.dom.click(form.$('.oe_kanban_global_click:first()'));
+ await testUtils.dom.click(form.$('.oe_kanban_global_click:first()'));
- testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_kanban_record:first() span').text(), 'new name',
'value of subrecord should have been updated');
// add subrecords
// -> single select
- testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new'));
+ await testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new'));
assert.ok($('.modal .o_list_view').length, "should have opened a list view in a modal");
assert.strictEqual($('.modal .o_list_view tbody .o_list_record_selector').length, 3,
"list view should contain 3 records");
- testUtils.dom.click($('.modal .o_list_view tbody tr:contains(red)'));
+ await testUtils.dom.click($('.modal .o_list_view tbody tr:contains(red)'));
assert.ok(!$('.modal .o_list_view').length, "should have closed the modal");
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 3,
'kanban should now contain 3 records');
@@ -222,23 +222,23 @@ QUnit.module('fields', {}, function () {
'record "red" should be in the kanban');
// -> multiple select
- testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new'));
+ await testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new'));
assert.ok($('.modal .o_select_button').prop('disabled'), "select button should be disabled");
assert.strictEqual($('.modal .o_list_view tbody .o_list_record_selector').length, 2,
"list view should contain 2 records");
- testUtils.dom.click($('.modal .o_list_view thead .o_list_record_selector input'));
- testUtils.dom.click($('.modal .o_select_button'));
+ await testUtils.dom.click($('.modal .o_list_view thead .o_list_record_selector input'));
+ await testUtils.dom.click($('.modal .o_select_button'));
assert.ok(!$('.modal .o_select_button').prop('disabled'), "select button should be enabled");
assert.ok(!$('.modal .o_list_view').length, "should have closed the modal");
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 5,
'kanban should now contain 5 records');
// -> created record
- testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new'));
- testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)'));
+ await testUtils.dom.click(form.$('.o_field_many2many .o-kanban-button-new'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)'));
assert.ok($('.modal .o_form_view.o_form_editable').length,
"should have opened a form view in edit mode, in a modal");
- testUtils.fields.editInput($('.modal .o_form_view input'), 'A new type');
- testUtils.dom.click($('.modal:nth(1) footer .btn-primary:first()'));
+ await testUtils.fields.editInput($('.modal .o_form_view input'), 'A new type');
+ await testUtils.dom.click($('.modal:nth(1) footer .btn-primary:first()'));
assert.ok(!$('.modal').length, "should have closed both modals");
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 6,
'kanban should now contain 6 records');
@@ -246,32 +246,32 @@ QUnit.module('fields', {}, function () {
'the newly created type should be in the kanban');
// delete subrecords
- testUtils.dom.click(form.$('.o_kanban_record:contains(silver)'));
+ await testUtils.dom.click(form.$('.o_kanban_record:contains(silver)'));
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'There should be a modal having Remove Button');
- testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
+ await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 5,
'should contain 5 records');
assert.ok(!form.$('.o_kanban_record:contains(silver)').length,
'the removed record should not be in kanban anymore');
- testUtils.dom.click(form.$('.o_kanban_record:contains(blue) .delete_icon'));
+ await testUtils.dom.click(form.$('.o_kanban_record:contains(blue) .delete_icon'));
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4,
'should contain 4 records');
assert.ok(!form.$('.o_kanban_record:contains(blue)').length,
'the removed record should not be in kanban anymore');
// save the record
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('many2many kanban(editable): properly handle create_text node option', function (assert) {
+ QUnit.test('many2many kanban(editable): properly handle create_text node option', async function (assert) {
assert.expect(1);
this.data.partner.records[0].timmy = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -291,19 +291,19 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_many2many[name="timmy"] .o-kanban-button-new').text().trim(),
"Add timmy", "In M2M Kanban, Add button should have 'Add timmy' label");
form.destroy();
});
- QUnit.test('many2many kanban: create action disabled', function (assert) {
+ QUnit.test('many2many kanban: create action disabled', async function (assert) {
assert.expect(4);
this.data.partner.records[0].timmy = [12, 14];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -335,27 +335,27 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o-kanban-button-new').length,
'"Add" button should not be available in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('.o-kanban-button-new').length,
'"Add" button should be available in edit');
assert.ok(form.$('.o_kanban_view .delete_icon').length,
'delete icon should be visible in edit');
- testUtils.dom.click(form.$('.o-kanban-button-new'));
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
assert.strictEqual($('.modal .modal-footer .btn-primary').length, 1, // only button 'Select'
'"Create" button should not be available in the modal');
form.destroy();
});
- QUnit.test('many2many list (non editable): edition', function (assert) {
+ QUnit.test('many2many list (non editable): edition', async function (assert) {
assert.expect(27);
this.data.partner.records[0].timmy = [12, 14];
this.data.partner_type.records.push({ id: 15, display_name: "bronze", color: 6 });
this.data.partner_type.fields.float_field = { string: 'Float', type: 'float' };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -392,7 +392,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" should not be visible in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 records');
@@ -404,34 +404,34 @@ QUnit.module('fields', {}, function () {
'"Add an item" should be visible in edit');
// edit existing subrecord
- testUtils.dom.click(form.$('.o_list_view tbody tr:first()'));
+ await testUtils.dom.click(form.$('.o_list_view tbody tr:first()'));
- testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name',
'value of subrecord should have been updated');
// add new subrecords
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_list_view').length, 1,
"a modal should be open");
assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1,
"the list should contain one row");
- testUtils.dom.click($('.modal .o_list_view .o_data_row'));
+ await testUtils.dom.click($('.modal .o_list_view .o_data_row'));
assert.strictEqual($('.modal .o_list_view').length, 0,
"the modal should be closed");
assert.containsN(form, '.o_list_view td.o_list_number', 3,
'should contain 3 subrecords');
// remove subrecords
- testUtils.dom.click(form.$('.o_list_record_remove:nth(1)'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:nth(1)'));
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 subrecords');
assert.strictEqual(form.$('.o_list_view .o_data_row td:first').text(), 'new name',
'the updated row still has the correct values');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 subrecords');
assert.strictEqual(form.$('.o_list_view .o_data_row td:first').text(),
@@ -453,13 +453,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2many list (editable): edition', function (assert) {
+ QUnit.test('many2many list (editable): edition', async function (assert) {
assert.expect(31);
this.data.partner.records[0].timmy = [12, 14];
this.data.partner_type.records.push({ id: 15, display_name: "bronze", color: 6 });
this.data.partner_type.fields.float_field = { string: 'Float', type: 'float' };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -494,7 +494,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" should not be visible in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 records');
@@ -508,17 +508,17 @@ QUnit.module('fields', {}, function () {
'"Add an item" should not visible in edit');
// edit existing subrecord
- testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
+ await testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
assert.ok(!$('.modal').length,
'in edit, clicking on a subrecord should not open a dialog');
assert.hasClass(form.$('.o_list_view tbody tr:first()'),'o_selected_row',
'first row should be in edition');
- testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name');
+ await testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name');
assert.hasClass(form.$('.o_list_view .o_data_row:first'),'o_selected_row',
'first row should still be in edition');
assert.strictEqual(form.$('.o_list_view input[name=display_name]').get(0),
document.activeElement, 'edited field should still have the focus');
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$el);
assert.doesNotHaveClass(form.$('.o_list_view tbody tr:first'), 'o_selected_row',
'first row should not be in edition anymore');
assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name',
@@ -526,34 +526,32 @@ QUnit.module('fields', {}, function () {
assert.verifySteps(['read', 'read']);
// add new subrecords
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_list_view').length, 1,
"a modal should be open");
assert.strictEqual($('.modal .o_list_view .o_data_row').length, 1,
"the list should contain one row");
- testUtils.dom.click($('.modal .o_list_view .o_data_row'));
+ await testUtils.dom.click($('.modal .o_list_view .o_data_row'));
assert.strictEqual($('.modal .o_list_view').length, 0,
"the modal should be closed");
assert.containsN(form, '.o_list_view td.o_list_number', 3,
'should contain 3 subrecords');
// remove subrecords
- testUtils.dom.click(form.$('.o_list_record_remove:nth(1)'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:nth(1)'));
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 subrecord');
assert.strictEqual(form.$('.o_list_view tbody .o_data_row td:first').text(),
'new name', 'the updated row still has the correct values');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 subrecords');
assert.strictEqual(form.$('.o_list_view .o_data_row td:first').text(),
'new name', 'the updated row still has the correct values');
assert.verifySteps([
- 'read', // main record
- 'read', // relational field
'search_read', // list view in dialog
'read', // relational field (updated)
'write', // save main record
@@ -564,12 +562,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2many: create & delete attributes', function (assert) {
+ QUnit.test('many2many: create & delete attributes', async function (assert) {
assert.expect(4);
this.data.partner.records[0].timmy = [12, 14];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -583,14 +581,14 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_x2many_list_row_add', "should have the 'Add an item' link");
assert.containsN(form, '.o_list_record_remove', 2, "should have the 'Add an item' link");
form.destroy();
- form = createView({
+ form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -604,7 +602,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, '.o_field_x2many_list_row_add', "should not have the 'Add an item' link");
assert.containsNone(form, '.o_list_record_remove', "should not have the 'Add an item' link");
@@ -612,9 +610,9 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2many list: create action disabled', function (assert) {
+ QUnit.test('many2many list: create action disabled', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -631,7 +629,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" link should not be available in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" link should not be available in edit either');
@@ -639,13 +637,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2many list: list of id as default value', function (assert) {
+ QUnit.test('many2many list: list of id as default value', async function (assert) {
assert.expect(1);
this.data.partner.fields.turtles.default = [2, 3];
this.data.partner.fields.turtles.type = "many2many";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -664,13 +662,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2many checkboxes with default values', function (assert) {
+ QUnit.test('many2many checkboxes with default values', async function (assert) {
assert.expect(7);
this.data.partner.fields.turtles.default = [3];
this.data.partner.fields.turtles.type = "many2many";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -694,10 +692,10 @@ QUnit.module('fields', {}, function () {
assert.ok(form.$('.o_form_view .custom-checkbox input').eq(2).prop('checked'),
"third checkbox should be checked");
- testUtils.dom.click(form.$('.o_form_view .custom-checkbox input:checked'));
- testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first());
- testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first());
- testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first());
+ await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input:checked'));
+ await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first());
+ await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first());
+ await testUtils.dom.click(form.$('.o_form_view .custom-checkbox input').first());
assert.ok(form.$('.o_form_view .custom-checkbox input').eq(0).prop('checked'),
"first checkbox should be checked");
@@ -706,12 +704,12 @@ QUnit.module('fields', {}, function () {
assert.notOk(form.$('.o_form_view .custom-checkbox input').eq(2).prop('checked'),
"third checkbox should not be checked");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('many2many list with x2many: add a record', function (assert) {
+ QUnit.test('many2many list with x2many: add a record', async function (assert) {
assert.expect(18);
this.data.partner_type.fields.m2m = {
@@ -720,7 +718,7 @@ QUnit.module('fields', {}, function () {
this.data.partner_type.records[0].m2m = [1, 2];
this.data.partner_type.records[1].m2m = [2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -742,7 +740,7 @@ QUnit.module('fields', {}, function () {
assert.step(_.last(route.split('/')) + ' on ' + args.model);
}
if (args.model === 'turtle') {
- assert.step(args.args[0]); // the read ids
+ assert.step(JSON.stringify(args.args[0])); // the read ids
}
return this._super.apply(this, arguments);
},
@@ -751,16 +749,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal .o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_data_row:first'));
assert.containsOnce(form, '.o_data_row',
"the record should have been added to the relation");
assert.strictEqual(form.$('.o_data_row:first .o_badge_text').text(), 'leonardodonatello',
"inner m2m should have been fetched and correctly displayed");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal .o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_data_row:first'));
assert.containsN(form, '.o_data_row', 2,
"the second record should have been added to the relation");
@@ -771,27 +769,27 @@ QUnit.module('fields', {}, function () {
'read on partner',
'search_read on partner_type',
'read on turtle',
- [1, 2, 3],
+ '[1,2,3]',
'read on partner_type',
'read on turtle',
- [1, 2],
+ '[1,2]',
'search_read on partner_type',
'read on turtle',
- [2, 3],
+ '[2,3]',
'read on partner_type',
'read on turtle',
- [2, 3],
+ '[2,3]',
]);
form.destroy();
});
- QUnit.test('many2many with a domain', function (assert) {
+ QUnit.test('many2many with a domain', async function (assert) {
// The domain specified on the field should not be replaced by the potential
// domain the user writes in the dialog, they should rather be concatenated
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -812,24 +810,24 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_data_row').length, 1,
"should contain only one row (gold)");
- $('.modal .o_searchview_input').trigger({ type: 'keypress', which: 115 }); // s
- $('.modal .o_searchview_input').trigger({ type: 'keydown', which: 13 }); // enter
+ await testUtils.fields.triggerKey('press', $('.modal .o_searchview_input'), 's');
+ await testUtils.fields.triggerKeydown($('.modal .o_searchview_input'), 'enter');
assert.strictEqual($('.modal .o_data_row').length, 0, "should contain no row");
form.destroy();
});
- QUnit.test('many2many list with onchange and edition of a record', function (assert) {
+ QUnit.test('many2many list with onchange and edition of a record', async function (assert) {
assert.expect(8);
this.data.partner.fields.turtles.type = "many2many";
this.data.partner.onchanges.turtles = function () { };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -850,14 +848,14 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('td.o_data_cell:first'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('td.o_data_cell:first'));
- testUtils.dom.click($('.modal-body input[type="checkbox"]'));
- testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
+ await testUtils.dom.click($('.modal-body input[type="checkbox"]'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
// there is nothing left to save -> should not do a 'write' RPC
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps([
'read', // read initial record (on partner)
@@ -872,10 +870,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange with 40+ commands for a many2many', function (assert) {
+ QUnit.test('onchange with 40+ commands for a many2many', async function (assert) {
// this test ensures that the basic_model correctly handles more LINK_TO
// commands than the limit of the dataPoint (40 for x2many kanban)
- assert.expect(23);
+ assert.expect(24);
// create a lot of partner_types that will be linked by the onchange
var commands = [[5]];
@@ -890,7 +888,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -925,44 +923,45 @@ QUnit.module('fields', {}, function () {
assert.verifySteps(['read']);
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange');
- assert.verifySteps(['read', 'onchange', 'read']);
+ assert.verifySteps(['onchange', 'read']);
assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(),
'1-40 / 45', "pager should be correct");
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40,
'there should be 40 records displayed on page 1');
- testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next'));
- assert.verifySteps(['read', 'onchange', 'read', 'read']);
+ await testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next'));
+ assert.verifySteps(['read']);
assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(),
'41-45 / 45', "pager should be correct");
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5,
'there should be 5 records displayed on page 2');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(),
'1-40 / 45', "pager should be correct");
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40,
'there should be 40 records displayed on page 1');
- testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next'));
assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(),
'41-45 / 45', "pager should be correct");
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5,
'there should be 5 records displayed on page 2');
- testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=timmy] .o_pager_next'));
assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(),
'1-40 / 45', "pager should be correct");
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40,
'there should be 40 records displayed on page 1');
+ assert.verifySteps(['write', 'read', 'read', 'read']);
form.destroy();
});
- QUnit.test('default_get, onchange, onchange on m2m', function (assert) {
+ QUnit.test('default_get, onchange, onchange on m2m', async function (assert) {
assert.expect(1);
this.data.partner.onchanges.int_field = function (obj) {
@@ -978,7 +977,7 @@ QUnit.module('fields', {}, function () {
];
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -994,15 +993,15 @@ QUnit.module('fields', {}, function () {
'</form>',
});
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
form.destroy();
});
- QUnit.test('widget many2many_tags', function (assert) {
+ QUnit.test('widget many2many_tags', async function (assert) {
assert.expect(1);
this.data.turtle.records[0].partner_ids = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'turtle',
data: this.data,
@@ -1023,7 +1022,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2many list add *many* records, remove, re-add', function (assert) {
+ QUnit.test('many2many list add *many* records, remove, re-add', async function (assert) {
assert.expect(5);
this.data.partner.fields.timmy.domain = [['color', '=', 2]];
@@ -1035,7 +1034,7 @@ QUnit.module('fields', {}, function () {
this.data.partner_type.records.push(new_record_partner_type);
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1055,52 +1054,52 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
assert.deepEqual(args.args[0], [1], "should call get_formview_id with correct id");
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
});
// First round: add 51 records in batch
- testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
var $modal = $('.modal-lg');
assert.equal($modal.length, 1,
'There should be one modal');
- testUtils.dom.click($modal.find('thead input[type=checkbox]'));
+ await testUtils.dom.click($modal.find('thead input[type=checkbox]'));
- testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button'));
+ await testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button'));
var m2m_records = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_data_cell:not(.o_many2many_tags_cell)');
assert.equal(m2m_records.length, 51,
'We should have added all the records present in the search view to the m2m field'); // the 50 in batch + 'gold'
- testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_save'));
+ await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_save'));
// Secound round: remove one record
- testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit'));
+ await testUtils.dom.click(form.$buttons.find('.btn.btn-primary.o_form_button_edit'));
var trash_buttons = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_list_record_remove');
- testUtils.dom.click(trash_buttons.first());
+ await testUtils.dom.click(trash_buttons.first());
var pager_limit = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_pager_limit');
assert.equal(pager_limit.text(), '50',
'We should have 50 records in the m2m field');
// Third round: re-add 1 records
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
$modal = $('.modal-lg');
assert.equal($modal.length, 1,
'There should be one modal');
- testUtils.dom.click($modal.find('thead input[type=checkbox]'));
+ await testUtils.dom.click($modal.find('thead input[type=checkbox]'));
- testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button'));
+ await testUtils.dom.click($modal.find('.btn.btn-primary.o_select_button'));
pager_limit = form.$('.o_field_many2many.o_field_widget.o_field_x2many.o_field_x2many_list .o_pager_limit');
assert.equal(pager_limit.text(), '51',
diff --git a/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js b/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js
index 04b58b017ba..4f2a3d03bed 100644
--- a/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js
+++ b/addons/web/static/tests/fields/relational_fields/field_many2one_tests.js
@@ -150,13 +150,13 @@ QUnit.module('fields', {}, function () {
}]
},
};
- }
+ },
}, function () {
QUnit.module('FieldMany2One');
- QUnit.test('many2ones in form views', function (assert) {
+ QUnit.test('many2ones in form views', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -174,7 +174,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'get_formview_action') {
assert.deepEqual(args.args[0], [4], "should call get_formview_action with correct id");
- return $.when({
+ return Promise.resolve({
res_id: 17,
type: 'ir.actions.act_window',
target: 'current',
@@ -183,7 +183,7 @@ QUnit.module('fields', {}, function () {
}
if (args.method === 'get_formview_id') {
assert.deepEqual(args.args[0], [4], "should call get_formview_id with correct id");
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
@@ -196,23 +196,22 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('a.o_form_uri:contains(aaa)').length, 1,
"should contain a link");
- testUtils.dom.click(form.$('a.o_form_uri'));
+ await testUtils.dom.click(form.$('a.o_form_uri'));
- testUtils.form.clickEdit(form);
-
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_external_button'));
assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: custom label',
"dialog title should display the custom string label");
- // TODO: test that we can edit the record in the dialog, and that the value is correctly
- // updated on close
+ // TODO: test that we can edit the record in the dialog, and that
+ // the value is correctly updated on close
form.destroy();
});
- QUnit.test('editing a many2one, but not changing anything', function (assert) {
+ QUnit.test('editing a many2one, but not changing anything', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -228,7 +227,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
assert.deepEqual(args.args[0], [4], "should call get_formview_id with correct id");
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
@@ -237,16 +236,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// click on the external button (should do an RPC)
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
// save and close modal
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
// save form
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// click next on pager
- testUtils.dom.click(form.pager.$('.o_pager_next'));
+ await testUtils.dom.click(form.pager.$('.o_pager_next'));
// this checks that the view did not ask for confirmation that the
// record is dirty
@@ -255,13 +254,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('context in many2one and default get', function (assert) {
+ QUnit.test('context in many2one and default get', async function (assert) {
assert.expect(1);
this.data.partner.fields.int_field.default = 14;
this.data.partner.fields.trululu.default = 2;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -280,9 +279,9 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editing a many2one (with form view opened with external button)', function (assert) {
+ QUnit.test('editing a many2one (with form view opened with external button)', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -297,7 +296,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
@@ -306,19 +305,19 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// click on the external button (should do an RPC)
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
- testUtils.fields.editInput($('.modal input[name="foo"]'), 'brandon');
+ await testUtils.fields.editInput($('.modal input[name="foo"]'), 'brandon');
// save and close modal
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
// save form
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// click next on pager
- testUtils.dom.click(form.pager.$('.o_pager_next'));
+ await testUtils.dom.click(form.pager.$('.o_pager_next'));
// this checks that the view did not ask for confirmation that the
// record is dirty
@@ -327,9 +326,9 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2ones in form views with show_adress', function (assert) {
+ QUnit.test('many2ones in form views with show_adress', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -359,7 +358,7 @@ QUnit.module('fields', {}, function () {
assert.strictEqual($('a.o_form_uri').html(), 'aaa<br>Street<br>City ZIP',
"input should have a multi-line content in readonly due to show_address");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'button.o_external_button:visible',
"should have an open record button");
@@ -374,12 +373,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('show_address works in a view embedded in a view of another type', function (assert) {
+ QUnit.test('show_address works in a view embedded in a view of another type', async function (assert) {
assert.expect(1);
this.data.turtle.records[1].turtle_trululu = 2;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -410,19 +409,19 @@ QUnit.module('fields', {}, function () {
},
});
// click the turtle field, opens a modal with the turtle form view
- testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell'));
+ await testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell'));
assert.strictEqual($('[name="turtle_trululu"]').text(), "second recordrue morgueparis 75013",
"The partner's address should be displayed");
form.destroy();
});
- QUnit.test('many2one data is reloaded if there is a context to take into account', function (assert) {
+ QUnit.test('many2one data is reloaded if there is a context to take into account', async function (assert) {
assert.expect(1);
this.data.turtle.records[1].turtle_trululu = 2;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -454,14 +453,14 @@ QUnit.module('fields', {}, function () {
},
});
// click the turtle field, opens a modal with the turtle form view
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal [name=turtle_trululu]').text(), "second recordrue morgueparis 75013",
"The partner's address should be displayed");
form.destroy();
});
- QUnit.test('many2ones in form views with search more', function (assert) {
+ QUnit.test('many2ones in form views with search more', async function (assert) {
assert.expect(3);
this.data.partner.records.push({
id: 5,
@@ -483,7 +482,7 @@ QUnit.module('fields', {}, function () {
display_name: "Partner 9",
});
this.data.partner.fields.datetime.searchable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -501,29 +500,29 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.fields.many2one.clickOpenDropdown('trululu');
- testUtils.fields.many2one.clickItem('trululu', 'Search');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickItem('trululu', 'Search');
assert.strictEqual($('tr.o_data_row').length, 9, "should display 9 records");
- testUtils.dom.click($('button:contains(Filters)'));
- testUtils.dom.click($('.o_add_custom_filter:visible'));
+ await testUtils.dom.click($('button:contains(Filters)'));
+ await testUtils.dom.click($('.o_add_custom_filter:visible'));
assert.strictEqual($('.o_filter_condition select.o_searchview_extended_prop_field').val(), 'datetime',
"datetime field should be selected");
- testUtils.dom.click($('.o_apply_filter'));
+ await testUtils.dom.click($('.o_apply_filter'));
assert.strictEqual($('tr.o_data_row').length, 0, "should display 0 records");
form.destroy();
});
- QUnit.test('onchanges on many2ones trigger when editing record in form view', function (assert) {
+ QUnit.test('onchanges on many2ones trigger when editing record in form view', async function (assert) {
assert.expect(10);
this.data.partner.onchanges.user_id = function () { };
this.data.user.fields.other_field = { string: "Other Field", type: "char" };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -541,7 +540,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
assert.step(args.method);
if (args.method === 'get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
if (args.method === 'onchange') {
assert.strictEqual(args.args[1].user_id, 17,
@@ -552,25 +551,25 @@ QUnit.module('fields', {}, function () {
});
// open the many2one in form view and change something
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_external_button'));
- testUtils.fields.editInput($('.modal-body input[name="other_field"]'), 'wood');
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.fields.editInput($('.modal-body input[name="other_field"]'), 'wood');
// save the modal and make sure an onchange is triggered
- testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']);
// save the main record, and check that no extra rpcs are done (record
// is not dirty, only a related record was modified)
- testUtils.form.clickSave(form);
- assert.verifySteps(['read', 'get_formview_id', 'load_views', 'read', 'write', 'onchange', 'read']);
+ await testUtils.form.clickSave(form);
+ assert.verifySteps([]);
form.destroy();
});
- QUnit.test('many2one fields with option "no_open"', function (assert) {
+ QUnit.test('many2one fields with option "no_open"', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -588,13 +587,13 @@ QUnit.module('fields', {}, function () {
"should be displayed inside a span (sanity check)");
assert.containsNone(form, 'span.o_form_uri', "should not have an anchor");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, '.o_field_widget[name=trululu] .o_external_button', "should not have the button to open the record");
form.destroy();
});
- QUnit.test('many2one in edit mode', function (assert) {
+ QUnit.test('many2one in edit mode', async function (assert) {
assert.expect(16);
// create 10 partners to have the 'Search More' option in the autocomplete dropdown
@@ -603,7 +602,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records.push({ id: id, display_name: "Partner " + id });
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -635,11 +634,11 @@ QUnit.module('fields', {}, function () {
event.data.callback({ user_context: {} });
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
- testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
assert.ok($dropdown.is(':visible'),
'clicking on the m2o input should open the dropdown if it is not open yet');
assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 7,
@@ -647,51 +646,50 @@ QUnit.module('fields', {}, function () {
assert.strictEqual($dropdown.find('li.o_m2o_dropdown_option').length, 2,
'autocomplete should contain "Search More" and Create and Edit..."');
- testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
assert.ok(!$dropdown.is(':visible'),
'clicking on the m2o input should close the dropdown if it is open');
// change the value of the m2o with a suggestion of the dropdown
- testUtils.fields.many2one.clickOpenDropdown('trululu');
- testUtils.fields.many2one.clickHighlightedItem('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickHighlightedItem('trululu');
assert.ok(!$dropdown.is(':visible'), 'clicking on a value should close the dropdown');
assert.strictEqual(form.$('.o_field_many2one input').val(), 'first record',
'value of the m2o should have been correctly updated');
// change the value of the m2o with a record in the 'Search More' modal
- testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
// click on 'Search More' (mouseenter required by ui-autocomplete)
- testUtils.fields.many2one.clickItem('trululu', 'Search');
+ await testUtils.fields.many2one.clickItem('trululu', 'Search');
assert.ok($('.modal .o_list_view').length, "should have opened a list view in a modal");
assert.ok(!$('.modal .o_list_view .o_list_record_selector').length,
"there should be no record selector in the list view");
assert.ok(!$('.modal .modal-footer .o_select_button').length,
"there should be no 'Select' button in the footer");
assert.ok($('.modal tbody tr').length > 10, "list should contain more than 10 records");
- // filter the list using the searchview
- $('.modal .o_searchview_input').trigger({ type: 'keypress', which: 80 }); // P
- $('.modal .o_searchview_input').trigger({ type: 'keydown', which: 13 }); // enter
+ await testUtils.fields.triggerKey('press', $('.modal .o_searchview_input'), 'P'),
+ await testUtils.fields.triggerKeydown($('.modal .o_searchview_input'), 'enter');
assert.strictEqual($('.modal tbody tr').length, 10,
"list should be restricted to records containing a P (10 records)");
// choose a record
- testUtils.dom.click($('.modal tbody tr:contains(Partner 20)'));
+ await testUtils.dom.click($('.modal tbody tr:contains(Partner 20)'));
assert.ok(!$('.modal').length, "should have closed the modal");
assert.ok(!$dropdown.is(':visible'), 'should have closed the dropdown');
assert.strictEqual(form.$('.o_field_many2one input').val(), 'Partner 20',
'value of the m2o should have been correctly updated');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('a.o_form_uri').text(), 'Partner 20',
"should display correct value after save");
form.destroy();
});
- QUnit.test('many2one in non edit mode', function (assert) {
+ QUnit.test('many2one in non edit mode', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -707,9 +705,9 @@ QUnit.module('fields', {}, function () {
"href should contain id and model");
// Remove value from many2one and then save, there should not have href with id and model on m2o anchor
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
form.$('.o_field_many2one input').val('').trigger('keyup').trigger('focusout');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.hasAttrValue(form.$('a.o_form_uri'), 'href', "#",
"href should have #");
@@ -717,14 +715,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2one searches with correct value', function (assert) {
- var done = assert.async();
+ QUnit.test('many2one searches with correct value', async function (assert) {
assert.expect(6);
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -748,31 +745,27 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_field_many2one input').val(), 'aaa',
"should be initially set to 'aaa'");
- testUtils.dom.click(form.$('.o_field_many2one input'));
+ await testUtils.dom.click(form.$('.o_field_many2one input'));
// unset the many2one -> should search again with ''
form.$('.o_field_many2one input').val('').trigger('keydown');
- concurrency.delay(0).then(function () {
- // write 'p' -> should search with 'p'
- form.$('.o_field_many2one input').val('p').trigger('keydown').trigger('keyup');
+ await testUtils.nextTick();
+ form.$('.o_field_many2one input').val('p').trigger('keydown').trigger('keyup');
+ await testUtils.nextTick();
- return concurrency.delay(0);
- }).then(function () {
- // close and re-open the dropdown -> should search with 'p' again
- testUtils.dom.click(form.$('.o_field_many2one input'));
- testUtils.dom.click(form.$('.o_field_many2one input'));
+ // close and re-open the dropdown -> should search with 'p' again
+ await testUtils.dom.click(form.$('.o_field_many2one input'));
+ await testUtils.dom.click(form.$('.o_field_many2one input'));
- assert.verifySteps(['search: ', 'search: ', 'search: p', 'search: p']);
+ assert.verifySteps(['search: ', 'search: ', 'search: p', 'search: p']);
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- form.destroy();
- done();
- });
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
+ form.destroy();
});
- QUnit.test('many2one field with option always_reload', function (assert) {
+ QUnit.test('many2one field with option always_reload', async function (assert) {
assert.expect(4);
var count = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -783,7 +776,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'name_get') {
count++;
- return $.when([[1, "first record\nand some address"]]);
+ return Promise.resolve([[1, "first record\nand some address"]]);
}
return this._super(route, args);
},
@@ -793,22 +786,22 @@ QUnit.module('fields', {}, function () {
assert.ok(form.$('a:contains(and some address)').length,
"should display additional result");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=trululu] input').val(), "first record",
"actual field value should be displayed to be edited");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.ok(form.$('a:contains(and some address)').length,
"should still display additional result");
form.destroy();
});
- QUnit.test('many2one field and list navigation', function (assert) {
+ QUnit.test('many2one field and list navigation', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -816,14 +809,11 @@ QUnit.module('fields', {}, function () {
});
// edit first input, to trigger autocomplete
- testUtils.dom.click(list.$('.o_data_row .o_data_cell').first());
- testUtils.fields.editInput(list.$('.o_data_cell input'), '');
+ await testUtils.dom.click(list.$('.o_data_row .o_data_cell').first());
+ await testUtils.fields.editInput(list.$('.o_data_cell input'), '');
// press keydown, to select first choice
- list.$('.o_data_cell input').focus().trigger($.Event('keydown', {
- which: $.ui.keyCode.DOWN,
- keyCode: $.ui.keyCode.DOWN,
- }));
+ await testUtils.fields.triggerKeydown(list.$('.o_data_cell input').focus(), 'down');
// we now check that the dropdown is open (and that the focus did not go
// to the next line)
@@ -839,7 +829,6 @@ QUnit.module('fields', {}, function () {
QUnit.test('standalone many2one field', async function (assert) {
assert.expect(4);
- var done = assert.async();
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
@@ -851,54 +840,53 @@ QUnit.module('fields', {}, function () {
Model: BasicModel,
data: this.data,
});
-
+ var record;
model.makeRecord('coucou', [{
name: 'partner_id',
relation: 'partner',
type: 'many2one',
value: [1, 'first partner'],
}]).then(function (recordID) {
- var record = model.get(recordID);
- // create a new widget that uses the StandaloneFieldManagerMixin
- var StandaloneWidget = Widget.extend(StandaloneFieldManagerMixin, {
- init: function (parent) {
- this._super.apply(this, arguments);
- StandaloneFieldManagerMixin.init.call(this, parent);
- },
- });
- var parent = new StandaloneWidget(model);
- testUtils.mock.addMockEnvironment(parent, {
- data: self.data,
- mockRPC: function (route, args) {
- assert.step(args.method);
- return this._super.apply(this, arguments);
- },
- });
+ record = model.get(recordID);
+ });
+ await testUtils.nextTick();
+ // create a new widget that uses the StandaloneFieldManagerMixin
+ var StandaloneWidget = Widget.extend(StandaloneFieldManagerMixin, {
+ init: function (parent) {
+ this._super.apply(this, arguments);
+ StandaloneFieldManagerMixin.init.call(this, parent);
+ },
+ });
+ var parent = new StandaloneWidget(model);
+ testUtils.mock.addMockEnvironment(parent, {
+ data: self.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method);
+ return this._super.apply(this, arguments);
+ },
+ });
- var relField = new relationalFields.FieldMany2One(parent, 'partner_id', record, {
- mode: 'edit',
- noOpen: true,
- });
+ var relField = new relationalFields.FieldMany2One(parent, 'partner_id', record, {
+ mode: 'edit',
+ noOpen: true,
+ });
- relField.appendTo(fixture);
- testUtils.fields.editInput($('input.o_input'), 'xyzzrot');
+ relField.appendTo(fixture);
+ await testUtils.nextTick();
+ await testUtils.fields.editInput($('input.o_input'), 'xyzzrot');
- concurrency.delay(0).then(function () {
- testUtils.fields.many2one.clickItem('partner_id', 'Create');
+ await testUtils.fields.many2one.clickItem('partner_id', 'Create');
- assert.containsNone(relField, '.o_external_button',
- "should not have the button to open the record");
- assert.verifySteps(['name_search', 'name_create']);
+ assert.containsNone(relField, '.o_external_button',
+ "should not have the button to open the record");
+ assert.verifySteps(['name_search', 'name_create']);
- parent.destroy();
- model.destroy();
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- done();
- });
- });
+ parent.destroy();
+ model.destroy();
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
});
- // QUnit.test('onchange on a many2one to a different model', function (assert) {
+ // QUnit.test('onchange on a many2one to a different model', async function (assert) {
// This test is commented because the mock server does not give the correct response.
// It should return a couple [id, display_name], but I don't know the logic used
// by the server, so it's hard to emulate it correctly
@@ -911,7 +899,7 @@ QUnit.module('fields', {}, function () {
// },
// };
- // var form = createView({
+ // var form = await createView({
// View: FormView,
// model: 'partner',
// data: this.data,
@@ -921,7 +909,7 @@ QUnit.module('fields', {}, function () {
// '</form>',
// res_id: 1,
// });
- // testUtils.form.clickEdit(form);
+ // await testUtils.form.clickEdit(form);
// assert.strictEqual(form.$('input').eq(1).val(), 'xpad', "initial product_id val should be xpad");
// testUtils.fields.editInput(form.$('input').eq(0), "let us trigger an onchange");
@@ -932,9 +920,9 @@ QUnit.module('fields', {}, function () {
QUnit.test('form: quick create then save directly', async function (assert) {
assert.expect(5);
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
var newRecordID;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -945,7 +933,7 @@ QUnit.module('fields', {}, function () {
var result = this._super.apply(this, arguments);
if (args.method === 'name_create') {
assert.step('name_create');
- return def.then(_.constant(result)).then(function (nameGet) {
+ return prom.then(_.constant(result)).then(function (nameGet) {
newRecordID = nameGet[0];
return nameGet;
});
@@ -959,23 +947,24 @@ QUnit.module('fields', {}, function () {
},
});
await testUtils.fields.many2one.searchAndClickItem('trululu', {search: 'b'});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps(['name_create'],
"should wait for the name_create before creating the record");
- def.resolve();
+ await prom.resolve();
+ await testUtils.nextTick();
- assert.verifySteps(['name_create', 'create']);
+ assert.verifySteps(['create']);
form.destroy();
});
QUnit.test('list: quick create then save directly', async function (assert) {
assert.expect(8);
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
var newRecordID;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -986,7 +975,7 @@ QUnit.module('fields', {}, function () {
var result = this._super.apply(this, arguments);
if (args.method === 'name_create') {
assert.step('name_create');
- return def.then(_.constant(result)).then(function (nameGet) {
+ return prom.then(_.constant(result)).then(function (nameGet) {
newRecordID = nameGet[0];
return nameGet;
});
@@ -1000,7 +989,7 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
await testUtils.fields.many2one.searchAndClickItem('trululu', {search:'b'});
list.$buttons.find('.o_list_button_add').show();
@@ -1011,9 +1000,10 @@ QUnit.module('fields', {}, function () {
assert.containsN(list, '.o_data_row', 4,
"should wait for the name_create before adding the new row");
- def.resolve();
+ await prom.resolve();
+ await testUtils.nextTick();
- assert.verifySteps(['name_create', 'create']);
+ assert.verifySteps(['create']);
assert.strictEqual(list.$('.o_data_row:nth(1) .o_data_cell').text(), 'b',
"created row should have the correct m2o value");
assert.containsN(list, '.o_data_row', 5, "should have added the fifth row");
@@ -1024,9 +1014,9 @@ QUnit.module('fields', {}, function () {
QUnit.test('list in form: quick create then save directly', async function (assert) {
assert.expect(6);
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
var newRecordID;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1043,7 +1033,7 @@ QUnit.module('fields', {}, function () {
var result = this._super.apply(this, arguments);
if (args.method === 'name_create') {
assert.step('name_create');
- return def.then(_.constant(result)).then(function (nameGet) {
+ return prom.then(_.constant(result)).then(function (nameGet) {
newRecordID = nameGet[0];
return nameGet;
});
@@ -1057,28 +1047,28 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.fields.many2one.searchAndClickItem('trululu', {search: 'b'});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps(['name_create'],
"should wait for the name_create before creating the record");
- def.resolve();
+ await prom.resolve();
+ await testUtils.nextTick();
- assert.verifySteps(['name_create', 'create']);
+ assert.verifySteps(['create']);
assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b',
"first row should have the correct m2o value");
form.destroy();
});
- QUnit.test('list in form: quick create then add a new line directly', function (assert) {
+ QUnit.test('list in form: quick create then add a new line directly', async function (assert) {
// required many2one inside a one2many list: directly after quick creating
// a new many2one value (before the name_create returns), click on add an item:
// at this moment, the many2one has still no value, and as it is required,
// the row is discarded if a saveLine is requested. However, it should
// wait for the name_create to return before trying to save the line.
- var done = assert.async();
assert.expect(8);
this.data.partner.onchanges = {
@@ -1088,9 +1078,9 @@ QUnit.module('fields', {}, function () {
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
var newRecordID;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1106,7 +1096,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'name_create') {
- return def.then(_.constant(result)).then(function (nameGet) {
+ return prom.then(_.constant(result)).then(function (nameGet) {
newRecordID = nameGet[0];
return nameGet;
});
@@ -1118,43 +1108,42 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- form.$('.o_field_many2one input').val('b').trigger('keydown');
- concurrency.delay(0).then(function () {
- testUtils.fields.many2one.clickHighlightedItem('trululu');
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
+ 'b', 'keydown');
+ await testUtils.fields.many2one.clickHighlightedItem('trululu');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- assert.containsOnce(form, '.o_data_row',
- "there should still be only one row");
- assert.hasClass(form.$('.o_data_row'),'o_selected_row',
- "the row should still be in edition");
+ assert.containsOnce(form, '.o_data_row',
+ "there should still be only one row");
+ assert.hasClass(form.$('.o_data_row'),'o_selected_row',
+ "the row should still be in edition");
- def.resolve();
+ await prom.resolve();
+ await testUtils.nextTick();
- assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b',
- "first row should have the correct m2o value");
- assert.containsN(form, '.o_data_row', 2,
- "there should now be 2 rows");
- assert.hasClass(form.$('.o_data_row:nth(1)'),'o_selected_row',
- "the second row should be in edition");
+ assert.strictEqual(form.$('.o_data_row:first .o_data_cell').text(), 'b',
+ "first row should have the correct m2o value");
+ assert.containsN(form, '.o_data_row', 2,
+ "there should now be 2 rows");
+ assert.hasClass(form.$('.o_data_row:nth(1)'),'o_selected_row',
+ "the second row should be in edition");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
- assert.containsOnce(form, '.o_data_row',
- "there should be 1 row saved (the second one was empty and invalid)");
- assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'b',
- "should have the correct m2o value");
+ assert.containsOnce(form, '.o_data_row',
+ "there should be 1 row saved (the second one was empty and invalid)");
+ assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'b',
+ "should have the correct m2o value");
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- form.destroy();
- done();
- });
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
+ form.destroy();
});
- QUnit.test('list in form: create with one2many with many2one', function (assert) {
+ QUnit.test('list in form: create with one2many with many2one', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1170,7 +1159,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({ p: [[0, 0, { display_name: 'new record' }]] });
+ return Promise.resolve({ p: [[0, 0, { display_name: 'new record' }]] });
} 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.
@@ -1187,13 +1176,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('list in form: create with one2many with many2one (version 2)', function (assert) {
+ QUnit.test('list in form: create with one2many with many2one (version 2)', async 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({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1209,7 +1198,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({ p: [[0, 0, { display_name: 'new record', trululu: false }]] });
+ return Promise.resolve({ 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.
@@ -1226,14 +1215,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('item not dropped on discard with empty required field (default_get)', function (assert) {
+ QUnit.test('item not dropped on discard with empty required field (default_get)', async function (assert) {
// This test simulates discarding a record that has been created with
// one of its required field that is empty. When we discard the changes
// on this empty field, it should not assume that this record should be
// abandonned, since it has been added (even though it is a new record).
assert.expect(8);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1249,7 +1238,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({ p: [[0, 0, { display_name: 'new record', trululu: false }]] });
+ return Promise.resolve({ p: [[0, 0, { display_name: 'new record', trululu: false }]] });
}
return this._super.apply(this, arguments);
},
@@ -1284,12 +1273,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('list in form: name_get with unique ids (default_get)', function (assert) {
+ QUnit.test('list in form: name_get with unique ids (default_get)', async function (assert) {
assert.expect(2);
this.data.partner.records[0].display_name = "MyTrululu";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1304,7 +1293,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({
+ return Promise.resolve({
p: [
[0, 0, { trululu: 1 }],
[0, 0, { trululu: 1 }]
@@ -1325,10 +1314,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('list in form: show name of many2one fields in multi-page (default_get)', function (assert) {
+ QUnit.test('list in form: show name of many2one fields in multi-page (default_get)', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1344,7 +1333,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({
+ return Promise.resolve({
p: [
[0, 0, { display_name: 'record1', trululu: 1 }],
[0, 0, { display_name: 'record2', trululu: 2 }]
@@ -1360,7 +1349,7 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('td.o_data_cell').first().next().text(),
"first record", "should show display_name of trululu of 1st record");
- testUtils.dom.click(form.$('button.o_pager_next'));
+ await testUtils.dom.click(form.$('button.o_pager_next'));
assert.strictEqual(form.$('td.o_data_cell').first().text(),
"record2", "should show display_name of 2nd record");
@@ -1370,7 +1359,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('list in form: item not dropped on discard with empty required field (onchange in default_get)', function (assert) {
+ QUnit.test('list in form: item not dropped on discard with empty required field (onchange in default_get)', async function (assert) {
// variant of the test "list in form: discard newly added element with
// empty required field (default_get)", in which the `default_get`
// performs an `onchange` at the same time. This `onchange` may create
@@ -1389,7 +1378,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1404,7 +1393,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({
+ return Promise.resolve({
product_id: 37,
});
}
@@ -1440,7 +1429,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('list in form: item not dropped on discard with empty required field (onchange on list after default_get)', function (assert) {
+ QUnit.test('list in form: item not dropped on discard with empty required field (onchange on list after default_get)', async function (assert) {
// discarding a record from an `onchange` in a `default_get` should not
// abandon the record. This should not be the case for following
// `onchange`, except if an onchange make some changes on the list:
@@ -1459,7 +1448,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1479,8 +1468,8 @@ QUnit.module('fields', {}, function () {
"should have no row in the editable list");
// select product_id to force on_change in editable list
- testUtils.dom.click(form.$('.o_field_widget[name="product_id"] .o_input'));
- testUtils.dom.click($('.ui-menu-item').first());
+ await testUtils.dom.click(form.$('.o_field_widget[name="product_id"] .o_input'));
+ await testUtils.dom.click($('.ui-menu-item').first());
// check that there is a record in the editable list with empty string as required field
assert.containsOnce(form, '.o_data_row',
@@ -1494,9 +1483,9 @@ QUnit.module('fields', {}, function () {
"should have empty string in the required field on this record");
// click on empty required field in editable list record
- testUtils.dom.click(requiredField);
+ await testUtils.dom.click(requiredField);
// click off so that the required field still stay empty
- testUtils.dom.click($('body'));
+ await testUtils.dom.click($('body'));
// record should not be dropped
assert.containsOnce(form, '.o_data_row',
@@ -1510,13 +1499,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('item dropped on discard with empty required field with "Add an item" (invalid on "ADD")', function (assert) {
+ QUnit.test('item dropped on discard with empty required field with "Add an item" (invalid on "ADD")', async function (assert) {
// when a record in a list is added with "Add an item", it should
// always be dropped on discard if some required field are empty
// at the record creation.
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1531,7 +1520,7 @@ QUnit.module('fields', {}, function () {
});
// Click on "Add an item"
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
var charField = form.$('.o_field_widget.o_field_char[name="display_name"]');
var requiredField = form.$('.o_field_widget.o_required_modifier[name="trululu"]');
charField.val("some text");
@@ -1547,9 +1536,9 @@ QUnit.module('fields', {}, function () {
"should have empty string in the required field on this record");
// click on empty required field in editable list record
- testUtils.dom.click(requiredField);
+ await testUtils.dom.click(requiredField);
// click off so that the required field still stay empty
- testUtils.dom.click($('body'));
+ await testUtils.dom.click($('body'));
// record should be dropped
assert.containsNone(form, '.o_data_row',
@@ -1558,7 +1547,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('item not dropped on discard with empty required field with "Add an item" (invalid on "UPDATE")', function (assert) {
+ QUnit.test('item not dropped on discard with empty required field with "Add an item" (invalid on "UPDATE")', async function (assert) {
// when a record in a list is added with "Add an item", it should
// be temporarily added to the list when it is valid (e.g. required
// fields are non-empty). If the record is updated so that the required
@@ -1569,7 +1558,7 @@ QUnit.module('fields', {}, function () {
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1587,7 +1576,7 @@ QUnit.module('fields', {}, function () {
"should initially not have any record in the list");
// Click on "Add an item"
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsOnce(form, '.o_data_row',
"should have a temporary record in the list");
@@ -1598,9 +1587,9 @@ QUnit.module('fields', {}, function () {
"should have empty string in the required field on this record");
// add something to required field and leave edit mode of the record
- testUtils.dom.click($inputEditMode);
- testUtils.dom.click($('li.ui-menu-item').first());
- testUtils.dom.click($('body'));
+ await testUtils.dom.click($inputEditMode);
+ await testUtils.dom.click($('li.ui-menu-item').first());
+ await testUtils.dom.click($('body'));
var $inputReadonlyMode = form.$('.o_data_cell.o_required_modifier');
assert.containsOnce(form, '.o_data_row',
@@ -1609,7 +1598,7 @@ QUnit.module('fields', {}, function () {
"should have put some content in the required field on this record");
// remove the required field and leave edit mode of the record
- testUtils.dom.click($('.o_data_row'));
+ await testUtils.dom.click($('.o_data_row'));
assert.containsOnce(form, '.o_data_row',
"should not have dropped record in the list on discard (invalid on UPDATE)");
assert.strictEqual($inputReadonlyMode.text(), "first record",
@@ -1619,7 +1608,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('list in form: default_get with x2many create', function (assert) {
+ QUnit.test('list in form: default_get with x2many create', async function (assert) {
assert.expect(5);
var displayName = 'brandon is the new timmy';
@@ -1634,7 +1623,7 @@ QUnit.module('fields', {}, function () {
obj.int_field = obj.timmy.length;
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1650,7 +1639,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({ timmy: [[0, 0, { display_name: 'brandon is the new timmy', name: 'brandon' }]] });
+ return Promise.resolve({ timmy: [[0, 0, { display_name: 'brandon is the new timmy', name: 'brandon' }]] });
}
if (args.method === 'create') {
assert.deepEqual(args.args[0], {
@@ -1672,14 +1661,14 @@ QUnit.module('fields', {}, function () {
// edit the subrecord and save
displayName = 'new value';
- testUtils.dom.click(form.$('.o_data_cell'));
- testUtils.fields.editInput(form.$('.o_data_cell input'), displayName);
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_data_cell'));
+ await testUtils.fields.editInput(form.$('.o_data_cell input'), displayName);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('list in form: default_get with x2many create and onchange', function (assert) {
+ QUnit.test('list in form: default_get with x2many create and onchange', async function (assert) {
assert.expect(2);
this.data.partner.onchanges.turtles = function (obj) {
@@ -1694,7 +1683,7 @@ QUnit.module('fields', {}, function () {
"should have properly created the x2many command list");
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1710,7 +1699,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({ turtles: [[6, 0, [2, 3]]] });
+ return Promise.resolve({ turtles: [[6, 0, [2, 3]]] });
}
if (args.method === 'create') {
// it would be even better if we did not send the current
@@ -1727,16 +1716,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('list in form: call button in sub view', function (assert) {
+ QUnit.test('list in form: call button in sub view', async function (assert) {
assert.expect(6);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1752,7 +1741,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
@@ -1777,16 +1766,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('td.o_data_cell:first'));
- testUtils.dom.click(form.$('.o_external_button'));
- testUtils.dom.click($('button:contains("Just do it !")'));
- testUtils.dom.click($('button:contains("Just don\'t do it !")'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('td.o_data_cell:first'));
+ await testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click($('button:contains("Just do it !")'));
+ await testUtils.dom.click($('button:contains("Just don\'t do it !")'));
form.destroy();
});
- QUnit.test('X2Many sequence list in modal', function (assert) {
+ QUnit.test('X2Many sequence list in modal', async function (assert) {
assert.expect(5);
this.data.partner.fields.sequence = { string: 'Sequence', type: 'integer' };
@@ -1810,7 +1799,7 @@ QUnit.module('fields', {}, function () {
this.data.partner_type.fields.partner_ids = { string: "Partner", type: "one2many", relation: 'partner' };
this.data.partner_type.records[0].partner_ids = [1, 2];
- testUtils.createAsyncView({
+ var form = await createView({
View: FormView,
model: 'product',
data: this.data,
@@ -1832,52 +1821,52 @@ QUnit.module('fields', {}, function () {
res_id: 37,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/read') {
- return $.when([{ id: 37, name: 'xphone', display_name: 'leonardo', turtle_ids: [1] }]);
+ return Promise.resolve([{ id: 37, name: 'xphone', display_name: 'leonardo', turtle_ids: [1] }]);
}
if (route === '/web/dataset/call_kw/turtle/read') {
- return $.when([{ id: 1, type_id: [12, 'gold'] }]);
+ return Promise.resolve([{ id: 1, type_id: [12, 'gold'] }]);
}
if (route === '/web/dataset/call_kw/partner_type/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
if (route === '/web/dataset/call_kw/partner_type/read') {
- return $.when([{ id: 12, partner_ids: [1, 2], display_name: 'gold' }]);
+ return Promise.resolve([{ id: 12, partner_ids: [1, 2], display_name: 'gold' }]);
}
if (route === '/web/dataset/call_kw/partner_type/write') {
assert.step('partner_type write');
}
return this._super.apply(this, arguments);
},
- }).then(function (form) {
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_cell'));
- testUtils.dom.click(form.$('.o_external_button'));
+ });
- var $modal = $('.modal');
- assert.equal($modal.length, 1,
- 'There should be 1 modal opened');
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_cell'));
+ await testUtils.dom.click(form.$('.o_external_button'));
- var $handles = $modal.find('.ui-sortable-handle');
- assert.equal($handles.length, 2,
- 'There should be 2 sequence handlers');
+ var $modal = $('.modal');
+ assert.equal($modal.length, 1,
+ 'There should be 1 modal opened');
- testUtils.dom.dragAndDrop($handles.eq(1), $modal.find('tbody tr').first(),
- { position: 'top' });
+ var $handles = $modal.find('.ui-sortable-handle');
+ assert.equal($handles.length, 2,
+ 'There should be 2 sequence handlers');
- // Saving the modal and then the original model
- testUtils.dom.click($modal.find('.modal-footer .btn-primary'));
- testUtils.form.clickSave(form);
+ await testUtils.dom.dragAndDrop($handles.eq(1),
+ $modal.find('tbody tr').first(), { position: 'top' });
- assert.verifySteps(['onchange sequence', 'partner_type write']);
+ // Saving the modal and then the original model
+ await testUtils.dom.click($modal.find('.modal-footer .btn-primary'));
+ await testUtils.form.clickSave(form);
- form.destroy();
- });
+ assert.verifySteps(['onchange sequence', 'partner_type write']);
+
+ form.destroy();
});
- QUnit.test('autocompletion in a many2one, in form view with a domain', function (assert) {
+ QUnit.test('autocompletion in a many2one, in form view with a domain', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1895,16 +1884,16 @@ QUnit.module('fields', {}, function () {
return this._super(route, args);
}
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
testUtils.dom.click(form.$('.o_field_widget[name=product_id] input'));
form.destroy();
});
- QUnit.test('autocompletion in a many2one, in form view with a date field', function (assert) {
+ QUnit.test('autocompletion in a many2one, in form view with a date field', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1921,13 +1910,13 @@ QUnit.module('fields', {}, function () {
return this._super(route, args);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
form.destroy();
});
- QUnit.test('creating record with many2one with option always_reload', function (assert) {
+ QUnit.test('creating record with many2one with option always_reload', async function (assert) {
assert.expect(2);
this.data.partner.fields.trululu.default = 1;
@@ -1939,7 +1928,7 @@ QUnit.module('fields', {}, function () {
var count = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1949,7 +1938,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
count++;
if (args.method === 'name_get' && args.args[0][0] === 2) {
- return $.when([[2, "hello world\nso much noise"]]);
+ return Promise.resolve([[2, "hello world\nso much noise"]]);
}
return this._super(route, args);
},
@@ -1961,10 +1950,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('selecting a many2one, then discarding', function (assert) {
+ QUnit.test('selecting a many2one, then discarding', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1974,23 +1963,23 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
assert.strictEqual(form.$('a[name=product_id]').text(), '', 'the tag a should be empty');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickItem('product_id','xphone');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickItem('product_id','xphone');
assert.strictEqual(form.$('.o_field_widget[name=product_id] input').val(), "xphone", "should have selected xphone");
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.strictEqual(form.$('a[name=product_id]').text(), '', 'the tag a should be empty');
form.destroy();
});
- QUnit.test('domain and context are correctly used when doing a name_search in a m2o', function (assert) {
+ QUnit.test('domain and context are correctly used when doing a name_search in a m2o', async function (assert) {
assert.expect(4);
this.data.partner.records[0].timmy = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2016,20 +2005,20 @@ QUnit.module('fields', {}, function () {
{ hey: "ho", hello: "world", test: "yop" },
'the field attr context should have been used for the ' +
'RPC (evaluated and merged with the session one)');
- return $.when([]);
+ return Promise.resolve([]);
}
if (args.method === 'name_search' && args.model === 'partner') {
assert.deepEqual(args.kwargs.args, [['id', 'in', [12]]],
'the field attr domain should have been used for the RPC (and evaluated)');
assert.deepEqual(args.kwargs.context, { hey: 'ho', timmy: [[6, false, [12]]] },
'the field attr context should have been used for the RPC (and evaluated)');
- return $.when([]);
+ return Promise.resolve([]);
}
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
testUtils.dom.click(form.$('.o_field_widget[name=product_id] input'));
testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
@@ -2037,10 +2026,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('quick create on a many2one', function (assert) {
+ QUnit.test('quick create on a many2one', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2059,17 +2048,17 @@ QUnit.module('fields', {}, function () {
});
form.$('.o_field_many2one input').focus();
- form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout');
-
- testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
+ 'new partner', ['keyup', 'focusout']);
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary').first());
form.destroy();
});
- QUnit.test('slow create on a many2one', function (assert) {
- assert.expect(7);
+ QUnit.test('slow create on a many2one', async function (assert) {
+ assert.expect(11);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2089,41 +2078,55 @@ QUnit.module('fields', {}, function () {
// cancel the many2one creation with Cancel button
form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur');
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 1, "there should be one opened modal");
- testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)'));
+
+ await testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)'));
+ assert.strictEqual($('.modal').length, 0, "the modal should be closed");
assert.strictEqual(form.$('.o_field_many2one input').val(), "",
'the many2one should not set a value as its creation has been cancelled (with Cancel button)');
// cancel the many2one creation with Close button
- form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur');
- testUtils.dom.click($('.modal .modal-header button'));
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
+ 'new product', ['keyup', 'blur']);
+ assert.strictEqual($('.modal').length, 1, "there should be one opened modal");
+ await testUtils.dom.click($('.modal .modal-header button'));
assert.strictEqual(form.$('.o_field_many2one input').val(), "",
'the many2one should not set a value as its creation has been cancelled (with Close button)');
+ assert.strictEqual($('.modal').length, 0, "the modal should be closed");
// select a new value then cancel the creation of the new one --> restore the previous
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickItem('product_id','o');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickItem('product_id','o');
assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone", "should have selected xphone");
+
form.$('.o_field_many2one input').focus().val('new product').trigger('keyup').trigger('blur');
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 1, "there should be one opened modal");
- testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)'));
+
+ await testUtils.dom.click($('.modal .modal-footer .btn:contains(Cancel)'));
assert.strictEqual(form.$('.o_field_many2one input').val(), "xphone",
'should have restored the many2one with its previous selected value (xphone)');
// confirm the many2one creation
- form.$('.o_field_many2one input').focus();
- form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('blur');
- testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
+ form.$('.o_field_many2one input').focus().val('new partner').trigger('keyup').trigger('blur');
+ await testUtils.nextTick();
+ assert.strictEqual($('.modal').length, 1, "there should be one opened modal");
+
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:contains(Create and edit)'));
+ await testUtils.nextTick();
assert.strictEqual($('.modal .o_form_view').length, 1,
'a new modal should be opened and contain a form view');
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
+
form.destroy();
});
- QUnit.test('no_create option on a many2one', function (assert) {
+ QUnit.test('no_create option on a many2one', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2134,14 +2137,14 @@ QUnit.module('fields', {}, function () {
'</form>',
});
- form.$('.o_field_many2one input').focus();
- form.$('.o_field_many2one input').val('new partner').trigger('keyup').trigger('focusout');
-
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
+ 'new partner', ['keyup', 'focusout']);
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 0, "should not display the create modal");
form.destroy();
});
- QUnit.test('can_create and can_write option on a many2one', function (assert) {
+ QUnit.test('can_create and can_write option on a many2one', async function (assert) {
assert.expect(5);
this.data.product.options = {
@@ -2149,7 +2152,7 @@ QUnit.module('fields', {}, function () {
can_write: "false",
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2163,117 +2166,98 @@ QUnit.module('fields', {}, function () {
},
mockRPC: function (route) {
if (route === '/web/dataset/call_kw/product/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
});
- testUtils.dom.click(form.$('.o_field_many2one input'));
+ await testUtils.dom.click(form.$('.o_field_many2one input'));
assert.strictEqual($('.ui-autocomplete .o_m2o_dropdown_option:contains(Create)').length, 0,
"there shouldn't be any option to search and create");
- testUtils.dom.click($('.ui-autocomplete li:contains(xpad)').mouseenter());
+ await testUtils.dom.click($('.ui-autocomplete li:contains(xpad)').mouseenter());
assert.strictEqual(form.$('.o_field_many2one input').val(), "xpad",
"the correct record should be selected");
assert.containsOnce(form, '.o_field_many2one .o_external_button',
"there should be an external button displayed");
- testUtils.dom.click(form.$('.o_field_many2one .o_external_button'));
+ await testUtils.dom.click(form.$('.o_field_many2one .o_external_button'));
assert.strictEqual($('.modal .o_form_view.o_form_readonly').length, 1,
"there should be a readonly form view opened");
- testUtils.dom.click($('.modal .o_form_button_cancel'));
-
- form.$('.o_field_many2one input').val('new product').trigger('keyup').trigger('focusout');
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
+ 'new product', ['keyup', 'focusout']);
assert.strictEqual($('.modal').length, 0, "should not display the create modal");
form.destroy();
});
- QUnit.test('pressing enter in a m2o in an editable list', function (assert) {
+ QUnit.test('pressing enter in a m2o in an editable list', async function (assert) {
assert.expect(9);
- var done = assert.async();
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
arch: '<tree editable="bottom"><field name="product_id"/></tree>',
});
- testUtils.dom.click(list.$('td.o_data_cell:first'));
+ await testUtils.dom.click(list.$('td.o_data_cell:first'));
assert.containsOnce(list, '.o_selected_row',
"should have a row in edit mode");
// we now write 'a' and press enter to check that the selection is
// working, and prevent the navigation
- testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
- concurrency.delay(0).then(function () {
- var $input = list.$('td.o_data_cell input:first');
- var $dropdown = $input.autocomplete('widget');
- assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible");
-
- // we now trigger ENTER to select first choice
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- assert.strictEqual($input[0], document.activeElement,
- "input should still be focused");
-
- // we now trigger again ENTER to make sure we can move to next line
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
-
- assert.notOk(document.contains($input[0]),
- "input should no longer be in dom");
- assert.hasClass(list.$('tr.o_data_row:eq(1)'),'o_selected_row',
- "second row should now be selected");
-
- // we now write again 'a' in the cell to select xpad. We will now
- // test with the tab key
- testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
- return concurrency.delay(0);
- }).then(function () {
- var $input = list.$('td.o_data_cell input:first');
- var $dropdown = $input.autocomplete('widget');
- assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible");
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
- assert.strictEqual($input[0], document.activeElement,
- "input should still be focused");
-
- // we now trigger again ENTER to make sure we can move to next line
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
-
- assert.notOk(document.contains($input[0]),
- "input should no longer be in dom");
- assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row',
- "third row should now be selected");
- list.destroy();
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- done();
- });
+ await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
+ var $input = list.$('td.o_data_cell input:first');
+ var $dropdown = $input.autocomplete('widget');
+ assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible");
+
+ // we now trigger ENTER to select first choice
+ await testUtils.fields.triggerKeydown($input, 'enter');
+ assert.strictEqual($input[0], document.activeElement,
+ "input should still be focused");
+
+ // we now trigger again ENTER to make sure we can move to next line
+ await testUtils.fields.triggerKeydown($input, 'enter');
+
+ assert.notOk(document.contains($input[0]),
+ "input should no longer be in dom");
+ assert.hasClass(list.$('tr.o_data_row:eq(1)'),'o_selected_row',
+ "second row should now be selected");
+
+ // we now write again 'a' in the cell to select xpad. We will now
+ // test with the tab key
+ await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
+ var $input = list.$('td.o_data_cell input:first');
+ var $dropdown = $input.autocomplete('widget');
+ assert.ok($dropdown.is(':visible'), "autocomplete dropdown should be visible");
+ await testUtils.fields.triggerKeydown($input, 'tab');
+ assert.strictEqual($input[0], document.activeElement,
+ "input should still be focused");
+
+ // we now trigger again ENTER to make sure we can move to next line
+ await testUtils.fields.triggerKeydown($input, 'tab');
+
+ assert.notOk(document.contains($input[0]),
+ "input should no longer be in dom");
+ assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row',
+ "third row should now be selected");
+ list.destroy();
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
});
- QUnit.test('pressing ENTER on a \'no_quick_create\' many2one should open a M2ODialog', function (assert) {
- var done = assert.async();
+ QUnit.test('pressing ENTER on a \'no_quick_create\' many2one should open a M2ODialog', async function (assert) {
assert.expect(2);
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2287,47 +2271,33 @@ QUnit.module('fields', {}, function () {
});
var $input = form.$('.o_field_many2one input');
- testUtils.fields.editInput($input, "Something that does not exist");
+ await testUtils.fields.editInput($input, "Something that does not exist");
$('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter');
- concurrency.delay(0).then(function () {
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- $input.trigger($.Event('keypress', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- $input.trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- concurrency.delay(0).then(function () {
- $input.blur();
- assert.strictEqual($('.modal').length, 1,
- "should have one modal in body");
- // Check that discarding clears $input
- testUtils.dom.click($('.modal .o_form_button_cancel'));
- assert.strictEqual($input.val(), '',
- "the field should be empty");
- form.destroy();
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- done();
- });
- });
+ await testUtils.nextTick();
+ await testUtils.fields.triggerKey('down', $input, 'enter')
+ await testUtils.fields.triggerKey('press', $input, 'enter')
+ await testUtils.fields.triggerKey('up', $input, 'enter')
+ $input.blur();
+ assert.strictEqual($('.modal').length, 1,
+ "should have one modal in body");
+ // Check that discarding clears $input
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
+ assert.strictEqual($input.val(), '',
+ "the field should be empty");
+ form.destroy();
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
});
- QUnit.test('select a value by pressing TAB on a many2one with onchange', function (assert) {
- var done = assert.async();
+ QUnit.test('select a value by pressing TAB on a many2one with onchange', async function (assert) {
assert.expect(3);
this.data.partner.onchanges.trululu = function () { };
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2338,7 +2308,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(def).then(_.constant(result));
+ return prom.then(_.constant(result));
}
return result;
},
@@ -2349,39 +2319,32 @@ QUnit.module('fields', {}, function () {
});
var $input = form.$('.o_field_many2one input');
- testUtils.fields.editInput($input, "first");
- concurrency.delay(0).then(function () {
- var evOptions = {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- };
- $input.trigger($.Event('keydown', evOptions));
- $input.trigger($.Event('keypress', evOptions));
- $input.trigger($.Event('keyup', evOptions));
-
- // simulate a focusout (e.g. because the user clicks outside)
- // before the onchange returns
- form.$('.o_field_char').focus();
-
- assert.strictEqual($('.modal').length, 0,
- "there shouldn't be any modal in body");
-
- // unlock the onchange
- def.resolve();
-
- assert.strictEqual($input.val(), 'first record',
- "first record should have been selected");
- assert.strictEqual($('.modal').length, 0,
- "there shouldn't be any modal in body");
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- form.destroy();
- done();
- });
+ await testUtils.fields.editInput($input, "first");
+ await testUtils.fields.triggerKey('down', $input, 'tab');
+ await testUtils.fields.triggerKey('press', $input, 'tab');
+ await testUtils.fields.triggerKey('up', $input, 'tab');
+
+ // simulate a focusout (e.g. because the user clicks outside)
+ // before the onchange returns
+ form.$('.o_field_char').focus();
+
+ assert.strictEqual($('.modal').length, 0,
+ "there shouldn't be any modal in body");
+
+ // unlock the onchange
+ prom.resolve();
+ await testUtils.nextTick();
+
+ assert.strictEqual($input.val(), 'first record',
+ "first record should have been selected");
+ assert.strictEqual($('.modal').length, 0,
+ "there shouldn't be any modal in body");
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
+ form.destroy();
});
- QUnit.test('many2one in editable list + onchange, with enter [REQUIRE FOCUS]', function (assert) {
+ QUnit.test('many2one in editable list + onchange, with enter [REQUIRE FOCUS]', async function (assert) {
assert.expect(6);
- var done = assert.async();
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
@@ -2389,9 +2352,9 @@ QUnit.module('fields', {}, function () {
obj.int_field = obj.product_id || 0;
};
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -2402,42 +2365,30 @@ QUnit.module('fields', {}, function () {
}
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return def.then(_.constant(result));
+ return prom.then(_.constant(result));
}
return result;
},
});
- testUtils.dom.click(list.$('td.o_data_cell:first'));
- testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
- concurrency.delay(0).then(function () {
- var $input = list.$('td.o_data_cell input:first');
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- $input.trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- def.resolve();
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM");
- assert.verifySteps(['name_search', 'onchange', 'write', 'read']);
- list.destroy();
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- done();
- });
+ await testUtils.dom.click(list.$('td.o_data_cell:first'));
+ await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
+ var $input = list.$('td.o_data_cell input:first');
+ await testUtils.fields.triggerKeydown($input, 'enter');
+ await testUtils.fields.triggerKey('up', $input, 'enter');
+ prom.resolve();
+ await testUtils.nextTick();
+ await testUtils.fields.triggerKeydown($input, 'enter');
+ assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM");
+ assert.verifySteps(['name_search', 'onchange', 'write', 'read']);
+ list.destroy();
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
});
- QUnit.test('many2one in editable list + onchange, with enter, part 2 [REQUIRE FOCUS]', function (assert) {
+ QUnit.test('many2one in editable list + onchange, with enter, part 2 [REQUIRE FOCUS]', async function (assert) {
// this is the same test as the previous one, but the onchange is just
// resolved slightly later
assert.expect(6);
- var done = assert.async();
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
@@ -2445,9 +2396,9 @@ QUnit.module('fields', {}, function () {
obj.int_field = obj.product_id || 0;
};
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -2458,38 +2409,27 @@ QUnit.module('fields', {}, function () {
}
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return def.then(_.constant(result));
+ return prom.then(_.constant(result));
}
return result;
},
});
- testUtils.dom.click(list.$('td.o_data_cell:first'));
- testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
- concurrency.delay(0).then(function () {
- var $input = list.$('td.o_data_cell input:first');
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- $input.trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- $input.trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
- def.resolve();
- assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM");
- assert.verifySteps(['name_search', 'onchange', 'write', 'read']);
- list.destroy();
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- done();
- });
+ await testUtils.dom.click(list.$('td.o_data_cell:first'));
+ await testUtils.fields.editInput(list.$('td.o_data_cell input:first'), 'a');
+ var $input = list.$('td.o_data_cell input:first');
+ await testUtils.fields.triggerKeydown($input, 'enter');
+ await testUtils.fields.triggerKey('up', $input, 'enter');
+ await testUtils.fields.triggerKeydown($input, 'enter');
+ prom.resolve();
+ await testUtils.nextTick();
+ assert.strictEqual($('.modal').length, 0, "should not have any modal in DOM");
+ assert.verifySteps(['name_search', 'onchange', 'write', 'read']);
+ list.destroy();
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
});
- QUnit.test('many2one: domain updated by an onchange', function (assert) {
+ QUnit.test('many2one: domain updated by an onchange', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = {
@@ -2497,7 +2437,7 @@ QUnit.module('fields', {}, function () {
};
var domain = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2509,7 +2449,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'onchange') {
domain = [['id', 'in', [10]]];
- return $.when({
+ return Promise.resolve({
domain: {
trululu: domain,
unexisting_field: domain,
@@ -2528,18 +2468,18 @@ QUnit.module('fields', {}, function () {
});
// trigger a name_search (domain should be [])
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
// close the dropdown
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
// trigger an onchange that will update the domain
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
// trigger a name_search (domain should be [['id', 'in', [10]]])
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
form.destroy();
});
- QUnit.test('many2one in one2many: domain updated by an onchange', function (assert) {
+ QUnit.test('many2one in one2many: domain updated by an onchange', async function (assert) {
assert.expect(3);
this.data.partner.onchanges = {
@@ -2547,7 +2487,7 @@ QUnit.module('fields', {}, function () {
};
var domain = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2561,7 +2501,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
domain: {
trululu: domain,
},
@@ -2580,18 +2520,18 @@ QUnit.module('fields', {}, function () {
// add a first row with a specific domain for the m2o
domain = [['id', 'in', [10]]]; // domain for subrecord 1
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
// add a second row with another domain for the m2o
domain = [['id', 'in', [5]]]; // domain for subrecord 2
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
// check again the first row to ensure that the domain hasn't change
domain = [['id', 'in', [10]]]; // domain for subrecord 1 should have been kept
- testUtils.dom.click(form.$('.o_data_row:first .o_data_cell'));
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_data_row:first .o_data_cell'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
form.destroy();
});
@@ -2606,7 +2546,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records.push({id: 100 + i, display_name: 'test_' + i});
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2652,7 +2592,7 @@ QUnit.module('fields', {}, function () {
}
var expectedDomain;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2682,7 +2622,7 @@ QUnit.module('fields', {}, function () {
// remove the filter on ids
expectedDomain = [];
- testUtils.dom.click($('.modal .o_cp_searchview .o_facet_remove'));
+ await testUtils.dom.click($('.modal .o_cp_searchview .o_facet_remove'));
assert.verifySteps([
'default_get',
@@ -2697,12 +2637,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('updating a many2one from a many2many', function (assert) {
+ QUnit.test('updating a many2one from a many2many', async function (assert) {
assert.expect(4);
this.data.turtle.records[1].turtle_trululu = 1;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2723,22 +2663,22 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
assert.deepEqual(args.args[0], [1], "should call get_formview_id with correct id");
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
});
// Opening the modal
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_row td:contains(first record)'));
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_row td:contains(first record)'));
+ await testUtils.dom.click(form.$('.o_external_button'));
assert.strictEqual($('.modal').length, 1,
"should have one modal in body");
// Changing the 'trululu' value
- testUtils.fields.editInput($('.modal input[name="display_name"]'), 'test');
- testUtils.dom.click($('.modal button.btn-primary'));
+ await testUtils.fields.editInput($('.modal input[name="display_name"]'), 'test');
+ await testUtils.dom.click($('.modal button.btn-primary'));
// Test whether the value has changed
assert.strictEqual($('.modal').length, 0,
@@ -2749,13 +2689,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('x2many list sorted by many2one', function (assert) {
+ QUnit.test('x2many list sorted by many2one', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [1, 2, 4];
this.data.partner.fields.trululu.sortable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2773,12 +2713,12 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '124',
"should have correct order initially");
- testUtils.dom.click(form.$('.o_list_view thead th:nth(1)'));
+ await testUtils.dom.click(form.$('.o_list_view thead th:nth(1)'));
assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '412',
"should have correct order (ASC)");
- testUtils.dom.click(form.$('.o_list_view thead th:nth(1)'));
+ await testUtils.dom.click(form.$('.o_list_view thead th:nth(1)'));
assert.strictEqual(form.$('.o_data_row .o_list_number').text(), '214',
"should have correct order (DESC)");
@@ -2786,10 +2726,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with extra field from server not in form', function (assert) {
+ QUnit.test('one2many with extra field from server not in form', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2814,20 +2754,20 @@ QUnit.module('fields', {}, function () {
}
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var x2mList = form.$('.o_field_x2many_list[name=p]');
// Add a record in the list
- testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
var modal = $('.modal-lg');
var nameInput = modal.find('input.o_input[name=display_name]');
- testUtils.fields.editInput(nameInput, 'michelangelo');
+ await testUtils.fields.editInput(nameInput, 'michelangelo');
// Save the record in the modal (though it is still virtual)
- testUtils.dom.click(modal.find('.btn-primary').first());
+ await testUtils.dom.click(modal.find('.btn-primary').first());
assert.equal(x2mList.find('.o_data_row').length, 1,
'There should be 1 records in the x2m list');
@@ -2840,7 +2780,7 @@ QUnit.module('fields', {}, function () {
'The display name field should have the right value');
// Save the whole thing
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
x2mList = form.$('.o_field_x2many_list[name=p]');
@@ -2858,10 +2798,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with extra field from server not in (inline) form', function (assert) {
+ QUnit.test('one2many with extra field from server not in (inline) form', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2885,15 +2825,15 @@ QUnit.module('fields', {}, function () {
var x2mList = form.$('.o_field_x2many_list[name=p]');
// Add a record in the list
- testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
var modal = $('.modal-lg');
var nameInput = modal.find('input.o_input[name=display_name]');
- testUtils.fields.editInput(nameInput, 'michelangelo');
+ await testUtils.fields.editInput(nameInput, 'michelangelo');
// Save the record in the modal (though it is still virtual)
- testUtils.dom.click(modal.find('.btn-primary').first());
+ await testUtils.dom.click(modal.find('.btn-primary').first());
assert.equal(x2mList.find('.o_data_row').length, 1,
'There should be 1 records in the x2m list');
@@ -2901,10 +2841,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with extra X2many field from server not in inline form', function (assert) {
+ QUnit.test('one2many with extra X2many field from server not in inline form', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2928,13 +2868,13 @@ QUnit.module('fields', {}, function () {
var x2mList = form.$('.o_field_x2many_list[name=p]');
// Add a first record in the list
- testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
// Save & New
- testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(1));
+ await testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(1));
// Save & Close
- testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(0));
+ await testUtils.dom.click($('.modal-lg').find('.btn-primary').eq(0));
assert.equal(x2mList.find('.o_data_row').length, 2,
'There should be 2 records in the x2m list');
@@ -2942,11 +2882,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many invisible depends on parent field', function (assert) {
+ QUnit.test('one2many invisible depends on parent field', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2972,21 +2912,22 @@ QUnit.module('fields', {}, function () {
});
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
+ await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
assert.containsOnce(form, 'th',
"should be 1 column when the product_id is set");
- form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
+ '', 'keyup');
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many when product_id is not set");
- testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
assert.containsOnce(form, 'th',
"should be 1 column after the value change");
form.destroy();
});
- QUnit.test('one2many column visiblity depends on onchange of parent field', function (assert) {
+ QUnit.test('one2many column visiblity depends on onchange of parent field', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [2];
@@ -2999,7 +2940,7 @@ QUnit.module('fields', {}, function () {
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3020,24 +2961,24 @@ QUnit.module('fields', {}, function () {
"should be only 1 column ('foo') in the one2many");
assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// add a new o2m record
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.$('.o_field_one2many input:first').focus();
- testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line');
- testUtils.dom.click(form.$el);
+ await testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line');
+ await testUtils.dom.click(form.$el);
assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')");
form.destroy();
});
- QUnit.test('one2many column_invisible on view not inline', function (assert) {
+ QUnit.test('one2many column_invisible on view not inline', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3064,15 +3005,16 @@ QUnit.module('fields', {}, function () {
});
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
+ await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
assert.containsOnce(form, 'th',
"should be 1 column when the product_id is set");
- form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
+ '', 'keyup');
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many when product_id is not set");
- testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
assert.containsOnce(form, 'th',
"should be 1 column after the value change");
form.destroy();
diff --git a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js
index 18581b88078..c29bf4f1ec9 100644
--- a/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js
+++ b/addons/web/static/tests/fields/relational_fields/field_one2many_tests.js
@@ -159,7 +159,7 @@ QUnit.module('fields', {}, function () {
}, function () {
QUnit.module('FieldOne2Many');
- QUnit.test('New record with a o2m also with 2 new records, ordered, and resequenced', function (assert) {
+ QUnit.test('New record with a o2m also with 2 new records, ordered, and resequenced', async function (assert) {
assert.expect(3);
// Needed to have two new records in a single stroke
@@ -169,11 +169,11 @@ QUnit.module('fields', {}, function () {
[5],
[0, 0, { trululu: false }],
[0, 0, { trululu: false }],
- ]
+ ];
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -190,7 +190,7 @@ QUnit.module('fields', {}, function () {
mode: 'create',
},
mockRPC: function (route, args) {
- assert.step(args.method + ' ' + args.model)
+ assert.step(args.method + ' ' + args.model);
return this._super(route, args);
},
});
@@ -198,7 +198,7 @@ QUnit.module('fields', {}, function () {
// change the int_field through drag and drop
// that way, we'll trigger the sorting and the name_get
// of the lines of "p"
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(1),
form.$('tbody tr').first(),
{ position: 'top' }
@@ -211,7 +211,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('O2M List with pager, decoration and default_order: add and cancel adding', function (assert) {
+ QUnit.test('O2M List with pager, decoration and default_order: add and cancel adding', async function (assert) {
assert.expect(3);
// The decoration on the list implies that its condition will be evaluated
@@ -222,7 +222,7 @@ QUnit.module('fields', {}, function () {
// and evaluation of the decoration against *visible records*
this.data.partner.records[0].p = [2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -240,30 +240,25 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list .o_field_x2many_list_row_add a'));
- var $dataRows = form.$('.o_field_x2many_list .o_data_row');
- assert.equal($dataRows.length, 2,
+ assert.containsN(form, '.o_field_x2many_list .o_data_row', 2,
'There should be 2 rows');
- var $expectedSelectedRow = $dataRows.eq(1);
+ var $expectedSelectedRow = form.$('.o_field_x2many_list .o_data_row').eq(1);
var $actualSelectedRow = form.$('.o_selected_row');
assert.equal($actualSelectedRow[0], $expectedSelectedRow[0],
'The selected row should be the new one');
// Cancel Creation
- var escapeKey = $.ui.keyCode.ESCAPE;
- $actualSelectedRow.find('input').trigger(
- $.Event('keydown', { which: escapeKey, keyCode: escapeKey }));
-
- $dataRows = form.$('.o_field_x2many_list .o_data_row');
- assert.equal($dataRows.length, 1,
+ await testUtils.fields.triggerKeydown($actualSelectedRow.find('input'), 'escape');
+ assert.containsOnce(form, '.o_field_x2many_list .o_data_row',
'There should be 1 row');
form.destroy();
});
- QUnit.test('O2M with parented m2o and domain on parent.m2o', function (assert) {
+ QUnit.test('O2M with parented m2o and domain on parent.m2o', async function (assert) {
assert.expect(3);
/* records in an o2m can have a m2o pointing to themselves
@@ -272,7 +267,7 @@ QUnit.module('fields', {}, function () {
*/
this.data.turtle.fields.parent_id = { string: "Parent", type: "many2one", relation: 'turtle' };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -297,31 +292,31 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list[name=turtles] .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list[name=turtles] .o_field_x2many_list_row_add a'));
- testUtils.fields.many2one.clickOpenDropdown('parent_id');
- testUtils.fields.many2one.clickHighlightedItem('parent_id');
+ await testUtils.fields.many2one.clickOpenDropdown('parent_id');
+ await testUtils.fields.many2one.clickHighlightedItem('parent_id');
var $modal = $('.modal-content');
- testUtils.dom.click($modal.eq(1).find('.modal-footer .btn-primary').eq(0));
- testUtils.dom.click($modal.eq(0).find('.modal-footer .btn-primary').eq(1));
+ await testUtils.dom.click($modal.eq(1).find('.modal-footer .btn-primary').eq(0));
+ await testUtils.dom.click($modal.eq(0).find('.modal-footer .btn-primary').eq(1));
- assert.equal(form.$('.o_data_row').length, 1,
+ assert.containsOnce(form, '.o_data_row',
'The main record should have the new record in its o2m');
$modal = $('.modal-content');
- testUtils.dom.click($modal.find('.o_field_many2one input'));
+ await testUtils.dom.click($modal.find('.o_field_many2one input'));
form.destroy();
});
- QUnit.test('one2many list editable with cell readonly modifier', function (assert) {
+ QUnit.test('one2many list editable with cell readonly modifier', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
this.data.partner.records[1].turtles = [1, 2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -344,22 +339,22 @@ QUnit.module('fields', {}, function () {
}
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
var $targetInput = $('.o_selected_row .o_input[name=foo]');
assert.equal($targetInput[0], document.activeElement,
'The first input of the line should have the focus');
// Simulating hitting the 'f' key twice
- testUtils.fields.editInput($targetInput, 'f');
- testUtils.fields.editInput($targetInput, $targetInput.val() + 'f');
+ await testUtils.fields.editInput($targetInput, 'f');
+ await testUtils.fields.editInput($targetInput, $targetInput.val() + 'f');
assert.equal($targetInput[0], document.activeElement,
'The first input of the line should still have the focus');
// Simulating a TAB key
- $targetInput.trigger($.Event('keydown', { which: 9, keyCode: 9 }));
+ await testUtils.fields.triggerKeydown($targetInput, 'tab');
var $secondTarget = $('.o_selected_row .o_input[name=qux]');
@@ -367,19 +362,19 @@ QUnit.module('fields', {}, function () {
'The second input of the line should have the focus after the TAB press');
- testUtils.fields.editInput($secondTarget, 9);
- testUtils.fields.editInput($secondTarget, $secondTarget.val() + 9);
+ await testUtils.fields.editInput($secondTarget, 9);
+ await testUtils.fields.editInput($secondTarget, $secondTarget.val() + 9);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many basic properties', function (assert) {
+ QUnit.test('one2many basic properties', async function (assert) {
assert.expect(6);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -412,7 +407,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('td.o_list_record_remove').length,
"embedded one2many records should not have a remove icon");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('.o_field_x2many_list_row_add').length,
"embedded one2many should now be editable");
@@ -425,10 +420,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('transferring class attributes in one2many sub fields', function (assert) {
+ QUnit.test('transferring class attributes in one2many sub fields', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -445,12 +440,12 @@ QUnit.module('fields', {}, function () {
assert.containsOnce(form, 'td.hey',
'should have a td with the desired class');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'td.hey',
'should have a td with the desired class');
- testUtils.dom.click(form.$('td.o_data_cell'));
+ await testUtils.dom.click(form.$('td.o_data_cell'));
assert.containsOnce(form, 'input[name="turtle_foo"].hey',
'should have an input with the desired class');
@@ -458,11 +453,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with date and datetime', function (assert) {
+ QUnit.test('one2many with date and datetime', async function (assert) {
assert.expect(2);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -494,11 +489,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('rendering with embedded one2many', function (assert) {
+ QUnit.test('rendering with embedded one2many', async function (assert) {
assert.expect(2);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -526,11 +521,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('use the limit attribute in arch (in field o2m inline tree view)', function (assert) {
+ QUnit.test('use the limit attribute in arch (in field o2m inline tree view)', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1, 2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -556,11 +551,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('use the limit attribute in arch (in field o2m non inline tree view)', function (assert) {
+ QUnit.test('use the limit attribute in arch (in field o2m non inline tree view)', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1, 2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -585,11 +580,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with default_order on view not inline', function (assert) {
+ QUnit.test('one2many with default_order on view not inline', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [1, 2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -615,11 +610,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('embedded one2many with widget', function (assert) {
+ QUnit.test('embedded one2many with widget', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -644,7 +639,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('embedded one2many with handle widget', function (assert) {
+ QUnit.test('embedded one2many with handle widget', async function (assert) {
assert.expect(10);
var nbConfirmChange = 0;
@@ -657,7 +652,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles = [1, 2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -685,14 +680,14 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa",
"should have the 3 rows in the correct order");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa",
"should still have the 3 rows in the correct order");
assert.strictEqual(nbConfirmChange, 0, "should not have confirmed any change yet");
// Drag and drop the second line in first position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(1),
form.$('tbody tr').first(),
{ position: 'top' }
@@ -705,7 +700,7 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipyopkawa",
"should have the 3 rows in the new order");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.deepEqual(_.map(this.data.turtle.records, function (turtle) {
return _.pick(turtle, 'id', 'turtle_foo', 'turtle_int');
@@ -723,7 +718,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange for embedded one2many in a one2many with a second page', function (assert) {
+ QUnit.test('onchange for embedded one2many in a one2many with a second page', async function (assert) {
assert.expect(1);
this.data.turtle.fields.partner_ids.type = 'one2many';
@@ -747,7 +742,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -778,16 +773,16 @@ QUnit.module('fields', {}, function () {
}
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_cell').eq(1));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_cell').eq(1));
var $cell = form.$('.o_selected_row .o_input[name=turtle_foo]');
- testUtils.fields.editSelect($cell, "hop");
- testUtils.form.clickSave(form);
+ await testUtils.fields.editSelect($cell, "hop");
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('onchange for embedded one2many in a one2many updated by server', function (assert) {
+ QUnit.test('onchange for embedded one2many in a one2many updated by server', async function (assert) {
// here we test that after an onchange, the embedded one2many field has
// been updated by a new list of ids by the server response, to this new
// list should be correctly sent back at save time
@@ -809,7 +804,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -840,11 +835,11 @@ QUnit.module('fields', {}, function () {
assert.deepEqual(form.$('.o_many2many_tags_cell').text().trim(), "second record",
"the partner_ids should be as specified at initialization");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_cell').eq(1));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_cell').eq(1));
var $cell = form.$('.o_selected_row .o_input[name=turtle_foo]');
- testUtils.fields.editSelect($cell, "hop");
- testUtils.form.clickSave(form);
+ await testUtils.fields.editSelect($cell, "hop");
+ await testUtils.form.clickSave(form);
assert.deepEqual(form.$('.o_many2many_tags_cell').text().trim().split(/\s+/),
["second", "record", "aaa"],
@@ -853,24 +848,24 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange for embedded one2many with handle widget', function (assert) {
+ QUnit.test('onchange for embedded one2many with handle widget', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1, 2, 3];
var partnerOnchange = 0;
this.data.partner.onchanges = {
- turtles: function (obj) {
+ turtles: function () {
partnerOnchange++;
},
};
var turtleOnchange = 0;
this.data.turtle.onchanges = {
- turtle_int: function (obj) {
+ turtle_int: function () {
turtleOnchange++;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -891,10 +886,10 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// Drag and drop the second line in first position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(1),
form.$('tbody tr').first(),
{ position: 'top' }
@@ -906,7 +901,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange for embedded one2many with handle widget using same sequence', function (assert) {
+ QUnit.test('onchange for embedded one2many with handle widget using same sequence', async function (assert) {
assert.expect(4);
this.data.turtle.records[0].turtle_int = 1;
@@ -920,7 +915,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -948,14 +943,14 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa",
"should have the 3 rows in the correct order");
// Drag and drop the second line in first position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(1),
form.$('tbody tr').first(),
{ position: 'top' }
@@ -965,11 +960,11 @@ QUnit.module('fields', {}, function () {
"should still have the 3 rows in the correct order");
assert.strictEqual(turtleOnchange, 3, "should update all lines");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('onchange (with command 5) for embedded one2many with handle widget', function (assert) {
+ QUnit.test('onchange (with command 5) for embedded one2many with handle widget', async function (assert) {
assert.expect(3);
var ids = [];
@@ -990,7 +985,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1009,16 +1004,16 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "yopblipkawa",
"should have the 3 rows in the correct order");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp');
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp');
// Drag and drop the third line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(2),
form.$('.o_field_one2many tbody tr').eq(1),
{ position: 'top' }
@@ -1026,8 +1021,8 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_data_cell').text(), "blurpkawablip", "should display to record in 'turtle_int' order");
- testUtils.form.clickSave(form);
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
assert.strictEqual(form.$('.o_data_cell:not(.o_handle_cell)').text(), "blurpkawablip",
"should display to record in 'turtle_int' order");
@@ -1035,7 +1030,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange with modifiers for embedded one2many on the second page', function (assert) {
+ QUnit.test('onchange with modifiers for embedded one2many on the second page', async function (assert) {
assert.expect(7);
var data = this.data;
@@ -1074,7 +1069,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: data,
@@ -1094,29 +1089,29 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29",
"should display the records in order");
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp');
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp');
// the domain fail if the widget does not use the allready loaded data.
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "blurp#21#22#23#24#25#26#27#28#29",
"should display the records in order with the changes");
- testUtils.dom.click($('.modal .modal-footer button:first'));
+ await testUtils.dom.click($('.modal .modal-footer button:first'));
assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29",
"should cancel changes and display the records in order");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// Drag and drop the third line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(2),
form.$('.o_field_one2many tbody tr').eq(1),
{ position: 'top' }
@@ -1126,7 +1121,7 @@ QUnit.module('fields', {}, function () {
"should display the records in order after resequence (display record with turtle_int=0)");
// Drag and drop the third line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(2),
form.$('.o_field_one2many tbody tr').eq(1),
{ position: 'top' }
@@ -1135,12 +1130,12 @@ QUnit.module('fields', {}, function () {
assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#39#40#41#42#43#44#45#46#47",
"should display the records in order after resequence (display record with turtle_int=0)");
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#39#40#41#42#43#44#45#46#47",
"should display the records in order after resequence");
- testUtils.dom.click($('.modal .modal-footer button:first'));
+ await testUtils.dom.click($('.modal .modal-footer button:first'));
assert.equal(form.$('.o_field_one2many td[class="o_data_cell"]').text(), "#20#21#22#23#24#25#26#27#28#29",
"should cancel changes and display the records in order");
@@ -1148,7 +1143,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange followed by edition on the second page', function (assert) {
+ QUnit.test('onchange followed by edition on the second page', async function (assert) {
assert.expect(12);
var ids = [];
@@ -1169,7 +1164,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1188,30 +1183,30 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1');
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2');
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1');
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2');
assert.containsN(form, '.o_data_row', 40, "should display 40 records");
assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 0, "should display '#39' at the first line");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 40, "should display 39 records and the create line");
assert.containsOnce(form, '.o_data_row:first .o_field_char', "should display the create line in first position");
assert.strictEqual(form.$('.o_data_row:first .o_field_char').val(), "", "should an empty input");
assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 1, "should display '#39' at the second line");
- testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3');
+ await testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3');
assert.containsOnce(form, '.o_data_row:first .o_field_char', "should display the create line in first position after onchange");
assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#39))').index(), 1, "should display '#39' at the second line after onchange");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 40, "should display 39 records and the create line");
assert.containsOnce(form, '.o_data_row:first .o_field_char', "should display the create line in first position");
@@ -1221,7 +1216,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange followed by edition on the second page (part 2)', function (assert) {
+ QUnit.test('onchange followed by edition on the second page (part 2)', async function (assert) {
assert.expect(8);
var ids = [];
@@ -1244,7 +1239,7 @@ QUnit.module('fields', {}, function () {
// bottom order
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1263,25 +1258,25 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1');
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2');
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(1) input:first'), 'value 1');
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:eq(2) input:first'), 'value 2');
assert.containsN(form, '.o_data_row', 40, "should display 40 records");
assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#77))').index(), 39, "should display '#77' at the last line");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 41, "should display 41 records and the create line");
assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#76))').index(), 38, "should display '#76' at the penultimate line");
assert.strictEqual(form.$('.o_data_row:has(.o_field_char)').index(), 40, "should display the create line at the last position");
- testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3');
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_data_row input:first'), 'value 3');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 42, "should display 42 records and the create line");
assert.strictEqual(form.$('.o_data_row:has(.o_data_cell:contains(#76))').index(), 38, "should display '#76' at the penultimate line");
@@ -1290,7 +1285,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange returning a command 6 for an x2many', function (assert) {
+ QUnit.test('onchange returning a command 6 for an x2many', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = {
@@ -1299,7 +1294,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1321,7 +1316,7 @@ QUnit.module('fields', {}, function () {
"there should be one record in the relation");
// change the value of foo to trigger the onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value');
assert.containsN(form, '.o_data_row', 3,
"there should be three records in the relation");
@@ -1329,7 +1324,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('x2many fields inside x2manys are fetched after an onchange', function (assert) {
+ QUnit.test('x2many fields inside x2manys are fetched after an onchange', async function (assert) {
assert.expect(6);
this.data.turtle.records[0].partner_ids = [1];
@@ -1340,7 +1335,7 @@ QUnit.module('fields', {}, function () {
};
var checkRPC = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1379,7 +1374,7 @@ QUnit.module('fields', {}, function () {
// change the value of foo to trigger the onchange
checkRPC = true; // enable flag to check read RPC for the m2m field
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value');
assert.containsN(form, '.o_data_row', 3,
"there should be three records in the relation");
@@ -1389,7 +1384,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('reference fields inside x2manys are fetched after an onchange', function (assert) {
+ QUnit.test('reference fields inside x2manys are fetched after an onchange', async function (assert) {
assert.expect(5);
this.data.turtle.records[1].turtle_ref = 'product,41';
@@ -1400,7 +1395,7 @@ QUnit.module('fields', {}, function () {
};
var checkRPC = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1437,7 +1432,7 @@ QUnit.module('fields', {}, function () {
// change the value of foo to trigger the onchange
checkRPC = true; // enable flag to check read RPC for reference field
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'some value');
assert.containsN(form, '.o_data_row', 3,
"there should be three records in the relation");
@@ -1447,7 +1442,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange on one2many containing x2many in form view', function (assert) {
+ QUnit.test('onchange on one2many containing x2many in form view', async function (assert) {
assert.expect(16);
this.data.partner.onchanges = {
@@ -1456,7 +1451,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1486,20 +1481,20 @@ QUnit.module('fields', {}, function () {
// open the created o2m record in a form view, and add a m2m subrecord
// in its relation
- testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
assert.strictEqual($('.modal').length, 1, "should have opened a dialog");
assert.strictEqual($('.modal .o_data_row').length, 0,
"there should be no record in the one2many in the dialog");
// add a many2many subrecord
- testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal').length, 2,
"should have opened a second dialog");
// select a many2many subrecord
- testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first'));
+ await testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first'));
assert.strictEqual($('.modal').length, 1,
"second dialog should be closed");
@@ -1509,25 +1504,25 @@ QUnit.module('fields', {}, function () {
'm2m pager should be hidden');
// click on 'Save & Close'
- testUtils.dom.click($('.modal-footer .btn-primary:first'));
+ await testUtils.dom.click($('.modal-footer .btn-primary:first'));
assert.strictEqual($('.modal').length, 0, "dialog should be closed");
// reopen o2m record, and another m2m subrecord in its relation, but
// discard the changes
- testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
assert.strictEqual($('.modal').length, 1, "should have opened a dialog");
assert.strictEqual($('.modal .o_data_row').length, 1,
"there should be one record in the one2many in the dialog");
// add another m2m subrecord
- testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal').length, 2,
"should have opened a second dialog");
- testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first'));
+ await testUtils.dom.click($('.modal:nth(1) .o_list_view .o_data_cell:first'));
assert.strictEqual($('.modal').length, 1,
"second dialog should be closed");
@@ -1535,12 +1530,12 @@ QUnit.module('fields', {}, function () {
"there should be two records in the one2many in the dialog");
// click on 'Discard'
- testUtils.dom.clickFirst($('.modal-footer .btn-secondary'));
+ await testUtils.dom.clickFirst($('.modal-footer .btn-secondary'));
assert.strictEqual($('.modal').length, 0, "dialog should be closed");
// reopen o2m record to check that second changes have properly been discarded
- testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
assert.strictEqual($('.modal').length, 1, "should have opened a dialog");
assert.strictEqual($('.modal .o_data_row').length, 1,
@@ -1549,7 +1544,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('embedded one2many with handle widget with minimum setValue calls', function (assert) {
+ QUnit.test('embedded one2many with handle widget with minimum setValue calls', async function (assert) {
var done = assert.async();
assert.expect(20);
@@ -1574,7 +1569,7 @@ QUnit.module('fields', {}, function () {
});
this.data.partner.records[0].turtles = [1, 2, 3, 4, 5, 6, 7];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1596,28 +1591,26 @@ QUnit.module('fields', {}, function () {
});
testUtils.mock.intercept(form, "field_changed", function (event) {
- assert.step(form.model.get(event.data.changes.turtles.id).res_id);
+ assert.step(String(form.model.get(event.data.changes.turtles.id).res_id));
}, true);
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- var steps = [];
var positions = [
- [6, 0, 'top', [3, 6, 1, 2, 5, 7, 4]], // move the last to the first line
- [5, 1, 'top', [7, 6, 1, 2, 5]], // move the penultimate to the second line
- [2, 5, 'center', [1, 2, 5, 6]], // move the third to the penultimate line
+ [6, 0, 'top', ['3', '6', '1', '2', '5', '7', '4']], // move the last to the first line
+ [5, 1, 'top', ['7', '6', '1', '2', '5']], // move the penultimate to the second line
+ [2, 5, 'center', ['1', '2', '5', '6']], // move the third to the penultimate line
];
- function dragAndDrop() {
+ async function dragAndDrop() {
var pos = positions.shift();
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(pos[0]),
form.$('tbody tr').eq(pos[1]),
{ position: pos[2] }
);
- steps = steps.concat(pos[3]);
- assert.verifySteps(steps,
+ assert.verifySteps(pos[3],
"sequences values should be apply from the begin index to the drop index");
if (positions.length) {
@@ -1644,11 +1637,11 @@ QUnit.module('fields', {}, function () {
dragAndDrop();
});
- QUnit.test('embedded one2many (editable list) with handle widget', function (assert) {
+ QUnit.test('embedded one2many (editable list) with handle widget', async function (assert) {
assert.expect(8);
this.data.partner.records[0].p = [1, 2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1676,12 +1669,12 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "My little Foo Valueblipyop",
"should have the 3 rows in the correct order");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "My little Foo Valueblipyop",
"should still have the 3 rows in the correct order");
// Drag and drop the second line in first position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
form.$('.ui-sortable-handle').eq(1),
form.$('tbody tr').first(),
{ position: 'top' }
@@ -1693,19 +1686,19 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipMy little Foo Valueyop",
"should have the 3 rows in the new order");
- testUtils.dom.click(form.$('tbody tr:first td:first'));
+ await testUtils.dom.click(form.$('tbody tr:first td:first'));
assert.strictEqual(form.$('tbody tr:first td.o_data_cell:not(.o_handle_cell) input').val(), "blip",
"should edit the correct row");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('td.o_data_cell:not(.o_handle_cell)').text(), "blipMy little Foo Valueyop",
"should still have the 3 rows in the new order");
form.destroy();
});
- QUnit.test('one2many field when using the pager', function (assert) {
+ QUnit.test('one2many field when using the pager', async function (assert) {
assert.expect(13);
var ids = [];
@@ -1721,7 +1714,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[1].p = ids.slice(42);
var count = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1759,6 +1752,7 @@ QUnit.module('fields', {}, function () {
// related records of record 1 anymore). Two additional RPCs should have
// been done
form.pager.next();
+ await testUtils.nextTick();
assert.strictEqual(count, 4, 'two RPCs should have been done');
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 3,
'one2many kanban should contain 3 cards for record 2');
@@ -1766,19 +1760,21 @@ QUnit.module('fields', {}, function () {
// move back to record 1, which should contain again its first 40 related
// records
form.pager.previous();
+ await testUtils.nextTick();
assert.strictEqual(count, 6, 'two RPCs should have been done');
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 40,
'one2many kanban should contain 40 cards for record 1');
// move to the second page of the o2m: 1 RPC should have been done to fetch
// the 2 subrecords of page 2, and those records should now be displayed
- testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
assert.strictEqual(count, 7, 'one RPC should have been done');
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 2,
'one2many kanban should contain 2 cards for record 1 at page 2');
// move to record 2 again and check that everything is correctly updated
form.pager.next();
+ await testUtils.nextTick();
assert.strictEqual(count, 9, 'two RPCs should have been done');
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 3,
'one2many kanban should contain 3 cards for record 2');
@@ -1786,15 +1782,16 @@ QUnit.module('fields', {}, function () {
// move back to record 1 and move to page 2 again: all data should have
// been correctly reloaded
form.pager.previous();
+ await testUtils.nextTick();
assert.strictEqual(count, 11, 'two RPCs should have been done');
- testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
assert.strictEqual(count, 12, 'one RPC should have been done');
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 2,
'one2many kanban should contain 2 cards for record 1 at page 2');
form.destroy();
});
- QUnit.test('edition of one2many field with pager', function (assert) {
+ QUnit.test('edition of one2many field with pager', async function (assert) {
assert.expect(31);
var ids = [];
@@ -1811,7 +1808,7 @@ QUnit.module('fields', {}, function () {
var saveCount = 0;
var checkRead = false;
var readIDs;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1894,10 +1891,10 @@ QUnit.module('fields', {}, function () {
// add a record on page one
checkRead = true;
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o-kanban-button-new'));
- testUtils.fields.editInput($('.modal input'), 'new record');
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
+ await testUtils.fields.editInput($('.modal input'), 'new record');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
// checks
assert.strictEqual(readIDs, undefined, "should not have read any record");
assert.strictEqual(form.$('span:contains(new record)').length, 0,
@@ -1909,14 +1906,14 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_kanban_record:first span:contains(new record)').length,
0, 'new record should not be on page 1');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// delete a record on page one
checkRead = true;
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 10)').length,
1, 'first record should be the one with id 10 (next checks rely on that)');
- testUtils.dom.click(form.$('.delete_icon:first'));
+ await testUtils.dom.click(form.$('.delete_icon:first'));
// checks
assert.deepEqual(readIDs, [50],
"should have read a record (to display 40 records on page 1)");
@@ -1925,31 +1922,31 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_x2m_control_panel .o_pager_counter').text().trim(),
'1-40 / 45', "pager range should be correct");
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// add and delete records in both pages
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
checkRead = true;
readIDs = undefined;
// add and delete a record in page 1
- testUtils.dom.click(form.$('.o-kanban-button-new'));
- testUtils.fields.editInput($('.modal input'), 'new record page 1');
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
+ await testUtils.fields.editInput($('.modal input'), 'new record page 1');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 11)').length,
1, 'first record should be the one with id 11 (next checks rely on that)');
- testUtils.dom.click(form.$('.delete_icon:first'));
+ await testUtils.dom.click(form.$('.delete_icon:first'));
assert.deepEqual(readIDs, [51],
"should have read a record (to display 40 records on page 1)");
// add and delete a record in page 2
- testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
assert.strictEqual(form.$('.o_kanban_record:first span:contains(relational record 52)').length,
1, 'first record should be the one with id 52 (next checks rely on that)');
checkRead = true;
readIDs = undefined;
- testUtils.dom.click(form.$('.delete_icon:first'));
- testUtils.dom.click(form.$('.o-kanban-button-new'));
- testUtils.fields.editInput($('.modal input'), 'new record page 2');
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click(form.$('.delete_icon:first'));
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
+ await testUtils.fields.editInput($('.modal input'), 'new record page 2');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual(readIDs, undefined, "should not have read any record");
// checks
assert.strictEqual(form.$('.o_kanban_record:not(".o_kanban_ghost")').length, 5,
@@ -1961,12 +1958,12 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_kanban_record span:contains(new record page 2)').length,
1, 'new records should be on page 2');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('edition of one2many field, with onchange and not inline sub view', function (assert) {
+ QUnit.test('edition of one2many field, with onchange and not inline sub view', async function (assert) {
assert.expect(2);
this.data.turtle.onchanges.turtle_int = function (obj) {
@@ -1974,7 +1971,7 @@ QUnit.module('fields', {}, function () {
};
this.data.partner.onchanges.turtles = function () { };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1985,27 +1982,27 @@ QUnit.module('fields', {}, function () {
'turtle,false,list': '<tree><field name="turtle_foo"/></tree>',
'turtle,false,form': '<form><group><field name="turtle_foo"/><field name="turtle_int"/></group></form>',
},
- mockRPC: function (route, args) {
+ mockRPC: function () {
return this._super.apply(this, arguments);
},
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($('input[name="turtle_int"]'), '5');
- testUtils.dom.click($('.modal-footer button.btn-primary').first());
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($('input[name="turtle_int"]'), '5');
+ await testUtils.dom.click($('.modal-footer button.btn-primary').first());
assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '5',
'should display 5 in the foo field');
- testUtils.dom.click(form.$('tbody tr:eq(1) td.o_data_cell'));
+ await testUtils.dom.click(form.$('tbody tr:eq(1) td.o_data_cell'));
- testUtils.fields.editInput($('input[name="turtle_int"]'), '3');
- testUtils.dom.click($('.modal-footer button.btn-primary').first());
+ await testUtils.fields.editInput($('input[name="turtle_int"]'), '3');
+ await testUtils.dom.click($('.modal-footer button.btn-primary').first());
assert.strictEqual(form.$('tbody tr:eq(1) td.o_data_cell').text(), '3',
'should now display 3 in the foo field');
form.destroy();
});
- QUnit.test('sorting one2many fields', function (assert) {
+ QUnit.test('sorting one2many fields', async function (assert) {
assert.expect(4);
this.data.partner.fields.foo.sortable = true;
@@ -2015,7 +2012,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].p = [23, 24, 25];
var rpcCount = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2040,20 +2037,20 @@ QUnit.module('fields', {}, function () {
throw "should not render the whole form";
};
- testUtils.dom.click(form.$('table thead th:contains(Foo)'));
+ await testUtils.dom.click(form.$('table thead th:contains(Foo)'));
assert.strictEqual(rpcCount, 0,
'sort should be in memory, no extra RPCs should have been done');
assert.ok(form.$('table tbody tr:eq(2) td:contains(xyz)').length,
"the 3rd record is the one with 'xyz' value");
- testUtils.dom.click(form.$('table thead th:contains(Foo)'));
+ await testUtils.dom.click(form.$('table thead th:contains(Foo)'));
assert.ok(form.$('table tbody tr:eq(2) td:contains(abc)').length,
"the 3rd record is the one with 'abc' value");
form.destroy();
});
- QUnit.test('one2many list field edition', function (assert) {
+ QUnit.test('one2many list field edition', async function (assert) {
assert.expect(6);
this.data.partner.records.push({
@@ -2062,7 +2059,7 @@ QUnit.module('fields', {}, function () {
});
this.data.partner.records[1].p = [3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2079,33 +2076,33 @@ QUnit.module('fields', {}, function () {
// edit the first line of the o2m
assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'relational record 1',
"display name of first record in o2m list should be 'relational record 1'");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_one2many tbody td').first());
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_one2many tbody td').first());
assert.hasClass(form.$('.o_field_one2many tbody td').first().parent(),'o_selected_row',
"first row of o2m should be in edition");
- testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value");
+ await testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value");
assert.hasClass(form.$('.o_field_one2many tbody td').first().parent(),'o_selected_row',
"first row of o2m should still be in edition");
// // leave o2m edition
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$el);
assert.doesNotHaveClass(form.$('.o_field_one2many tbody td').first().parent(), 'o_selected_row',
"first row of o2m should be readonly again");
// discard changes
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'new value',
"changes shouldn't have been discarded yet, waiting for user confirmation");
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'relational record 1',
"display name of first record in o2m list should be 'relational record 1'");
// edit again and save
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_one2many tbody td').first());
- testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value");
- testUtils.dom.click(form.$el);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_one2many tbody td').first());
+ await testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value");
+ await testUtils.dom.click(form.$el);
+ await testUtils.form.clickSave(form);
// FIXME: this next test doesn't pass as the save of updates of
// relational data is temporarily disabled
// assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'new value',
@@ -2114,9 +2111,9 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list: create action disabled', function (assert) {
+ QUnit.test('one2many list: create action disabled', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2133,17 +2130,17 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" link should not be available in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" link should not be available in readonly');
form.destroy();
});
- QUnit.test('one2many list: unlink two records', function (assert) {
+ QUnit.test('one2many list: unlink two records', async function (assert) {
assert.expect(9);
this.data.partner.records[0].p = [1, 2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2174,7 +2171,7 @@ QUnit.module('fields', {}, function () {
'<form string="Partner"><field name="display_name"/></form>',
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, 'td.o_list_record_remove button', 3,
"should have 3 remove buttons");
@@ -2182,28 +2179,28 @@ QUnit.module('fields', {}, function () {
assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-times',
"should have X icons to remove (unlink) records");
- testUtils.dom.click(form.$('td.o_list_record_remove button').first());
+ await testUtils.dom.click(form.$('td.o_list_record_remove button').first());
assert.containsN(form, 'td.o_list_record_remove button', 2,
"should have 2 remove buttons (a record is supposed to have been unlinked)");
- testUtils.dom.click(form.$('tr.o_data_row').first());
+ await testUtils.dom.click(form.$('tr.o_data_row').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'there should be a modal having Remove Button');
- testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
+ await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.containsOnce(form, 'td.o_list_record_remove button',
"should have 1 delete button (another record is supposed to have been unlinked)");
// save and check that the correct command has been generated
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many list: deleting two records', function (assert) {
+ QUnit.test('one2many list: deleting two records', async function (assert) {
assert.expect(9);
this.data.partner.records[0].p = [1, 2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2234,7 +2231,7 @@ QUnit.module('fields', {}, function () {
'<form string="Partner"><field name="display_name"/></form>',
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, 'td.o_list_record_remove button', 3,
"should have 3 remove buttons");
@@ -2242,21 +2239,21 @@ QUnit.module('fields', {}, function () {
assert.hasClass(form.$('td.o_list_record_remove button').first(),'fa fa-trash-o',
"should have trash bin icons to remove (delete) records");
- testUtils.dom.click(form.$('td.o_list_record_remove button').first());
+ await testUtils.dom.click(form.$('td.o_list_record_remove button').first());
assert.containsN(form, 'td.o_list_record_remove button', 2,
"should have 2 remove buttons (a record is supposed to have been deleted)");
- testUtils.dom.click(form.$('tr.o_data_row').first());
+ await testUtils.dom.click(form.$('tr.o_data_row').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'there should be a modal having Remove Button');
- testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
+ await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.containsOnce(form, 'td.o_list_record_remove button',
"should have 1 remove button (another record is supposed to have been deleted)");
// save and check that the correct command has been generated
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// FIXME: it would be nice to test that the view is re-rendered correctly,
// but as the relational data isn't re-fetched, the rendering is ok even
@@ -2264,11 +2261,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many kanban: edition', function (assert) {
+ QUnit.test('one2many kanban: edition', async function (assert) {
assert.expect(17);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2303,7 +2300,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_one2many .o-kanban-button-new').length,
'"Create" button should not be visible in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1,
'should contain 1 record');
@@ -2321,40 +2318,40 @@ QUnit.module('fields', {}, function () {
'Create button should have "Add" label');
// edit existing subrecord
- testUtils.dom.click(form.$('.oe_kanban_global_click'));
+ await testUtils.dom.click(form.$('.oe_kanban_global_click'));
- testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new name');
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new name');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_kanban_record span:first').text(), 'new name',
'value of subrecord should have been updated');
// create a new subrecord
- testUtils.dom.click(form.$('.o-kanban-button-new'));
- testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 1');
- testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
+ await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 1');
+ await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 2,
'should contain 2 records');
assert.strictEqual(form.$('.o_kanban_record:nth(1) span').text(), 'new subrecord 1',
'value of newly created subrecord should be "new subrecord 1"');
// create two new subrecords
- testUtils.dom.click(form.$('.o-kanban-button-new'));
- testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 2');
- testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)'));
- testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 3');
- testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
+ await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 2');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)'));
+ await testUtils.fields.editInput($('.modal .o_form_view input').first(), 'new subrecord 3');
+ await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 4,
'should contain 4 records');
// delete subrecords
- testUtils.dom.click(form.$('.oe_kanban_global_click').first());
+ await testUtils.dom.click(form.$('.oe_kanban_global_click').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'There should be a modal having Remove Button');
- testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
+ await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 3,
'should contain 3 records');
- testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()'));
- testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()'));
+ await testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()'));
+ await testUtils.dom.click(form.$('.o_kanban_view .delete_icon:first()'));
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1,
'should contain 1 records');
assert.strictEqual(form.$('.o_kanban_record span:first').text(), 'new subrecord 3',
@@ -2362,10 +2359,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many kanban (editable): properly handle create_text node option', function (assert) {
+ QUnit.test('one2many kanban (editable): properly handle create_text node option', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2385,19 +2382,19 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o-kanban-button-new').text().trim(),
"Add turtle", "In O2M Kanban, Add button should have 'Add turtle' label");
form.destroy();
});
- QUnit.test('one2many kanban: create action disabled', function (assert) {
+ QUnit.test('one2many kanban: create action disabled', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2422,7 +2419,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o-kanban-button-new').length,
'"Add" button should not be available in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(!form.$('.o-kanban-button-new').length,
'"Add" button should not be available in edit');
@@ -2431,13 +2428,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable one2many list, pager is updated', function (assert) {
+ QUnit.test('editable one2many list, pager is updated', async function (assert) {
assert.expect(1);
this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' });
this.data.partner.records[0].turtles = [1, 2, 3, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2452,21 +2449,21 @@ QUnit.module('fields', {}, function () {
});
// add a record, then click in form view to confirm it
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$el);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$el);
assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 5',
"pager should display the correct total");
form.destroy();
});
- QUnit.test('one2many list (non editable): edition', function (assert) {
+ QUnit.test('one2many list (non editable): edition', async function (assert) {
assert.expect(12);
var nbWrite = 0;
this.data.partner.records[0].p = [2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2497,7 +2494,7 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" should not be visible in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_list_view td.o_list_number', 2,
'should contain 2 records');
@@ -2509,10 +2506,10 @@ QUnit.module('fields', {}, function () {
'"Add an item" should not visible in edit');
// edit existing subrecord
- testUtils.dom.click(form.$('.o_list_view tbody tr:first() td:eq(1)'));
+ await testUtils.dom.click(form.$('.o_list_view tbody tr:first() td:eq(1)'));
- testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.fields.editInput($('.modal .o_form_view input'), 'new name');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name',
'value of subrecord should have been updated');
assert.strictEqual(nbWrite, 0, "should not have write anything in DB");
@@ -2521,23 +2518,23 @@ QUnit.module('fields', {}, function () {
// TODO when 'Add an item' will be implemented
// remove subrecords
- testUtils.dom.click(form.$('.o_list_record_remove:nth(1)'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:nth(1)'));
assert.containsOnce(form, '.o_list_view td.o_list_number',
'should contain 1 subrecord');
assert.strictEqual(form.$('.o_list_view tbody td:first()').text(), 'new name',
'the remaining subrecord should be "new name"');
- testUtils.form.clickSave(form); // save the record
+ await testUtils.form.clickSave(form); // save the record
assert.strictEqual(nbWrite, 1, "should have write the changes in DB");
form.destroy();
});
- QUnit.test('one2many list (editable): edition', function (assert) {
+ QUnit.test('one2many list (editable): edition', async function (assert) {
assert.expect(7);
this.data.partner.records[0].p = [2, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2557,25 +2554,25 @@ QUnit.module('fields', {}, function () {
assert.ok(!form.$('.o_field_x2many_list_row_add').length,
'"Add an item" link should not be available in readonly');
- testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
+ await testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
assert.ok($('.modal .o_form_readonly').length,
'in readonly, clicking on a subrecord should open it in readonly in a dialog');
- testUtils.dom.click($('.modal .o_form_button_cancel'));
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('.o_field_x2many_list_row_add').length,
'"Add an item" link should be available in edit');
// edit existing subrecord
- testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
+ await testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
assert.strictEqual($('.modal').length, 0,
'in edit, clicking on a subrecord should not open a dialog');
assert.hasClass(form.$('.o_list_view tbody tr:first()'),'o_selected_row',
'first row should be in edition');
- testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name');
+ await testUtils.fields.editInput(form.$('.o_list_view input:first()'), 'new name');
- testUtils.dom.click(form.$('.o_list_view tbody tr:nth(1) td:first'));
+ await testUtils.dom.click(form.$('.o_list_view tbody tr:nth(1) td:first'));
assert.doesNotHaveClass(form.$('.o_list_view tbody tr:first'), 'o_selected_row',
'first row should not be in edition anymore');
assert.strictEqual(form.$('.o_list_view tbody td:first').text(), 'new name',
@@ -2586,10 +2583,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list (editable): edition, part 2', function (assert) {
+ QUnit.test('one2many list (editable): edition, part 2', async function (assert) {
assert.expect(8);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2613,12 +2610,12 @@ QUnit.module('fields', {}, function () {
});
// edit mode, then click on Add an item and enter a value
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'kartoffel');
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'kartoffel');
// click again on Add an item
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('td:contains(kartoffel)').length, 1,
"should have one td with the new value");
assert.containsOnce(form, '.o_selected_row > td input',
@@ -2626,8 +2623,8 @@ QUnit.module('fields', {}, function () {
assert.containsN(form, 'tr.o_data_row', 2, "should have 2 data rows");
// enter another value and save
- testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'gemuse');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('.o_selected_row > td input'), 'gemuse');
+ await testUtils.form.clickSave(form);
assert.containsN(form, 'tr.o_data_row', 2, "should have 2 data rows");
assert.strictEqual(form.$('td:contains(kartoffel)').length, 1,
"should have one td with the new value");
@@ -2637,10 +2634,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list (editable): edition, part 3', function (assert) {
+ QUnit.test('one2many list (editable): edition, part 3', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2659,22 +2656,22 @@ QUnit.module('fields', {}, function () {
// edit mode, then click on Add an item 2 times
assert.containsOnce(form, 'tr.o_data_row',
"should have 1 data rows");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, 'tr.o_data_row', 3,
"should have 3 data rows");
// cancel the edition
- testUtils.form.clickDiscard(form);
- testUtils.dom.click($('.modal-footer button.btn-primary').first());
+ await testUtils.form.clickDiscard(form);
+ await testUtils.dom.click($('.modal-footer button.btn-primary').first());
assert.containsOnce(form, 'tr.o_data_row',
"should have 1 data rows");
form.destroy();
});
- QUnit.test('one2many list (editable): edition, part 4', function (assert) {
+ QUnit.test('one2many list (editable): edition, part 4', async function (assert) {
assert.expect(3);
var i = 0;
@@ -2687,7 +2684,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2707,26 +2704,26 @@ QUnit.module('fields', {}, function () {
// edit mode, then click on Add an item
assert.containsNone(form, 'tr.o_data_row',
"should have 0 data rows");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('textarea').val(), "",
"field turtle_description should be empty");
// add a value in the turtle_trululu field to trigger an onchange
- testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
- testUtils.fields.many2one.clickHighlightedItem('turtle_trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
+ await testUtils.fields.many2one.clickHighlightedItem('turtle_trululu');
assert.strictEqual(form.$('textarea').val(), "Some Description",
"field turtle_description should be set to the result of the onchange");
form.destroy();
});
- QUnit.test('one2many list (editable): discarding required empty data', function (assert) {
+ QUnit.test('one2many list (editable): discarding required empty data', async function (assert) {
assert.expect(7);
this.data.turtle.fields.turtle_foo.required = true;
delete this.data.turtle.fields.turtle_foo.default;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2751,15 +2748,15 @@ QUnit.module('fields', {}, function () {
// edit mode, then click on Add an item, then click elsewhere
assert.containsNone(form, 'tr.o_data_row',
"should have 0 data rows");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('label.o_form_label').first());
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('label.o_form_label').first());
assert.containsNone(form, 'tr.o_data_row',
"should still have 0 data rows");
// click on Add an item again, then click on save
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickSave(form);
assert.containsNone(form, 'tr.o_data_row',
"should still have 0 data rows");
@@ -2767,11 +2764,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable one2many list, adding line when only one page', function (assert) {
+ QUnit.test('editable one2many list, adding line when only one page', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [1, 2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2786,22 +2783,21 @@ QUnit.module('fields', {}, function () {
});
// add a record, to reach the page size limit
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
-
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// the record currently being added should not count in the pager
assert.isNotVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager'));
form.destroy();
});
- QUnit.test('editable one2many list, adding line, then discarding', function (assert) {
+ QUnit.test('editable one2many list, adding line, then discarding', async function (assert) {
assert.expect(2);
this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' });
this.data.partner.records[0].turtles = [1, 2, 3, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2816,12 +2812,12 @@ QUnit.module('fields', {}, function () {
});
// add a record, then discard
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickDiscard(form);
// confirm the discard operation
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.isVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager'));
assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4',
@@ -2830,14 +2826,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable one2many list, required field and pager', function (assert) {
+ QUnit.test('editable one2many list, required field and pager', async function (assert) {
assert.expect(1);
this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' });
this.data.turtle.fields.turtle_foo.required = true;
this.data.partner.records[0].turtles = [1, 2, 3, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2852,24 +2848,24 @@ QUnit.module('fields', {}, function () {
});
// add a (empty) record
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// go on next page. The new record is not valid and should be discarded
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
assert.containsOnce(form, 'tr.o_data_row');
form.destroy();
});
- QUnit.test('editable one2many list, required field, pager and confirm discard', function (assert) {
+ QUnit.test('editable one2many list, required field, pager and confirm discard', async function (assert) {
assert.expect(3);
this.data.turtle.records.push({ id: 4, turtle_foo: 'stephen hawking' });
this.data.turtle.fields.turtle_foo.required = true;
this.data.partner.records[0].turtles = [1, 2, 3, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2885,19 +2881,19 @@ QUnit.module('fields', {}, function () {
});
// add a record with a dirty state, but not valid
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('input[name="turtle_int"]'), 4321);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), 4321);
// go to next page. The new record is not valid, but dirty. we should
// see a confirm dialog
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4',
"pager should still display the correct total");
// click on cancel
- testUtils.dom.click($('.modal .modal-footer .btn-secondary'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-secondary'));
assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_cp_pager').text().trim(), '1-3 / 4',
"pager should again display the correct total");
@@ -2906,12 +2902,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable one2many list, adding, discarding, and pager', function (assert) {
+ QUnit.test('editable one2many list, adding, discarding, and pager', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2926,18 +2922,18 @@ QUnit.module('fields', {}, function () {
});
// add a 4 records record (to make the pager appear)
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// go on next page
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
// discard
- testUtils.form.clickDiscard(form);
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.form.clickDiscard(form);
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.containsOnce(form, 'tr.o_data_row');
assert.isNotVisible(form.$('.o_field_widget[name=turtles] .o_cp_pager'));
@@ -2945,13 +2941,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('unselecting a line with missing required data', function (assert) {
+ QUnit.test('unselecting a line with missing required data', async function (assert) {
assert.expect(5);
this.data.turtle.fields.turtle_foo.required = true;
delete this.data.turtle.fields.turtle_foo.default;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2971,40 +2967,40 @@ QUnit.module('fields', {}, function () {
// edit mode, then click on Add an item, then click elsewhere
assert.containsNone(form, 'tr.o_data_row',
"should have 0 data rows");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsOnce(form, 'tr.o_data_row',
"should have 1 data rows");
// adding a value in the non required field, so it is dirty, but with
// a missing required field
- testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '12345');
+ await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '12345');
// click elsewhere,
- testUtils.dom.click(form.$('label.o_form_label'));
+ await testUtils.dom.click(form.$('label.o_form_label'));
assert.strictEqual($('.modal').length, 1,
'a confirmation model should be opened');
// click on cancel, the line should still be selected
- testUtils.dom.click($('.modal .modal-footer button.btn-secondary'));
+ await testUtils.dom.click($('.modal .modal-footer button.btn-secondary'));
assert.containsOnce(form, 'tr.o_data_row.o_selected_row',
"should still have 1 selected data row");
// click elsewhere, and click on ok (on the confirmation dialog)
- testUtils.dom.click(form.$('label.o_form_label'));
- testUtils.dom.click($('.modal .modal-footer button.btn-primary'));
+ await testUtils.dom.click(form.$('label.o_form_label'));
+ await testUtils.dom.click($('.modal .modal-footer button.btn-primary'));
assert.containsNone(form, 'tr.o_data_row',
"should have 0 data rows (invalid line has been discarded");
form.destroy();
});
- QUnit.test('pressing enter in a o2m with a required empty field', function (assert) {
+ QUnit.test('pressing enter in a o2m with a required empty field', async function (assert) {
assert.expect(4);
this.data.turtle.fields.turtle_foo.required = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3025,19 +3021,16 @@ QUnit.module('fields', {}, function () {
});
// edit mode, then click on Add an item, then click elsewhere
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- form.$('input[name="turtle_foo"]').trigger($.Event('keydown', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'enter');
assert.hasClass(form.$('input[name="turtle_foo"]'),'o_field_invalid',
"input should be marked invalid");
assert.verifySteps(['read', 'default_get']);
form.destroy();
});
- QUnit.test('editing a o2m, with required field and onchange', function (assert) {
+ QUnit.test('editing a o2m, with required field and onchange', async function (assert) {
assert.expect(12);
this.data.turtle.fields.turtle_foo.required = true;
@@ -3048,7 +3041,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3074,16 +3067,16 @@ QUnit.module('fields', {}, function () {
// edit mode, then click on Add an item
assert.containsNone(form, 'tr.o_data_row',
"should have 0 data rows");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// input some text in required turtle_foo field
- testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'aubergine');
+ await testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'aubergine');
assert.strictEqual(form.$('input[name="turtle_int"]').val(), "9",
"onchange should have been triggered");
// save and check everything is fine
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_data_row td:contains(aubergine)').length, 1,
"should have one row with turtle_foo value");
assert.strictEqual(form.$('.o_data_row td:contains(9)').length, 1,
@@ -3093,10 +3086,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable o2m, pressing ESC discard current changes', function (assert) {
+ QUnit.test('editable o2m, pressing ESC discard current changes', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3114,24 +3107,24 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsOnce(form, 'tr.o_data_row',
"there should be one data row");
- form.$('input[name="turtle_foo"]').trigger({ type: 'keydown', which: $.ui.keyCode.ESCAPE });
+ await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'escape');
assert.containsNone(form, 'tr.o_data_row',
"data row should have been discarded");
assert.verifySteps(['read', 'default_get']);
form.destroy();
});
- QUnit.test('editable o2m with required field, pressing ESC discard current changes', function (assert) {
+ QUnit.test('editable o2m with required field, pressing ESC discard current changes', async function (assert) {
assert.expect(5);
this.data.turtle.fields.turtle_foo.required = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3149,22 +3142,22 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsOnce(form, 'tr.o_data_row',
"there should be one data row");
- form.$('input[name="turtle_foo"]').trigger({ type: 'keydown', which: $.ui.keyCode.ESCAPE });
+ await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'escape');
assert.containsNone(form, 'tr.o_data_row',
"data row should have been discarded");
assert.verifySteps(['read', 'default_get']);
form.destroy();
});
- QUnit.test('pressing escape in editable o2m list in dialog', function (assert) {
+ QUnit.test('pressing escape in editable o2m list in dialog', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3192,14 +3185,13 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_data_row.o_selected_row').length, 1,
"there should be a row in edition in the dialog");
- // trigger keydown ESCAPE in the edited row
- $('.modal .o_data_cell input').trigger({ type: 'keydown', which: $.ui.keyCode.ESCAPE });
+ await testUtils.fields.triggerKeydown($('.modal .o_data_cell input'), 'escape');
assert.strictEqual($('.modal').length, 1,
"dialog should still be open");
@@ -3209,7 +3201,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable o2m with onchange and required field: delete an invalid line', function (assert) {
+ QUnit.test('editable o2m with onchange and required field: delete an invalid line', async function (assert) {
assert.expect(5);
this.data.partner.onchanges = {
@@ -3218,7 +3210,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles = [1];
this.data.turtle.records[0].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3239,16 +3231,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_data_cell:first'));
+ await testUtils.dom.click(form.$('.o_data_cell:first'));
form.$('.o_field_widget[name="product_id"] input').val('').trigger('keyup');
assert.verifySteps(['read', 'read'], 'no onchange should be done as line is invalid');
- testUtils.dom.click(form.$('.o_list_record_remove'));
- assert.verifySteps(['read', 'read', 'onchange'], 'onchange should have been done');
+ await testUtils.dom.click(form.$('.o_list_record_remove'));
+ assert.verifySteps(['onchange'], 'onchange should have been done');
form.destroy();
});
- QUnit.test('onchange in a one2many', function (assert) {
+ QUnit.test('onchange in a one2many', async function (assert) {
assert.expect(1);
this.data.partner.records.push({
@@ -3258,7 +3250,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[1].p = [3];
this.data.partner.onchanges = { p: true };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3272,7 +3264,7 @@ QUnit.module('fields', {}, function () {
res_id: 2,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
p: [
[5], // delete all
@@ -3285,17 +3277,17 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_one2many tbody td').first());
- testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_one2many tbody td').first());
+ await testUtils.fields.editInput(form.$('.o_field_one2many tbody td').first().find('input'), "new value");
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_one2many tbody td').first().text(), 'from onchange',
"display name of first record in o2m list should be 'new value'");
form.destroy();
});
- QUnit.test('one2many, default_get and onchange (basic)', function (assert) {
+ QUnit.test('one2many, default_get and onchange (basic)', async function (assert) {
assert.expect(1);
this.data.partner.fields.p.default = [
@@ -3303,7 +3295,7 @@ QUnit.module('fields', {}, function () {
];
this.data.partner.onchanges = { p: true };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3316,7 +3308,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
p: [
[5], // delete all
@@ -3334,14 +3326,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many and default_get (with date)', function (assert) {
+ QUnit.test('one2many and default_get (with date)', async function (assert) {
assert.expect(1);
this.data.partner.fields.p.default = [
[0, false, { date: '2017-10-08' }],
];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3360,14 +3352,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many and onchange (with integer)', function (assert) {
+ QUnit.test('one2many and onchange (with integer)', async function (assert) {
assert.expect(4);
this.data.turtle.onchanges = {
- turtle_int: function (obj) { }
+ turtle_int: function () { }
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3384,10 +3376,10 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('td:contains(9)'));
- testUtils.fields.editInput(form.$('td input[name="turtle_int"]'), "3");
+ await testUtils.dom.click(form.$('td:contains(9)'));
+ await testUtils.fields.editInput(form.$('td input[name="turtle_int"]'), "3");
// the 'change' event is triggered on the input when we focus somewhere
// else, for example by clicking in the body. However, if we try to
@@ -3399,15 +3391,15 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many and onchange (with date)', function (assert) {
+ QUnit.test('one2many and onchange (with date)', async function (assert) {
assert.expect(7);
this.data.partner.onchanges = {
- date: function (obj) { }
+ date: function () { }
};
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3424,23 +3416,28 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
-
- testUtils.dom.click(form.$('td:contains(01/25/2017)'));
- testUtils.dom.click(form.$('.o_datepicker_input'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
- testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1));
- testUtils.dom.click($('.day:contains(22)'));
+ await testUtils.form.clickEdit(form);
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('td:contains(01/25/2017)'));
+ await testUtils.dom.click(form.$('.o_datepicker_input'));
+ await testUtils.nextTick();
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch').first());
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch:eq(1)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .year:contains(2017)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .month').eq(1));
+ await testUtils.dom.click($('.day:contains(22)'));
+ // trigger the blur of input before the click on Save, to closely mock what actually
+ // happens when we really click on Save
+ // this is required to close the datepicker before removing the input from the DOM
+ // (because of the re-rendering in readonly), otherwise tempusdominus crashes
+ await testUtils.dom.triggerEvents(form.$('.o_datepicker_input'), 'blur');
+ await testUtils.form.clickSave(form);
assert.verifySteps(['read', 'read', 'onchange', 'write', 'read', 'read']);
form.destroy();
});
- QUnit.test('one2many and onchange (with command DELETE_ALL)', function (assert) {
+ QUnit.test('one2many and onchange (with command DELETE_ALL)', async function (assert) {
assert.expect(5);
this.data.partner.onchanges = {
@@ -3451,7 +3448,7 @@ QUnit.module('fields', {}, function () {
};
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3482,34 +3479,34 @@ QUnit.module('fields', {}, function () {
"o2m should contain one row");
// empty o2m by triggering the onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange');
assert.containsNone(form, '.o_data_row',
"rows of the o2m should have been deleted");
// add two new subrecords
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'x');
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'y');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'x');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'y');
assert.containsN(form, '.o_data_row', 2,
"o2m should contain two rows");
// empty o2m by triggering the onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange again');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange again');
assert.containsNone(form, '.o_data_row',
"rows of the o2m should have been deleted");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'z');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'z');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many and onchange only write modified field', function (assert) {
+ QUnit.test('one2many and onchange only write modified field', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = {
@@ -3532,7 +3529,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles = [3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3567,14 +3564,14 @@ QUnit.module('fields', {}, function () {
assert.containsOnce(form, '.o_data_row',
"o2m should contain one row");
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first'));
- testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp');
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:first td:first'));
+ await testUtils.fields.editInput(form.$('.o_field_one2many .o_list_view tbody tr:first input:first'), 'blurp');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many with CREATE onchanges correctly refreshed', function (assert) {
+ QUnit.test('one2many with CREATE onchanges correctly refreshed', async function (assert) {
assert.expect(5);
var delta = 0;
@@ -3626,7 +3623,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3648,27 +3645,27 @@ QUnit.module('fields', {}, function () {
assert.containsNone(form, '.o_data_row',
"o2m shouldn't contain any row");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// trigger the first onchange
deactiveOnchange = false;
- testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '10');
+ await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '10');
// put the list back in non edit mode
- testUtils.dom.click(form.$('input[name="foo"]'));
+ await testUtils.dom.click(form.$('input[name="foo"]'));
assert.strictEqual(form.$('.o_data_row').text(), "first10second-10",
"should correctly refresh the records");
// trigger the second onchange
- testUtils.dom.click(form.$('.o_field_x2many_list tbody tr:first td:first'));
- testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '20');
+ await testUtils.dom.click(form.$('.o_field_x2many_list tbody tr:first td:first'));
+ await testUtils.fields.editInput(form.$('input[name="turtle_int"]'), '20');
- testUtils.dom.click(form.$('input[name="foo"]'));
+ await testUtils.dom.click(form.$('input[name="foo"]'));
assert.strictEqual(form.$('.o_data_row').text(), "first20second-20",
"should correctly refresh the records");
assert.containsN(form, '.o_field_widget', delta,
"all (non visible) field widgets should have been destroyed");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_data_row').text(), "first20second-20",
"should correctly refresh the records after save");
@@ -3677,7 +3674,7 @@ QUnit.module('fields', {}, function () {
testUtils.mock.unpatch(AbstractField);
});
- QUnit.test('editable one2many with sub widgets are rendered in readonly', function (assert) {
+ QUnit.test('editable one2many with sub widgets are rendered in readonly', async function (assert) {
assert.expect(2);
var editableWidgets = 0;
@@ -3690,7 +3687,7 @@ QUnit.module('fields', {}, function () {
},
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3710,7 +3707,7 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(editableWidgets, 1,
"o2m is only widget in edit mode");
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
assert.strictEqual(editableWidgets, 3,
"3 widgets currently in edit mode");
@@ -3719,7 +3716,7 @@ QUnit.module('fields', {}, function () {
testUtils.mock.unpatch(AbstractField);
});
- QUnit.test('one2many editable list with onchange keeps the order', function (assert) {
+ QUnit.test('one2many editable list with onchange keeps the order', async function (assert) {
assert.expect(2);
this.data.partner.records[0].p = [1, 2, 4];
@@ -3727,7 +3724,7 @@ QUnit.module('fields', {}, function () {
p: function () { },
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3747,9 +3744,9 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_data_cell').text(), 'first recordsecond recordaaa',
"records should be display in the correct order");
- testUtils.dom.click(form.$('.o_data_row:first .o_data_cell'));
- testUtils.fields.editInput(form.$('.o_selected_row .o_field_widget[name=display_name]'), 'new');
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$('.o_data_row:first .o_data_cell'));
+ await testUtils.fields.editInput(form.$('.o_selected_row .o_field_widget[name=display_name]'), 'new');
+ await testUtils.dom.click(form.$el);
assert.strictEqual(form.$('.o_data_cell').text(), 'newsecond recordaaa',
"records should be display in the correct order");
@@ -3757,14 +3754,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list (editable): readonly domain is evaluated', function (assert) {
+ QUnit.test('one2many list (editable): readonly domain is evaluated', async function (assert) {
assert.expect(2);
this.data.partner.records[0].p = [2, 4];
this.data.partner.records[1].product_id = false;
this.data.partner.records[2].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3779,7 +3776,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasClass(form.$('.o_list_view tbody tr:eq(0) td:first'),'o_readonly_modifier',
"first record should have display_name in readonly mode");
@@ -3789,12 +3786,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('pager of one2many field in new record', function (assert) {
+ QUnit.test('pager of one2many field in new record', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3811,7 +3808,7 @@ QUnit.module('fields', {}, function () {
'o2m pager should be hidden');
// click to create a subrecord
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
assert.containsOnce(form, 'tr.o_data_row');
assert.ok(!form.$('.o_x2m_control_panel .o_cp_pager div').is(':visible'),
@@ -3819,7 +3816,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list with a many2one', function (assert) {
+ QUnit.test('one2many list with a many2one', async function (assert) {
assert.expect(5);
this.data.partner.records[0].p = [2];
@@ -3833,7 +3830,7 @@ QUnit.module('fields', {}, function () {
//
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3863,14 +3860,14 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('tbody td:contains(xpad)').length, 0,
"should not display 'xpad' anywhere");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
- testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
testUtils.fields.many2one.clickItem('product_id', 'xpad');
- testUtils.dom.click($('.modal .modal-footer button:eq(0)'));
+ await testUtils.dom.click($('.modal .modal-footer button:eq(0)'));
assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1,
"should display 'xpad' on a td");
@@ -3879,14 +3876,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list with inline form view', function (assert) {
+ QUnit.test('one2many list with inline form view', async function (assert) {
assert.expect(5);
this.data.partner.records[0].p = [];
- var rpcCount = 0;
-
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3907,7 +3902,6 @@ QUnit.module('fields', {}, function () {
'</form>',
res_id: 1,
mockRPC: function (route, args) {
- rpcCount++;
if (args.method === 'write') {
assert.deepEqual(args.args[1].p, [[0, args.args[1].p[0][1], {
foo: false, int_field: 123, product_id: 41,
@@ -3917,63 +3911,63 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
// write in the many2one field, value = 37 (xphone)
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
// write in the integer field
- testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '123');
+ await testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '123');
// save and close
- testUtils.dom.click($('.modal .modal-footer button:eq(0)'));
+ await testUtils.dom.click($('.modal .modal-footer button:eq(0)'));
assert.strictEqual(form.$('tbody td:contains(xphone)').length, 1,
"should display 'xphone' in a td");
// reopen the record in form view
- testUtils.dom.click(form.$('tbody td:contains(xphone)'));
+ await testUtils.dom.click(form.$('tbody td:contains(xphone)'));
assert.strictEqual($('.modal .modal-body input').val(), "xphone",
"should display 'xphone' in an input");
- testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '456');
+ await testUtils.fields.editInput($('.modal .modal-body input.o_field_widget'), '456');
// discard
- testUtils.dom.click($('.modal .modal-footer span:contains(Discard)'));
+ await testUtils.dom.click($('.modal .modal-footer span:contains(Discard)'));
// reopen the record in form view
- testUtils.dom.click(form.$('tbody td:contains(xphone)'));
+ await testUtils.dom.click(form.$('tbody td:contains(xphone)'));
assert.strictEqual($('.modal .modal-body input.o_field_widget').val(), "123",
"should display 123 (previous change has been discarded)");
// write in the many2one field, value = 41 (xpad)
- testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
testUtils.fields.many2one.clickItem('product_id', 'xpad');
// save and close
- testUtils.dom.click($('.modal .modal-footer button:eq(0)'));
+ await testUtils.dom.click($('.modal .modal-footer button:eq(0)'));
assert.strictEqual(form.$('tbody td:contains(xpad)').length, 1,
"should display 'xpad' in a td");
// save the record
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many list with inline form view with context with parent key', function (assert) {
+ QUnit.test('one2many list with inline form view with context with parent key', async function (assert) {
assert.expect(2);
this.data.partner.records[0].p = [2];
this.data.partner.records[0].product_id = 41;
this.data.partner.records[1].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4001,23 +3995,23 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// open a modal
- testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)'));
+ await testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)'));
// write in the many2one field
- testUtils.dom.click($('.modal .o_field_many2one input'));
+ await testUtils.dom.click($('.modal .o_field_many2one input'));
form.destroy();
});
- QUnit.test('value of invisible x2many fields is correctly evaluated in context', function (assert) {
+ QUnit.test('value of invisible x2many fields is correctly evaluated in context', async function (assert) {
assert.expect(1);
this.data.partner.records[0].timmy = [12];
this.data.partner.records[0].p = [2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4040,19 +4034,19 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_widget[name=product_id] input'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_widget[name=product_id] input'));
form.destroy();
});
- QUnit.test('one2many list, editable, with many2one and with context with parent key', function (assert) {
+ QUnit.test('one2many list, editable, with many2one and with context with parent key', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
this.data.partner.records[1].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4074,23 +4068,23 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)'));
+ await testUtils.dom.click(form.$('tr.o_data_row:eq(0) td:contains(xphone)'));
// trigger a name search
- testUtils.dom.click(form.$('table td input'));
+ await testUtils.dom.click(form.$('table td input'));
form.destroy();
});
- QUnit.test('one2many list, editable, with a date in the context', function (assert) {
+ QUnit.test('one2many list, editable, with a date in the context', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
this.data.partner.records[1].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4114,18 +4108,18 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('one2many field with context', function (assert) {
+ QUnit.test('one2many field with context', async function (assert) {
assert.expect(2);
var counter = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4152,19 +4146,19 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'hammer');
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'hammer');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('one2many list edition, some basic functionality', function (assert) {
+ QUnit.test('one2many list edition, some basic functionality', async function (assert) {
assert.expect(3);
this.data.partner.fields.foo.default = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4177,30 +4171,30 @@ QUnit.module('fields', {}, function () {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
assert.containsOnce(form, 'td input.o_field_widget',
"should have created a row in edit mode");
- testUtils.fields.editInput(form.$('td input.o_field_widget'), 'a');
+ await testUtils.fields.editInput(form.$('td input.o_field_widget'), 'a');
assert.containsOnce(form, 'td input.o_field_widget',
"should not have unselected the row after edition");
- testUtils.fields.editInput(form.$('td input.o_field_widget'), 'abc');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('td input.o_field_widget'), 'abc');
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('td:contains(abc)').length, 1,
"should have a row with the correct value");
form.destroy();
});
- QUnit.test('one2many list, the context is properly evaluated and sent', function (assert) {
+ QUnit.test('one2many list, the context is properly evaluated and sent', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4223,15 +4217,15 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('one2many with many2many widget: create', function (assert) {
+ QUnit.test('one2many with many2many widget: create', async function (assert) {
assert.expect(10);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4271,28 +4265,28 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_data_row').length, 2,
"sould have 2 records in the select view (the last one is not displayed because it is already selected)");
- testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input'));
- testUtils.dom.click($('.modal .o_select_button'));
- testUtils.dom.click($('.o_form_button_save'));
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input'));
+ await testUtils.dom.click($('.modal .o_select_button'));
+ await testUtils.dom.click($('.o_form_button_save'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_data_row').length, 1,
"sould have 1 record in the select view");
- testUtils.dom.click($('.modal-footer button:eq(1)'));
- testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_foo"]'), 'tototo');
- testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_int"]'), 50);
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.dom.click($('.modal-footer button:eq(1)'));
+ await testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_foo"]'), 'tototo');
+ await testUtils.fields.editInput($('.modal input.o_field_widget[name="turtle_int"]'), 50);
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
- testUtils.dom.click($('.modal-footer button:contains(&):first'));
+ await testUtils.dom.click($('.modal-footer button:contains(&):first'));
assert.strictEqual($('.modal').length, 0, "sould close the modals");
@@ -4301,15 +4295,15 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_data_row').text(), "blip1.59yop1.50tototo1.550xphone",
"should display the record values in one2many list");
- testUtils.dom.click($('.o_form_button_save'));
+ await testUtils.dom.click($('.o_form_button_save'));
form.destroy();
});
- QUnit.test('one2many with many2many widget: edition', function (assert) {
+ QUnit.test('one2many with many2many widget: edition', async function (assert) {
assert.expect(7);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4351,44 +4345,44 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: one2many turtle field',
"modal should use the python field string as title");
- testUtils.dom.click($('.modal .o_form_button_cancel'));
- testUtils.form.clickEdit(form);
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
+ await testUtils.form.clickEdit(form);
// edit the first one2many record
- testUtils.dom.click(form.$('.o_data_row:first'));
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.dom.click($('.modal-footer button:first'));
- testUtils.dom.click($('.o_form_button_save'));
+ await testUtils.dom.click($('.o_form_button_save'));
// add a one2many record
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input'));
- testUtils.dom.click($('.modal .o_select_button'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_data_row:first .o_list_record_selector input'));
+ await testUtils.dom.click($('.modal .o_select_button'));
// edit the second one2many record
- testUtils.dom.click(form.$('.o_data_row:eq(1)'));
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.dom.click(form.$('.o_data_row:eq(1)'));
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.dom.click($('.modal-footer button:first'));
- testUtils.dom.click($('.o_form_button_save'));
+ await testUtils.dom.click($('.o_form_button_save'));
form.destroy();
});
- QUnit.test('new record, the context is properly evaluated and sent', function (assert) {
+ QUnit.test('new record, the context is properly evaluated and sent', async function (assert) {
assert.expect(2);
this.data.partner.fields.int_field.default = 17;
var n = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4413,15 +4407,15 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('parent data is properly sent on an onchange rpc', function (assert) {
+ QUnit.test('parent data is properly sent on an onchange rpc', async function (assert) {
assert.expect(1);
this.data.partner.onchanges = { bar: function () { } };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4444,16 +4438,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('parent data is properly sent on an onchange rpc, new record', function (assert) {
+ QUnit.test('parent data is properly sent on an onchange rpc, new record', async function (assert) {
assert.expect(6);
this.data.turtle.onchanges = { turtle_bar: function () { } };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4475,12 +4469,12 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
assert.verifySteps(['default_get', 'onchange', 'default_get', 'onchange']);
form.destroy();
});
- QUnit.test('id in one2many obtained in onchange is properly set', function (assert) {
+ QUnit.test('id in one2many obtained in onchange is properly set', async function (assert) {
assert.expect(1);
this.data.partner.onchanges.turtles = function (obj) {
@@ -4489,7 +4483,7 @@ QUnit.module('fields', {}, function () {
[1, 3, { turtle_foo: "kawa" }]
];
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4508,10 +4502,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('id field in one2many in a new record', function (assert) {
+ QUnit.test('id field in one2many in a new record', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4533,19 +4527,19 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.dom.click(form.$('td.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('td input[name="turtle_foo"]'), 'cat');
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('td.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('td input[name="turtle_foo"]'), 'cat');
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('sub form view with a required field', function (assert) {
+ QUnit.test('sub form view with a required field', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.required = true;
this.data.partner.fields.foo.default = null;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4562,9 +4556,9 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal-footer button.btn-primary').first());
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('tbody td.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal-footer button.btn-primary').first());
assert.strictEqual($('.modal').length, 1, "should still have an open modal");
assert.strictEqual($('.modal tbody label.o_field_invalid').length, 1,
@@ -4572,12 +4566,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list with action button', function (assert) {
+ QUnit.test('one2many list with action button', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4605,17 +4599,17 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_list_button button'));
+ await testUtils.dom.click(form.$('.o_list_button button'));
form.destroy();
});
- QUnit.test('one2many kanban with action button', function (assert) {
+ QUnit.test('one2many kanban with action button', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4649,12 +4643,12 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.oe_kanban_action_button'));
+ await testUtils.dom.click(form.$('.oe_kanban_action_button'));
form.destroy();
});
- QUnit.test('one2many kanban with edit type action and domain widget (widget using SpecialData)', function (assert) {
+ QUnit.test('one2many kanban with edit type action and domain widget (widget using SpecialData)', async function (assert) {
assert.expect(1);
this.data.turtle.fields.model_name = { string: "Domain Condition Model", type: "char" };
@@ -4664,7 +4658,7 @@ QUnit.module('fields', {}, function () {
record.condition = '[]';
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4694,12 +4688,12 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.dom.click(form.$('.oe_kanban_action:eq(0)'));
+ await testUtils.dom.click(form.$('.oe_kanban_action:eq(0)'));
assert.strictEqual($('.o_domain_selector').length, 1, "should add domain selector widget");
form.destroy();
});
- QUnit.test('one2many list with onchange and domain widget (widget using SpecialData)', function (assert) {
+ QUnit.test('one2many list with onchange and domain widget (widget using SpecialData)', async function (assert) {
assert.expect(3);
this.data.turtle.fields.model_name = { string: "Domain Condition Model", type: "char" };
@@ -4729,7 +4723,7 @@ QUnit.module('fields', {}, function () {
},
};
var nbFetchSpecialDomain = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4762,28 +4756,28 @@ QUnit.module('fields', {}, function () {
}
});
- testUtils.dom.click(form.$('.o_field_one2many .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_one2many .o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal').length, 1, "form view dialog should be opened");
- testUtils.fields.editInput($('.modal-body input[name="model_name"]'), 'partner');
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.fields.editInput($('.modal-body input[name="model_name"]'), 'partner');
+ await testUtils.dom.click($('.modal-footer button:first'));
assert.strictEqual(form.$('.o_field_one2many tbody tr:first').text(), "coucouhas changed[]",
"the onchange should create one new record and remove the existing");
- testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(0) td:first'));
+ await testUtils.dom.click(form.$('.o_field_one2many .o_list_view tbody tr:eq(0) td:first'));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(nbFetchSpecialDomain, 1,
"should only fetch special domain once");
form.destroy();
});
- QUnit.test('one2many without inline tree arch', function (assert) {
+ QUnit.test('one2many without inline tree arch', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4809,13 +4803,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('many2one and many2many in one2many', function (assert) {
+ QUnit.test('many2one and many2many in one2many', async function (assert) {
assert.expect(11);
this.data.turtle.records[1].product_id = 37;
this.data.partner.records[0].turtles = [2, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4862,46 +4856,46 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_data_row:first td:nth(2) .badge:first span').text(),
'second record', "m2m values should have been correctly fetched");
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal .o_field_widget').text(), "xphone",
'should display the form view dialog with the many2one value');
- testUtils.dom.click($('.modal-footer button'));
+ await testUtils.dom.click($('.modal-footer button'));
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// edit the m2m of first row
- testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
+ await testUtils.dom.click(form.$('.o_list_view tbody td:first()'));
// remove a tag
- testUtils.dom.click(form.$('.o_field_many2manytags .badge:contains(aaa) .o_delete'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .badge:contains(aaa) .o_delete'));
assert.strictEqual(form.$('.o_selected_row .o_field_many2manytags .o_badge_text:contains(aaa)').length, 0,
"tag should have been correctly removed");
// add a tag
- testUtils.fields.many2one.clickOpenDropdown('partner_ids');
- testUtils.fields.many2one.clickHighlightedItem('partner_ids');
+ await testUtils.fields.many2one.clickOpenDropdown('partner_ids');
+ await testUtils.fields.many2one.clickHighlightedItem('partner_ids');
assert.strictEqual(form.$('.o_selected_row .o_field_many2manytags .o_badge_text:contains(first record)').length, 1,
"tag should have been correctly added");
// edit the m2o of first row
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickItem('product_id', 'xpad');
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickItem('product_id', 'xpad');
assert.strictEqual(form.$('.o_selected_row .o_field_many2one:first input').val(), 'xpad',
"m2o value should have been updated");
// save (should correctly generate the commands)
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('many2manytag in one2many, onchange, some modifiers, and more than one page', function (assert) {
+ QUnit.test('many2manytag in one2many, onchange, some modifiers, and more than one page', async function (assert) {
assert.expect(9);
this.data.partner.records[0].turtles = [1, 2, 3];
this.data.partner.onchanges.turtles = function () { };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4922,8 +4916,8 @@ QUnit.module('fields', {}, function () {
});
assert.containsN(form, '.o_data_row', 2,
'there should be only 2 rows displayed');
- testUtils.dom.clickFirst(form.$('.o_list_record_remove'));
- testUtils.dom.clickFirst(form.$('.o_list_record_remove'));
+ await testUtils.dom.clickFirst(form.$('.o_list_record_remove'));
+ await testUtils.dom.clickFirst(form.$('.o_list_record_remove'));
assert.containsOnce(form, '.o_data_row',
'there should be just one remaining row');
@@ -4940,7 +4934,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange many2many in one2many list editable', function (assert) {
+ QUnit.test('onchange many2many in one2many list editable', async function (assert) {
assert.expect(14);
this.data.product.records.push({
@@ -4988,7 +4982,7 @@ QUnit.module('fields', {}, function () {
turtles: partnerOnchange,
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5007,11 +5001,11 @@ QUnit.module('fields', {}, function () {
});
// add new line (first, xpad)
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first');
- testUtils.dom.click(form.$('div[name="product_id"] input'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first');
+ await testUtils.dom.click(form.$('div[name="product_id"] input'));
// the onchange won't be generated
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
assert.containsOnce(form, '.o_field_many2manytags.o_input',
'should display the line in editable mode');
@@ -5020,7 +5014,7 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_field_many2manytags.o_input .o_badge_text').text(), "first record",
'should display the tag from the onchange');
- testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]'));
+ await testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]'));
assert.strictEqual(form.$('.o_data_cell.o_required_modifier').text(), "xpad",
'should display the product xpad');
@@ -5028,7 +5022,7 @@ QUnit.module('fields', {}, function () {
'should display the tag in readonly');
// enable the many2many onchange and generate it
- testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10');
+ await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10');
assert.strictEqual(form.$('.o_data_cell.o_required_modifier').text(), "xenomorphexphone",
'should display the product xphone and xenomorphe');
@@ -5036,21 +5030,21 @@ QUnit.module('fields', {}, function () {
'should display the name, one2many and many2many value');
// disable the many2many onchange
- testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '0');
+ await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '0');
// remove and start over
- testUtils.dom.click(form.$('.o_list_record_remove:first button'));
- testUtils.dom.click(form.$('.o_list_record_remove:first button'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:first button'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:first button'));
// enable the many2many onchange
- testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10');
+ await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10');
// add new line (first, xenomorphe)
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first');
- testUtils.dom.click(form.$('div[name="product_id"] input'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('input[name="display_name"]'), 'first');
+ await testUtils.dom.click(form.$('div[name="product_id"] input'));
// generate the onchange
- testUtils.dom.click($('li.ui-menu-item a:contains(xenomorphe)').trigger('mouseenter'));
+ await testUtils.dom.click($('li.ui-menu-item a:contains(xenomorphe)').trigger('mouseenter'));
assert.containsOnce(form, '.o_field_many2manytags.o_input',
'should display the line in editable mode');
@@ -5060,19 +5054,19 @@ QUnit.module('fields', {}, function () {
'should display the tag from the onchange');
// put list in readonly mode
- testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]'));
+ await testUtils.dom.click(form.$('input.o_field_integer[name="int_field"]'));
assert.strictEqual(form.$('.o_data_cell.o_required_modifier').text(), "xenomorphexphone",
'should display the product xphone and xenomorphe');
assert.strictEqual(form.$('.o_field_many2manytags:not(.o_input) .o_badge_text').text(), "second recordfirst record",
'should display the tag in readonly (first record and second record)');
- testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10');
+ await testUtils.fields.editInput(form.$('input.o_field_integer[name="int_field"]'), '10');
assert.strictEqual(form.$('.o_data_row').text().replace(/\s+/g, ' '), "firstxenomorphe second record new linexphone first record ",
'should display the name, one2many and many2many value');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_data_row').text().replace(/\s+/g, ' '), "firstxenomorphe second record new linexphone first record ",
'should display the name, one2many and many2many value after save');
@@ -5080,14 +5074,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('load view for x2many in one2many', function (assert) {
+ QUnit.test('load view for x2many in one2many', async function (assert) {
assert.expect(2);
this.data.turtle.records[1].product_id = 37;
this.data.partner.records[0].turtles = [2, 3];
this.data.partner.records[2].turtles = [1, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5116,7 +5110,7 @@ QUnit.module('fields', {}, function () {
assert.containsN(form, '.o_data_row', 2,
'should display the 2 turtles');
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal .o_field_widget[name="partner_ids"] .o_list_view').length, 1,
'should display many2many list view in the modal');
@@ -5124,12 +5118,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many (who contains a one2many) with tree view and without form view', function (assert) {
+ QUnit.test('one2many (who contains a one2many) with tree view and without form view', async function (assert) {
assert.expect(1);
// avoid error in _postprocess
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5148,7 +5142,7 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal .o_field_widget[name="turtle_foo"]').text(), 'blip',
'should open the modal and display the form field');
@@ -5156,7 +5150,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with x2many in form view (but not in list view)', function (assert) {
+ QUnit.test('one2many with x2many in form view (but not in list view)', async function (assert) {
assert.expect(1);
// avoid error when saving the edited related record (because the
@@ -5165,7 +5159,7 @@ QUnit.module('fields', {}, function () {
this.data.turtle.fields.o2m = { string: "o2m", type: "one2many", relation: 'user' };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5197,26 +5191,26 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_data_row:first')); // edit first record
+ await testUtils.dom.click(form.$('.o_data_row:first')); // edit first record
- testUtils.fields.many2one.clickOpenDropdown('partner_ids');
- testUtils.fields.many2one.clickHighlightedItem('partner_ids');
+ await testUtils.fields.many2one.clickOpenDropdown('partner_ids');
+ await testUtils.fields.many2one.clickHighlightedItem('partner_ids');
// add a many2many tag and save
- testUtils.dom.click($('.modal .o_field_many2manytags input'));
- testUtils.fields.editInput($('.modal .o_field_many2manytags input'), 'test');
- testUtils.dom.click($('.modal .modal-footer .btn-primary')); // save
+ await testUtils.dom.click($('.modal .o_field_many2manytags input'));
+ await testUtils.fields.editInput($('.modal .o_field_many2manytags input'), 'test');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary')); // save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('many2many list in a one2many opened by a many2one', function (assert) {
+ QUnit.test('many2many list in a one2many opened by a many2one', async function (assert) {
assert.expect(1);
this.data.turtle.records[1].turtle_trululu = 2;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5243,7 +5237,7 @@ QUnit.module('fields', {}, function () {
},
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/partner/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
if (args.method === 'write') {
assert.deepEqual(args.args[1].timmy, [[6, false, [12]]],
@@ -5254,27 +5248,27 @@ QUnit.module('fields', {}, function () {
});
// edit the first partner in the one2many partner form view
- testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell'));
+ await testUtils.dom.click(form.$('.o_data_row:first td.o_data_cell'));
// open form view for many2one
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
// click on add, to add a new partner in the m2m
- testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
// select the partner_type 'gold' (this closes the 2nd modal)
- testUtils.dom.click($('.modal td:contains(gold)'));
+ await testUtils.dom.click($('.modal td:contains(gold)'));
// confirm the changes in the modal
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('nested x2many default values', function (assert) {
+ QUnit.test('nested x2many default values', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5287,7 +5281,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.model === 'partner' && args.method === 'default_get') {
- return $.when({
+ return Promise.resolve({
turtles: [
[0, 0, { partner_ids: [[6, 0, [4]]] }],
[0, 0, { partner_ids: [[6, 0, [1]]] }],
@@ -5308,12 +5302,12 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many (who contains display_name) with tree view and without form view', function (assert) {
+ QUnit.test('one2many (who contains display_name) with tree view and without form view', async function (assert) {
assert.expect(1);
// avoid error in _fetchX2Manys
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5332,7 +5326,7 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal .o_field_widget[name="turtle_foo"]').text(), 'blip',
'should open the modal and display the form field');
@@ -5340,10 +5334,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many field with virtual ids', function (assert) {
+ QUnit.test('one2many field with virtual ids', async function (assert) {
assert.expect(11);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5387,13 +5381,13 @@ QUnit.module('fields', {}, function () {
"should not have kanban records yet");
// // switch to edit mode and create a new kanban record
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_widget .o-kanban-button-new'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_widget .o-kanban-button-new'));
// save & close the modal
assert.strictEqual($('.modal-content input.o_field_widget').val(), 'My little Foo Value',
"should already have the default value for field foo");
- testUtils.dom.click($('.modal-content .btn-primary').first());
+ await testUtils.dom.click($('.modal-content .btn-primary').first());
assert.containsOnce(form, '.o_field_widget .o_kanban_view',
"should have one inner kanban view for the one2many field");
@@ -5405,7 +5399,7 @@ QUnit.module('fields', {}, function () {
'My little Foo Value', "should have a value for the foo field");
// save the view to force a create of the new record in the one2many
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_field_widget .o_kanban_view',
"should have one inner kanban view for the one2many field");
assert.strictEqual(form.$('.o_field_widget .o_kanban_view .o_kanban_record:not(.o_kanban_ghost)').length, 1,
@@ -5418,10 +5412,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('focusing fields in one2many list', function (assert) {
+ QUnit.test('focusing fields in one2many list', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5438,23 +5432,23 @@ QUnit.module('fields', {}, function () {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_row:first td:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first td:first'));
assert.strictEqual(form.$('input[name="turtle_foo"]')[0], document.activeElement,
"turtle foo field should have focus");
- form.$('input[name="turtle_foo"]').trigger({ type: 'keydown', which: $.ui.keyCode.TAB });
+ await testUtils.fields.triggerKeydown(form.$('input[name="turtle_foo"]'), 'tab');
assert.strictEqual(form.$('input[name="turtle_int"]')[0], document.activeElement,
"turtle int field should have focus");
form.destroy();
});
- QUnit.test('one2many list editable = top', function (assert) {
+ QUnit.test('one2many list editable = top', async function (assert) {
assert.expect(6);
this.data.turtle.fields.turtle_foo.default = "default foo turtle";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5479,12 +5473,12 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_data_row',
"should start with one data row");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 2,
"should have 2 data rows");
@@ -5493,15 +5487,15 @@ QUnit.module('fields', {}, function () {
assert.hasClass(form.$('tr.o_data_row:first'),'o_selected_row',
"first row should be selected");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many list editable = bottom', function (assert) {
+ QUnit.test('one2many list editable = bottom', async function (assert) {
assert.expect(6);
this.data.turtle.fields.turtle_foo.default = "default foo turtle";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5526,12 +5520,12 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_data_row',
"should start with one data row");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 2,
"should have 2 data rows");
@@ -5540,14 +5534,14 @@ QUnit.module('fields', {}, function () {
assert.hasClass(form.$('tr.o_data_row:eq(1)'),'o_selected_row',
"second row should be selected");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('x2many fields use their "mode" attribute', function (assert) {
+ QUnit.test('x2many fields use their "mode" attribute', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5578,8 +5572,8 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list editable, no onchange when required field is not set', function (assert) {
- assert.expect(7);
+ QUnit.test('one2many list editable, no onchange when required field is not set', async function (assert) {
+ assert.expect(8);
this.data.turtle.fields.turtle_foo.required = true;
this.data.partner.onchanges = {
@@ -5590,7 +5584,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].int_field = 0;
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5609,28 +5603,29 @@ QUnit.module('fields', {}, function () {
},
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0",
"int_field should start with value 0");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0",
"int_field should still be 0 (no onchange should have been done yet");
assert.verifySteps(['read', 'default_get'], "no onchange should have been applied");
- testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text");
+ await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text");
+ assert.verifySteps(['onchange']);
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1",
"int_field should now be 1 (the onchange should have been done");
form.destroy();
});
- QUnit.test('one2many list editable: trigger onchange when row is valid', function (assert) {
+ QUnit.test('one2many list editable: trigger onchange when row is valid', async function (assert) {
// should omit require fields that aren't in the view as they (obviously)
// have no value, when checking the validity of required fields
// shouldn't consider numerical fields with value 0 as unset
- assert.expect(12);
+ assert.expect(13);
this.data.turtle.fields.turtle_foo.required = true;
this.data.turtle.fields.turtle_qux.required = true; // required field not in the view
@@ -5647,7 +5642,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].int_field = 0;
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5670,33 +5665,34 @@ QUnit.module('fields', {}, function () {
},
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0",
"int_field should start with value 0");
// add a new row (which is invalid at first)
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0",
"int_field should still be 0 (no onchange should have been done yet)");
assert.verifySteps(['load_views', 'read', 'default_get'], "no onchange should have been applied");
// fill turtle_foo field
- testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text");
+ await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text");
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "0",
"int_field should still be 0 (no onchange should have been done yet)");
- assert.verifySteps(['load_views', 'read', 'default_get'], "no onchange should have been applied");
+ assert.verifySteps([], "no onchange should have been applied");
// fill partner_ids field with a tag (all required fields will then be set)
- testUtils.fields.many2one.clickOpenDropdown('partner_ids');
- testUtils.fields.many2one.clickHighlightedItem('partner_ids');
+ await testUtils.fields.many2one.clickOpenDropdown('partner_ids');
+ await testUtils.fields.many2one.clickHighlightedItem('partner_ids');
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1",
"int_field should now be 1 (the onchange should have been done");
+ assert.verifySteps(['name_search', 'read', 'onchange']);
form.destroy();
});
- QUnit.test('one2many list editable: \'required\' modifiers is properly working', function (assert) {
+ QUnit.test('one2many list editable: \'required\' modifiers is properly working', async function (assert) {
assert.expect(3);
this.data.partner.onchanges = {
@@ -5707,7 +5703,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5721,18 +5717,18 @@ QUnit.module('fields', {}, function () {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10",
"int_field should start with value 10");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10",
"int_field should still be 10 (no onchange, because line is not valid)");
// fill turtle_foo field
- testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text");
+ await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_foo"]'), "some text");
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1",
"int_field should be 1 (onchange triggered, because line is now valid)");
@@ -5740,7 +5736,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list editable: \'required\' modifiers is properly working, part 2', function (assert) {
+ QUnit.test('one2many list editable: \'required\' modifiers is properly working, part 2', async function (assert) {
assert.expect(3);
this.data.partner.onchanges = {
@@ -5751,7 +5747,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5766,18 +5762,18 @@ QUnit.module('fields', {}, function () {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10",
"int_field should start with value 10");
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "10",
"int_field should still be 10 (no onchange, because line is not valid)");
// fill turtle_int field
- testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_int"]'), "1");
+ await testUtils.fields.editInput(form.$('.o_field_widget[name="turtle_int"]'), "1");
assert.strictEqual(form.$('.o_field_widget[name="int_field"]').val(), "1",
"int_field should be 1 (onchange triggered, because line is now valid)");
@@ -5785,7 +5781,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many list editable: add new line before onchange returns', function (assert) {
+ QUnit.test('one2many list editable: add new line before onchange returns', async function (assert) {
// If the user adds a new row (with a required field with onchange), selects
// a value for that field, then adds another row before the onchange returns,
// the editable list must wait for the onchange to return before trying to
@@ -5796,8 +5792,8 @@ QUnit.module('fields', {}, function () {
turtle_trululu: function () { },
};
- var def;
- var form = createView({
+ var prom;
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5811,23 +5807,23 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(prom).then(_.constant(result));
}
return result;
},
});
// add a first line but hold the onchange back
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ prom = testUtils.makeTestPromise();
assert.containsOnce(form, '.o_data_row',
"should have created the first row immediately");
- def = $.Deferred();
- testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
- testUtils.fields.many2one.clickHighlightedItem('turtle_trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
+ await testUtils.fields.many2one.clickHighlightedItem('turtle_trululu');
// try to add a second line and check that it is correctly waiting
// for the onchange to return
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal').length, 0, "no modal should be displayed");
assert.strictEqual($('.o_field_invalid').length, 0,
"no field should be marked as invalid");
@@ -5836,8 +5832,9 @@ QUnit.module('fields', {}, function () {
assert.hasClass(form.$('.o_data_row'),'o_selected_row',
"first row should still be in edition");
- // resolve the onchange def
- def.resolve();
+ // resolve the onchange promise
+ prom.resolve();
+ await testUtils.nextTick();
assert.containsN(form, '.o_data_row', 2,
"second row should now have been created");
assert.doesNotHaveClass(form.$('.o_data_row:first'), 'o_selected_row',
@@ -5846,15 +5843,15 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable list: multiple clicks on Add an item do not create invalid rows', function (assert) {
+ QUnit.test('editable list: multiple clicks on Add an item do not create invalid rows', async function (assert) {
assert.expect(3);
this.data.turtle.onchanges = {
turtle_trululu: function () { },
};
- var def;
- var form = createView({
+ var prom;
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5868,21 +5865,21 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(prom).then(_.constant(result));
}
return result;
},
});
-
+ prom = testUtils.makeTestPromise();
// click twice to add a new line
- def = $.Deferred();
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsNone(form, '.o_data_row',
"no row should have been created yet (waiting for the onchange)");
- // resolve the onchange def
- def.resolve();
+ // resolve the onchange promise
+ prom.resolve();
+ await testUtils.nextTick();
assert.containsOnce(form, '.o_data_row',
"only one row should have been created");
assert.hasClass(form.$('.o_data_row:first'),'o_selected_row',
@@ -5891,7 +5888,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable list: value reset by an onchange', function (assert) {
+ QUnit.test('editable list: value reset by an onchange', async function (assert) {
// this test reproduces a subtle behavior that may occur in a form view:
// the user adds a record in a one2many field, and directly clicks on a
// datetime field of the form view which has an onchange, which totally
@@ -5907,8 +5904,8 @@ QUnit.module('fields', {}, function () {
},
};
- var def;
- var form = createView({
+ var prom;
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5923,22 +5920,23 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(prom).then(_.constant(result));
}
return result;
},
});
// trigger the two onchanges
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_data_row .o_field_widget'), 'a name');
- def = $.Deferred();
- testUtils.dom.click(form.$('.o_datepicker_input'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_data_row .o_field_widget'), 'a name');
+ prom = testUtils.makeTestPromise();
+ await testUtils.dom.click(form.$('.o_datepicker_input'));
var dateTimeVal = fieldUtils.format.datetime(moment(), { timezone: false });
- testUtils.fields.editSelect(form.$('.o_datepicker_input'), dateTimeVal);
+ await testUtils.fields.editSelect(form.$('.o_datepicker_input'), dateTimeVal);
- // resolve the onchange def
- def.resolve();
+ // resolve the onchange promise
+ prom.resolve();
+ await testUtils.nextTick();
assert.containsOnce(form, '.o_data_row',
"should have one record in the o2m");
@@ -5948,14 +5946,14 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editable list: onchange that returns a warning', function (assert) {
+ QUnit.test('editable list: onchange that returns a warning', async function (assert) {
assert.expect(5);
this.data.turtle.onchanges = {
display_name: function () { },
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5970,7 +5968,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
if (args.method === 'onchange') {
assert.step(args.method);
- return $.when({
+ return Promise.resolve({
value: {},
warning: {
title: "Warning",
@@ -5991,22 +5989,22 @@ QUnit.module('fields', {}, function () {
});
// add a line (this should trigger an onchange and a warning)
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// check if 'Add an item' still works (this should trigger an onchange
// and a warning again)
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.verifySteps(['onchange', 'warning', 'onchange', 'warning']);
form.destroy();
});
- QUnit.test('editable list: contexts are correctly sent', function (assert) {
+ QUnit.test('editable list: contexts are correctly sent', async function (assert) {
assert.expect(5);
this.data.partner.records[0].timmy = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6051,14 +6049,14 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.dom.click(form.$('.o_data_cell:first'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'abc');
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_data_cell:first'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'abc');
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('resetting invisible one2manys', function (assert) {
+ QUnit.test('resetting invisible one2manys', async function (assert) {
assert.expect(3);
this.data.partner.records[0].turtles = [];
@@ -6066,7 +6064,7 @@ QUnit.module('fields', {}, function () {
obj.turtles = [[5], [4, 1]];
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6084,20 +6082,20 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.fields.editInput(form.$('input[name="foo"]'), 'abcd');
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), 'abcd');
assert.verifySteps(['read', 'onchange']);
form.destroy();
});
- QUnit.test('one2many: onchange that returns unknow field in list, but not in form', function (assert) {
+ QUnit.test('one2many: onchange that returns unknow field in list, but not in form', async function (assert) {
assert.expect(5);
this.data.partner.onchanges = {
name: function () { },
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6115,7 +6113,7 @@ QUnit.module('fields', {}, function () {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
p: [[5], [0, 0, { display_name: 'new', timmy: [[5], [4, 12]] }]],
},
@@ -6130,7 +6128,7 @@ QUnit.module('fields', {}, function () {
assert.containsNone(form, '.o_field_widget[name="timmy"]',
"timmy should not be displayed in the list view");
- testUtils.dom.click(form.$('.o_data_row td:first'));
+ await testUtils.dom.click(form.$('.o_data_row td:first'));
assert.strictEqual($('.modal .o_field_many2manytags[name="timmy"]').length, 1,
"timmy should be displayed in the form view");
@@ -6142,16 +6140,16 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange and required fields with override in arch', function (assert) {
+ QUnit.test('onchange and required fields with override in arch', async function (assert) {
assert.expect(4);
this.data.partner.onchanges = {
- turtles: function (obj) { }
+ turtles: function () { }
};
this.data.turtle.fields.turtle_foo.required = true;
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6169,16 +6167,16 @@ QUnit.module('fields', {}, function () {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// triggers an onchange on partner, because the new record is valid
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.verifySteps(['read', 'default_get', 'onchange']);
form.destroy();
});
- QUnit.test('onchange on a one2many containing a one2many', function (assert) {
+ QUnit.test('onchange on a one2many containing a one2many', async function (assert) {
// the purpose of this test is to ensure that the onchange specs are
// correctly and recursively computed
assert.expect(1);
@@ -6187,7 +6185,7 @@ QUnit.module('fields', {}, function () {
p: function () { }
};
var checkOnchange = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6211,16 +6209,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($('.modal .o_data_cell input'), 'new record');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($('.modal .o_data_cell input'), 'new record');
checkOnchange = true;
- testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
form.destroy();
});
- QUnit.test('editing tabbed one2many (editable=bottom)', function (assert) {
+ QUnit.test('editing tabbed one2many (editable=bottom)', async function (assert) {
assert.expect(12);
this.data.partner.records[0].turtles = [];
@@ -6230,7 +6228,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles.push(id);
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6255,14 +6253,14 @@ QUnit.module('fields', {}, function () {
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, 'tr.o_data_row', 41);
assert.hasClass(form.$('tr.o_data_row').last(), 'o_selected_row');
- testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
+ await testUtils.form.clickSave(form);
assert.containsN(form, 'tr.o_data_row', 40);
@@ -6270,7 +6268,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('editing tabbed one2many (editable=bottom), again...', function (assert) {
+ QUnit.test('editing tabbed one2many (editable=bottom), again...', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [];
@@ -6280,7 +6278,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles.push(id);
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6295,18 +6293,18 @@ QUnit.module('fields', {}, function () {
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
- testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
- testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_x2m_control_panel .o_pager_next'));
assert.containsN(form, 'tr.o_data_row', 3,
"should have 3 data rows on the current page");
form.destroy();
});
- QUnit.test('editing tabbed one2many (editable=top)', function (assert) {
+ QUnit.test('editing tabbed one2many (editable=top)', async function (assert) {
assert.expect(15);
this.data.partner.records[0].turtles = [];
@@ -6317,7 +6315,7 @@ QUnit.module('fields', {}, function () {
this.data.partner.records[0].turtles.push(id);
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6342,12 +6340,12 @@ QUnit.module('fields', {}, function () {
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
assert.containsN(form, 'tr.o_data_row', 2);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, 'tr.o_data_row', 3);
@@ -6356,8 +6354,8 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('tr.o_data_row input').val(), 'default foo',
"selected input should have correct string");
- testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('.o_data_row input[name="turtle_foo"]'), 'rainbow dash');
+ await testUtils.form.clickSave(form);
assert.containsN(form, 'tr.o_data_row', 40);
@@ -6365,8 +6363,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many field: change value before pending onchange returns', function (assert) {
- var done = assert.async();
+ QUnit.test('one2many field: change value before pending onchange returns', async function (assert) {
assert.expect(2);
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
@@ -6375,8 +6372,8 @@ QUnit.module('fields', {}, function () {
this.data.partner.onchanges = {
int_field: function () { }
};
- var def;
- var form = createView({
+ var prom;
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6392,42 +6389,41 @@ QUnit.module('fields', {}, function () {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
// delay the onchange RPC
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(prom).then(_.constant(result));
}
return result;
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- def = $.Deferred();
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), '44');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ prom = testUtils.makeTestPromise();
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), '44');
var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
// set trululu before onchange
- form.$('.o_field_many2one input').val('first').trigger('keydown').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one input'),
+ 'first', ['keydown', 'keyup']);
// complete the onchange
- def.resolve();
+ prom.resolve();
assert.strictEqual(form.$('.o_field_many2one input').val(), 'first',
'should have kept the new value');
- concurrency.delay(0).then(function () {
- // check name_search result
- assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 1,
- 'autocomplete should contains 1 suggestion');
+ await testUtils.nextTick();
+ // check name_search result
+ assert.strictEqual($dropdown.find('li:not(.o_m2o_dropdown_option)').length, 1,
+ 'autocomplete should contains 1 suggestion');
- relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
- form.destroy();
- done();
- });
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
+ form.destroy();
});
- QUnit.test('focus is correctly reset after an onchange in an x2many', function (assert) {
+ QUnit.test('focus is correctly reset after an onchange in an x2many', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = {
int_field: function () { }
};
- var def;
- var form = createView({
+ var prom;
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6445,37 +6441,38 @@ QUnit.module('fields', {}, function () {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
// delay the onchange RPC
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(prom).then(_.constant(result));
}
return result;
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- def = $.Deferred();
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ prom = testUtils.makeTestPromise();
testUtils.fields.editAndTrigger(form.$('.o_field_widget[name=int_field]'), '44',
['input', { type: 'keydown', which: $.ui.keyCode.TAB }]);
- def.resolve();
+ prom.resolve();
+ await testUtils.nextTick();
assert.strictEqual(document.activeElement, form.$('.o_field_widget[name=qux]')[0],
"qux field should have the focus");
- testUtils.fields.many2one.clickOpenDropdown('trululu');
- testUtils.fields.many2one.clickHighlightedItem('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickHighlightedItem('trululu');
assert.strictEqual(form.$('.o_field_many2one input').val(), 'first record',
"the one2many field should have the expected value");
form.destroy();
});
- QUnit.test('checkbox in an x2many that triggers an onchange', function (assert) {
+ QUnit.test('checkbox in an x2many that triggers an onchange', async function (assert) {
assert.expect(1);
this.data.partner.onchanges = {
bar: function () { }
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6488,23 +6485,23 @@ QUnit.module('fields', {}, function () {
'</form>',
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_widget[name=bar] input'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=bar] input'));
assert.notOk(form.$('.o_field_widget[name=bar] input').prop('checked'),
"the checkbox should be unticked");
form.destroy();
});
- QUnit.test('one2many with default value: edit line to make it invalid', function (assert) {
+ QUnit.test('one2many with default value: edit line to make it invalid', async function (assert) {
assert.expect(3);
this.data.partner.fields.p.default = [
[0, false, { foo: "coucou", int_field: 5 }],
];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6519,9 +6516,9 @@ QUnit.module('fields', {}, function () {
});
// edit the line and enter an invalid value for int_field
- testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(1)'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 'e');
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(1)'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 'e');
+ await testUtils.dom.click(form.$el);
assert.containsOnce(form, '.o_data_row.o_selected_row',
"line should not have been removed and should still be in edition");
@@ -6533,7 +6530,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('default value for nested one2manys (coming from onchange)', function (assert) {
+ QUnit.test('default value for nested one2manys (coming from onchange)', async function (assert) {
assert.expect(3);
this.data.partner.onchanges.p = function (obj) {
@@ -6543,7 +6540,7 @@ QUnit.module('fields', {}, function () {
];
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6568,17 +6565,17 @@ QUnit.module('fields', {}, function () {
assert.strictEqual(form.$('.o_data_cell').text(), '1 record',
"should correctly display the value of the inner o2m");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('display correct value after validation error', function (assert) {
+ QUnit.test('display correct value after validation error', async function (assert) {
assert.expect(4);
this.data.partner.onchanges.turtles = function () { };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6597,8 +6594,8 @@ QUnit.module('fields', {}, function () {
// we simulate a validation error. In the 'real' web client,
// the server error will be used by the session to display
// an error dialog. From the point of view of the basic
- // model, the deferred is just rejected.
- return $.Deferred().reject();
+ // model, the promise is just rejected.
+ return Promise.reject();
}
}
if (args.method === 'write') {
@@ -6615,31 +6612,31 @@ QUnit.module('fields', {}, function () {
"initial text should be correct");
// click and edit value to 'foo', which will trigger onchange
- testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'foo');
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'foo');
+ await testUtils.dom.click(form.$el);
assert.strictEqual(form.$('.o_data_row .o_data_cell:nth(0)').text(), 'foo',
"field should have been changed to foo");
// click and edit value to 'pinky', which trigger a failed onchange
- testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'pinky');
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$('.o_data_row .o_data_cell:nth(0)'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_foo]'), 'pinky');
+ await testUtils.dom.click(form.$el);
assert.strictEqual(form.$('.o_data_row .o_data_cell:nth(0)').text(), 'foo',
"turtle_foo text should now be set back to foo");
// we make sure here that when we save, the values are the current
// values displayed in the field.
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('propagate context to sub views', function (assert) {
+ QUnit.test('propagate context to sub views', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6659,14 +6656,14 @@ QUnit.module('fields', {}, function () {
},
viewOptions: { context: { flutter: 'shy' } },
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'pinky pie');
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('input[name="turtle_foo"]'), 'pinky pie');
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('onchange on nested one2manys', function (assert) {
+ QUnit.test('onchange on nested one2manys', async function (assert) {
assert.expect(6);
this.data.partner.onchanges.display_name = function (obj) {
@@ -6681,7 +6678,7 @@ QUnit.module('fields', {}, function () {
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6715,30 +6712,30 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'trigger onchange');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'trigger onchange');
assert.strictEqual(form.$('.o_data_cell').text(), 'test',
"should have added the new row to the one2many");
// open the new subrecord to check the value of the nested o2m, and to
// ensure that it will be saved
- testUtils.dom.click(form.$('.o_data_cell:first'));
+ await testUtils.dom.click(form.$('.o_data_cell:first'));
assert.strictEqual($('.modal .o_data_cell').text(), 'test nested',
"should have added the new row to the nested one2many");
- testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.clickFirst($('.modal .modal-footer .btn-primary'));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2many with multiple pages and sequence field', function (assert) {
+ QUnit.test('one2many with multiple pages and sequence field', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.partner.onchanges.turtles = function () { };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6754,7 +6751,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
turtles: [
[5],
@@ -6769,19 +6766,19 @@ QUnit.module('fields', {}, function () {
mode: 'edit',
},
});
- testUtils.dom.click(form.$('.o_list_record_remove:first button'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:first button'));
assert.strictEqual(form.$('.o_data_row').text(), 'from onchange',
'onchange has been properly applied');
form.destroy();
});
- QUnit.test('one2many with multiple pages and sequence field, part2', function (assert) {
+ QUnit.test('one2many with multiple pages and sequence field, part2', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.partner.onchanges.turtles = function () { };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6797,7 +6794,7 @@ QUnit.module('fields', {}, function () {
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
turtles: [
[5],
@@ -6813,20 +6810,20 @@ QUnit.module('fields', {}, function () {
mode: 'edit',
},
});
- testUtils.dom.click(form.$('.o_list_record_remove:first button'));
+ await testUtils.dom.click(form.$('.o_list_record_remove:first button'));
assert.strictEqual(form.$('.o_data_row').text(), 'from onchange id2from onchange id3',
'onchange has been properly applied');
form.destroy();
});
- QUnit.test('one2many with sequence field, override default_get, bottom when inline', function (assert) {
+ QUnit.test('one2many with sequence field, override default_get, bottom when inline', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.turtle.fields.turtle_int.default = 10;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6852,22 +6849,22 @@ QUnit.module('fields', {}, function () {
// check line is at the correct place
var inputText = 'ninja';
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText);
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText);
+ await testUtils.form.clickSave(form);
assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText);
form.destroy();
});
- QUnit.test('one2many with sequence field, override default_get, top when inline', function (assert) {
+ QUnit.test('one2many with sequence field, override default_get, top when inline', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.turtle.fields.turtle_int.default = 10;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6893,22 +6890,22 @@ QUnit.module('fields', {}, function () {
// check line is at the correct place
var inputText = 'ninja';
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText);
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText);
+ await testUtils.form.clickSave(form);
assert.strictEqual($('.o_data_cell').text(), inputText + "blipyopkawa");
form.destroy();
});
- QUnit.test('one2many with sequence field, override default_get, bottom when popup', function (assert) {
+ QUnit.test('one2many with sequence field, override default_get, bottom when popup', async function (assert) {
assert.expect(3);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.turtle.fields.turtle_int.default = 10;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6939,25 +6936,25 @@ QUnit.module('fields', {}, function () {
// check line is at the correct place
var inputText = 'ninja';
- testUtils.dom.click($('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($('.o_input[name="turtle_foo"]'), inputText);
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click($('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($('.o_input[name="turtle_foo"]'), inputText);
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText);
- testUtils.dom.click($('.o_form_button_save'));
+ await testUtils.dom.click($('.o_form_button_save'));
assert.strictEqual($('.o_data_cell').text(), "blipyopkawa" + inputText);
form.destroy();
});
- QUnit.test('one2many with sequence field, override default_get, not last page', function (assert) {
+ QUnit.test('one2many with sequence field, override default_get, not last page', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.turtle.fields.turtle_int.default = 10;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6979,19 +6976,19 @@ QUnit.module('fields', {}, function () {
// click add a new line
// check turtle_int for new is the current max of the page
- testUtils.dom.click($('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_input[name="turtle_int"]').val(), '10');
form.destroy();
});
- QUnit.test('one2many with sequence field, override default_get, last page', function (assert) {
+ QUnit.test('one2many with sequence field, override default_get, last page', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [3, 2, 1];
this.data.turtle.fields.turtle_int.default = 10;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7013,12 +7010,12 @@ QUnit.module('fields', {}, function () {
// click add a new line
// check turtle_int for new is the current max of the page +1
- testUtils.dom.click($('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .o_input[name="turtle_int"]').val(), '22');
form.destroy();
});
- QUnit.test('one2many with sequence field, fetch name_get from empty list, field text', function (assert) {
+ QUnit.test('one2many with sequence field, fetch name_get from empty list, field text', async function (assert) {
// There was a bug where a RPC would fail because no route was set.
// The scenario is:
// - create a new parent model, which has a one2many
@@ -7043,7 +7040,7 @@ QUnit.module('fields', {}, function () {
relation: 'product'
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7067,11 +7064,11 @@ QUnit.module('fields', {}, function () {
var inputText1 = 'relax';
var inputText2 = 'max';
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText1);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText2);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText1);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), inputText2);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.o_data_cell:nth-child(2)').text(), inputText1 + inputText2);
@@ -7079,7 +7076,7 @@ QUnit.module('fields', {}, function () {
assert.equal($handles.length, 3, 'There should be 3 sequence handlers');
- testUtils.dom.dragAndDrop($handles.eq(1),
+ await testUtils.dom.dragAndDrop($handles.eq(1),
form.$('tbody tr').first(),
{ position: 'top' }
);
@@ -7089,7 +7086,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with several pages, onchange and default order', function (assert) {
+ QUnit.test('one2many with several pages, onchange and default order', async function (assert) {
// This test reproduces a specific scenario where a one2many is displayed
// over several pages, and has a default order such that a record that
// would normally be on page 1 is actually on another page. Moreover,
@@ -7117,7 +7114,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: data,
@@ -7145,9 +7142,9 @@ QUnit.module('fields', {}, function () {
"should display two records out of three, in the correct order");
// edit turtle_int field of first row
- testUtils.dom.click(form.$('.o_data_cell:first'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_int]'), 3);
- testUtils.dom.click(form.$el);
+ await testUtils.dom.click(form.$('.o_data_cell:first'));
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=turtle_int]'), 3);
+ await testUtils.dom.click(form.$el);
assert.strictEqual(form.$('.o_data_cell.foo').text(), 'blipkawa',
"should still display the same two records");
@@ -7163,10 +7160,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('new record, with one2many with more default values than limit', function (assert) {
+ QUnit.test('new record, with one2many with more default values than limit', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7184,14 +7181,14 @@ QUnit.module('fields', {}, function () {
});
assert.strictEqual(form.$('.o_data_row').text(), 'yopblip',
'data has been properly loaded');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_data_row').text(), 'yopblip',
'data has been properly saved');
form.destroy();
});
- QUnit.test('add a new line after limit is reached should behave nicely', function (assert) {
+ QUnit.test('add a new line after limit is reached should behave nicely', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1, 2, 3];
@@ -7208,7 +7205,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7225,16 +7222,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsN(form, '.o_data_row', 4, 'should have 4 data rows');
- testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), 'a');
+ await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), 'a');
assert.containsN(form, '.o_data_row', 4,
'should still have 4 data rows (the limit is increased to 4)');
form.destroy();
});
- QUnit.test('onchange in a one2many with non inline view on an existing record', function (assert) {
+ QUnit.test('onchange in a one2many with non inline view on an existing record', async function (assert) {
assert.expect(6);
this.data.partner.fields.sequence = { string: 'Sequence', type: 'integer' };
@@ -7245,7 +7242,7 @@ QUnit.module('fields', {}, function () {
this.data.partner_type.fields.partner_ids = { string: "Partner", type: "one2many", relation: 'partner' };
this.data.partner_type.records[0].partner_ids = [1, 2];
- var form = testUtils.createView({
+ var form = await createView({
View: FormView,
model: 'partner_type',
data: this.data,
@@ -7265,13 +7262,13 @@ QUnit.module('fields', {}, function () {
});
// swap 2 lines in the one2many
- testUtils.dom.dragAndDrop(form.$('.ui-sortable-handle:eq(1)'), form.$('tbody tr').first(),
+ await testUtils.dom.dragAndDrop(form.$('.ui-sortable-handle:eq(1)'), form.$('tbody tr').first(),
{ position: 'top' });
assert.verifySteps(['load_views', 'read', 'read', 'onchange', 'onchange']);
form.destroy();
});
- QUnit.test('onchange in a one2many with non inline view on a new record', function (assert) {
+ QUnit.test('onchange in a one2many with non inline view on a new record', async function (assert) {
assert.expect(8);
this.data.turtle.onchanges = {
@@ -7282,7 +7279,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7300,8 +7297,8 @@ QUnit.module('fields', {}, function () {
});
// add a row and trigger the onchange
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_data_row .o_field_widget[name=display_name]'), 'a name');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_data_row .o_field_widget[name=display_name]'), 'a name');
assert.strictEqual(form.$('.o_data_row .o_field_widget[name=turtle_int]').val(), "44",
"should have triggered the onchange");
@@ -7318,10 +7315,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('add a line, edit it and "Save & New"', function (assert) {
+ QUnit.test('add a line, edit it and "Save & New"', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7337,27 +7334,27 @@ QUnit.module('fields', {}, function () {
"there should be no record in the relation");
// add a new record
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($('.modal .o_field_widget'), 'new record');
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($('.modal .o_field_widget'), 'new record');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual(form.$('.o_data_row .o_data_cell').text(), 'new record',
"should display the new record");
// reopen freshly added record and edit it
- testUtils.dom.click(form.$('.o_data_row .o_data_cell'));
- testUtils.fields.editInput($('.modal .o_field_widget'), 'new record edited');
+ await testUtils.dom.click(form.$('.o_data_row .o_data_cell'));
+ await testUtils.fields.editInput($('.modal .o_field_widget'), 'new record edited');
// save it, and choose to directly create another record
- testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:nth(1)'));
assert.strictEqual($('.modal').length, 1,
"the model should still be open");
assert.strictEqual($('.modal .o_field_widget').text(), '',
"should have cleared the input");
- testUtils.fields.editInput($('.modal .o_field_widget'), 'another new record');
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.fields.editInput($('.modal .o_field_widget'), 'another new record');
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual(form.$('.o_data_row .o_data_cell').text(),
'new record editedanother new record', "should display the two records");
@@ -7365,10 +7362,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('o2m add a line custom control create editable', function (assert) {
+ QUnit.test('o2m add a line custom control create editable', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7402,25 +7399,25 @@ QUnit.module('fields', {}, function () {
// click add food
// check it's empty
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)'));
assert.strictEqual($('.o_data_cell').text(), "");
// click add pizza
// save the modal
// check it's pizza
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)'));
// click add pasta
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)'));
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)'));
+ await testUtils.form.clickSave(form);
assert.strictEqual($('.o_data_cell').text(), "pizzapasta");
form.destroy();
});
- QUnit.test('o2m add a line custom control create non-editable', function (assert) {
+ QUnit.test('o2m add a line custom control create non-editable', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7454,31 +7451,31 @@ QUnit.module('fields', {}, function () {
// click add food
// check it's empty
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)'));
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(0)'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual($('.o_data_cell').text(), "");
// click add pizza
// save the modal
// check it's pizza
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)'));
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(1)'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual($('.o_data_cell').text(), "pizza");
// click add pasta
// save the whole record
// check it's pizzapasta
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)'));
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a:eq(2)'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual($('.o_data_cell').text(), "pizzapasta");
form.destroy();
});
- QUnit.test('o2m add a line custom control create align with handle', function (assert) {
+ QUnit.test('o2m add a line custom control create align with handle', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7501,7 +7498,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many form view with action button', function (assert) {
+ QUnit.test('one2many form view with action button', async function (assert) {
// once the action button is clicked, the record is reloaded (via the
// on_close handler, executed because the python method does not return
// any action, or an ir.action.act_window_close) ; this test ensures that
@@ -7512,7 +7509,7 @@ QUnit.module('fields', {}, function () {
var data = this.data;
data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: data,
@@ -7547,21 +7544,21 @@ QUnit.module('fields', {}, function () {
"initial display_name of o2m record should be correct");
// open one2many record in form view
- testUtils.dom.click(form.$('.o_data_cell:first'));
+ await testUtils.dom.click(form.$('.o_data_cell:first'));
assert.strictEqual($('.modal .o_form_view').length, 1,
"should have opened the form view in a dialog");
assert.strictEqual($('.modal .o_form_view .o_data_row').length, 0,
"there should be no record in the many2many");
// click on the action button
- testUtils.dom.click($('.modal .o_form_view button'));
+ await testUtils.dom.click($('.modal .o_form_view button'));
assert.strictEqual($('.modal .o_data_row').length, 1,
"fields in the o2m form view should have been read");
assert.strictEqual($('.modal .o_data_cell').text(), 'gold',
"many2many subrecord should have been fetched");
// save the dialog
- testUtils.dom.click($('.modal .modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_data_cell').text(), 'new name',
"fields in the o2m list view should have been read as well");
@@ -7569,7 +7566,7 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('onchange affecting inline unopened list view', function (assert) {
+ QUnit.test('onchange affecting inline unopened list view', async function (assert) {
// when we got onchange result for fields of record that were not
// already available because they were in a inline view not already
// opened, in a given configuration the change were applied ignoring
@@ -7605,7 +7602,7 @@ QUnit.module('fields', {}, function () {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'user',
data: this.data,
@@ -7627,42 +7624,42 @@ QUnit.module('fields', {}, function () {
});
// add a turtle on second partner
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_row:eq(1)'));
- testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_row:eq(1)'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
$('.modal input[name="display_name"]').val('michelangelo').change();
- testUtils.dom.click($('.modal .btn-primary'));
+ await testUtils.dom.click($('.modal .btn-primary'));
// open first partner so changes from previous action are applied
- testUtils.dom.click(form.$('.o_data_row:eq(0)'));
- testUtils.dom.click($('.modal .btn-primary'));
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_data_row:eq(0)'));
+ await testUtils.dom.click($('.modal .btn-primary'));
+ await testUtils.form.clickSave(form);
assert.strictEqual(numUserOnchange, 2,
'there should 2 and only 2 onchange from closing the partner modal');
- testUtils.dom.click(form.$('.o_data_row:eq(0)'));
+ await testUtils.dom.click(form.$('.o_data_row:eq(0)'));
assert.strictEqual($('.modal .o_data_row').length, 1,
'only 1 turtle for first partner');
assert.strictEqual($('.modal .o_data_row').text(), 'donatello',
'first partner turtle is donatello');
- testUtils.dom.click($('.modal .o_form_button_cancel'));
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
- testUtils.dom.click(form.$('.o_data_row:eq(1)'));
+ await testUtils.dom.click(form.$('.o_data_row:eq(1)'));
assert.strictEqual($('.modal .o_data_row').length, 1,
'only 1 turtle for second partner');
assert.strictEqual($('.modal .o_data_row').text(), 'michelangelo',
'second partner turtle is michelangelo');
- testUtils.dom.click($('.modal .o_form_button_cancel'));
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
form.destroy();
});
- QUnit.test('click on URL should not open the record', function (assert) {
+ QUnit.test('click on URL should not open the record', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7678,20 +7675,20 @@ QUnit.module('fields', {}, function () {
res_id: 1,
});
- testUtils.dom.click(form.$('.o_email_cell a'));
+ await testUtils.dom.click(form.$('.o_email_cell a'));
assert.strictEqual($('.modal .o_form_view').length, 0,
'click should not open the modal');
- testUtils.dom.click(form.$('.o_url_cell a'));
+ await testUtils.dom.click(form.$('.o_url_cell a'));
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) {
+ QUnit.test('create and edit on m2o in o2m, and press ESCAPE', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7707,21 +7704,18 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsOnce(form, '.o_selected_row',
"should have create a new row in edition");
- testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
- testUtils.fields.many2one.clickItem('turtle_trululu','Create and Edit...');
+ await testUtils.fields.many2one.clickOpenDropdown('turtle_trululu');
+ await testUtils.fields.many2one.clickItem('turtle_trululu','Create and Edit...');
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,
- }));
+ await testUtils.fields.triggerKeydown($('.modal .o_form_view .o_field_widget[name=display_name]'), 'escape');
assert.strictEqual($('.modal .o_form_view').length, 0,
"should have closed the dialog");
@@ -7731,13 +7725,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many add a line should not crash if orderedResIDs is not set', function (assert) {
+ QUnit.test('one2many add a line should not crash if orderedResIDs is not set', async function (assert) {
// There is no assertion, the code will just crash before the bugfix.
assert.expect(0);
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7761,16 +7755,16 @@ QUnit.module('fields', {}, function () {
},
});
- testUtils.dom.click($('button[name="action_invoice_open"]'));
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('button[name="action_invoice_open"]'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('one2many shortcut tab should not crash when there is no input widget', function (assert) {
+ QUnit.test('one2many shortcut tab should not crash when there is no input widget', async function (assert) {
assert.expect(2);
// create a one2many view which has no input (only 1 textarea in this case)
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7788,12 +7782,9 @@ QUnit.module('fields', {}, function () {
});
// add a row, fill it, then trigger the tab shortcut
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editAndTrigger(
- form.$('.o_input[name="turtle_foo"]'),
- 'ninja',
- ['input', $.Event('keydown', {which: $.ui.keyCode.TAB, keyCode: $.ui.keyCode.TAB,})]
- );
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_input[name="turtle_foo"]'), 'ninja');
+ await testUtils.fields.triggerKeydown(form.$('.o_input[name="turtle_foo"]'), 'tab');
assert.strictEqual(form.$('.o_field_text').text(), 'blipninja',
'current line should be saved');
@@ -7803,15 +7794,15 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with onchange, required field, shortcut enter', function (assert) {
+ QUnit.test('one2many with onchange, required field, shortcut enter', async function (assert) {
assert.expect(5);
this.data.turtle.onchanges = {
turtle_foo: function () { },
};
- var def;
- var form = createView({
+ var prom;
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7825,7 +7816,7 @@ QUnit.module('fields', {}, function () {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(prom).then(_.constant(result));
}
return result;
},
@@ -7837,20 +7828,15 @@ QUnit.module('fields', {}, function () {
var value = "hello";
// add a new line
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
// we want to add a delay to simulate an onchange
- def = $.Deferred();
+ prom = testUtils.makeTestPromise();
// write something in the field
var $input = form.$('input[name="turtle_foo"]');
- testUtils.fields.editInput($input, value);
-
- // trigger keydown ENTER
- $input.trigger($.Event('keydown', {
- keyCode: $.ui.keyCode.ENTER,
- which: $.ui.keyCode.ENTER,
- }));
+ await testUtils.fields.editInput($input, value);
+ await testUtils.fields.triggerKeydown($input, 'enter');
// check that nothing changed before the onchange finished
assert.strictEqual($input.val(), value, "input content shouldn't change");
@@ -7858,7 +7844,8 @@ QUnit.module('fields', {}, function () {
"should still contain only one row");
// unlock onchange
- def.resolve();
+ prom.resolve();
+ await testUtils.nextTick();
// check the current line is added with the correct content and a new line is editable
assert.strictEqual(form.$('td.o_data_cell').text(), value);
@@ -7869,13 +7856,13 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('no deadlock when leaving a one2many line with uncommitted changes', function (assert) {
+ QUnit.test('no deadlock when leaving a one2many line with uncommitted changes', async function (assert) {
// Before unselecting a o2m line, field widgets are asked to commit their changes (new values
// that they wouldn't have sent to the model yet). This test is added alongside a bug fix
// ensuring that we don't end up in a deadlock when a widget actually has some changes to
// commit at that moment.
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7895,13 +7882,13 @@ QUnit.module('fields', {}, function () {
fieldDebounce: 5000,
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=turtles] input'), 'some foo value');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=turtles] input'), 'some foo value');
// click to add a second row to unselect the current one, then save
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_form_readonly',
"form view should be in readonly");
@@ -7919,10 +7906,10 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many with extra field from server not in form', function (assert) {
+ QUnit.test('one2many with extra field from server not in form', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7948,20 +7935,20 @@ QUnit.module('fields', {}, function () {
}
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var x2mList = form.$('.o_field_x2many_list[name=p]');
// Add a record in the list
- testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
var modal = $('.modal-lg');
var nameInput = modal.find('input.o_input[name=display_name]');
- testUtils.fields.editInput(nameInput, 'michelangelo');
+ await testUtils.fields.editInput(nameInput, 'michelangelo');
// Save the record in the modal (though it is still virtual)
- testUtils.dom.click(modal.find('.btn-primary').first());
+ await testUtils.dom.click(modal.find('.btn-primary').first());
assert.equal(x2mList.find('.o_data_row').length, 1,
'There should be 1 records in the x2m list');
@@ -7974,7 +7961,7 @@ QUnit.module('fields', {}, function () {
'The display name field should have the right value');
// Save the whole thing
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
x2mList = form.$('.o_field_x2many_list[name=p]');
@@ -7992,11 +7979,11 @@ QUnit.module('fields', {}, function () {
form.destroy();
});
- QUnit.test('one2many invisible depends on parent field', function (assert) {
+ QUnit.test('one2many invisible depends on parent field', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -8022,21 +8009,22 @@ QUnit.module('fields', {}, function () {
});
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
+ await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
assert.containsOnce(form, 'th',
"should be 1 column when the product_id is set");
- form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
+ '', 'keyup');
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many when product_id is not set");
- testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
assert.containsOnce(form, 'th',
"should be 1 column after the value change");
form.destroy();
});
- QUnit.test('one2many column visiblity depends on onchange of parent field', function (assert) {
+ QUnit.test('one2many column visiblity depends on onchange of parent field', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [2];
@@ -8049,7 +8037,7 @@ QUnit.module('fields', {}, function () {
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -8070,24 +8058,24 @@ QUnit.module('fields', {}, function () {
"should be only 1 column ('foo') in the one2many");
assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// add a new o2m record
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.$('.o_field_one2many input:first').focus();
- testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line');
- testUtils.dom.click(form.$el);
+ await testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line');
+ await testUtils.dom.click(form.$el);
assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')");
form.destroy();
});
- QUnit.test('one2many column_invisible on view not inline', function (assert) {
+ QUnit.test('one2many column_invisible on view not inline', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -8114,24 +8102,25 @@ QUnit.module('fields', {}, function () {
});
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
+ await testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
assert.containsOnce(form, 'th',
"should be 1 column when the product_id is set");
- form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
+ '', 'keyup');
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many when product_id is not set");
- testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
assert.containsOnce(form, 'th',
"should be 1 column after the value change");
form.destroy();
});
- QUnit.test('field context is correctly passed to x2m subviews', function (assert) {
+ QUnit.test('field context is correctly passed to x2m subviews', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
diff --git a/addons/web/static/tests/fields/relational_fields_mobile_tests.js b/addons/web/static/tests/fields/relational_fields_mobile_tests.js
index 1f2b2655e02..794a8a89545 100644
--- a/addons/web/static/tests/fields/relational_fields_mobile_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_mobile_tests.js
@@ -52,11 +52,11 @@ QUnit.module('relational_fields', {
QUnit.module('FieldOne2Many');
- QUnit.test('one2many kanban: deletion in mobile', function (assert) {
+ QUnit.test('one2many kanban: deletion in mobile', async function (assert) {
assert.expect(9);
this.data.partner.records[0].p = [1, 2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -94,7 +94,7 @@ QUnit.module('relational_fields', {
assert.containsNone(form, '.o_field_one2many .o-kanban-button-new',
'"Create" button should not be visible in readonly');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_one2many .o-kanban-button-new',
'"Create" button should be visible in edit');
@@ -102,16 +102,16 @@ QUnit.module('relational_fields', {
"should have 2 records");
// open and delete record
- testUtils.dom.click(form.$('.oe_kanban_global_click').first());
+ await testUtils.dom.click(form.$('.oe_kanban_global_click').first());
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 1,
'there should be a Remove button in the modal footer');
- testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
+ await testUtils.dom.click($('.modal .modal-footer .o_btn_remove'));
assert.strictEqual($('.o_modal').length, 0, "there shoul be no more modal");
assert.strictEqual(form.$('.o_kanban_record:not(.o_kanban_ghost)').length, 1,
'should contain 1 records');
// save and check that the correct command has been generated
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
});
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index faf3df6f2e8..af64afbb9e4 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -1,7 +1,6 @@
odoo.define('web.relational_fields_tests', function (require) {
"use strict";
-var concurrency = require('web.concurrency');
var FormView = require('web.FormView');
var ListView = require('web.ListView');
var relationalFields = require('web.relational_fields');
@@ -147,10 +146,10 @@ QUnit.module('relational_fields', {
}]
},
};
- }
+ },
}, function () {
- QUnit.test('search more pager is reset when doing a new search', function (assert) {
+ QUnit.test('search more pager is reset when doing a new search', async function (assert) {
assert.expect(6);
for(var i = 10; i < 180; i++) {
this.data.partner.records.push({
@@ -159,17 +158,19 @@ QUnit.module('relational_fields', {
});
}
- function stringToEvent ($element, string) {
+ async function stringToEvent ($element, string) {
for (var i = 0; i < string.length; i++) {
var keyAscii = string.charCodeAt(i);
$element.val($element.val()+string[i]);
$element.trigger($.Event('keyup', {which: keyAscii, keyCode:keyAscii}));
+ await testUtils.nextTick();
}
$element.trigger($.Event('keyup', {which: $.ui.keyCode.ENTER, keyCode:$.ui.keyCode.ENTER}));
+ await testUtils.nextTick();
}
this.data.partner.fields.datetime.searchable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -187,17 +188,18 @@ QUnit.module('relational_fields', {
res_id: 1,
});
- form.$buttons.find('.o_form_button_edit').click();
- var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
- form.$('.o_field_many2one input').click();
- $dropdown.find('.o_m2o_dropdown_option:contains(Search)').mouseenter().click();
- $('.modal .o_pager_next').click();
+ await testUtils.form.clickEdit(form);
+
+
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickItem('trululu','Search');
+ await testUtils.dom.click($('.modal .o_pager_next'));
assert.strictEqual($('.o_pager_limit').text(), "1173", "there should be 173 records");
assert.strictEqual($('.o_pager_value').text(), "181-160", "should display the second page");
assert.strictEqual($('tr.o_data_row').length, 80, "should display 80 record");
- stringToEvent($('.modal .o_searchview_input'), 'first');
+ await stringToEvent($('.modal .o_searchview_input'), 'first');
assert.strictEqual($('.o_pager_limit').text(), "11", "there should be 1 record");
assert.strictEqual($('.o_pager_value').text(), "11-1", "should display the first page");
@@ -205,7 +207,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('do not call name_get if display_name already known', function (assert) {
+ QUnit.test('do not call name_get if display_name already known', async function (assert) {
// default_get only returns the id for many2one fields
// onchange returns an array with the id and the display_name
// thus, when an onchange is performed, there is no need to call
@@ -219,7 +221,7 @@ QUnit.module('relational_fields', {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -241,7 +243,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('x2many default_order multiple fields', function (assert) {
+ QUnit.test('x2many default_order multiple fields', async function (assert) {
assert.expect(7);
this.data.partner.records = [
@@ -256,7 +258,7 @@ QUnit.module('relational_fields', {
this.data.partner.records[0].p = [1, 7, 4, 5, 2, 6, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -284,7 +286,7 @@ QUnit.module('relational_fields', {
});
- QUnit.test('one2many from a model that has been sorted', function (assert) {
+ QUnit.test('one2many from a model that has been sorted', async function (assert) {
assert.expect(1);
/* On a standard list view, sort your records by a field
@@ -293,7 +295,7 @@ QUnit.module('relational_fields', {
*/
this.data.partner.records[0].turtles = [3, 2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -319,10 +321,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget many2many_checkboxes in a subview', function (assert) {
+ QUnit.test('widget many2many_checkboxes in a subview', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -347,19 +349,19 @@ QUnit.module('relational_fields', {
res_id: 1,
});
- form.$buttons.find('.o_form_button_edit').click();
- form.$('.o_data_cell').click();
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_cell'));
// edit the partner_ids field by (un)checking boxes on the widget
var $firstCheckbox = $('.modal .custom-control-input').first();
- $firstCheckbox.click();
+ await testUtils.dom.click($firstCheckbox);
assert.ok($firstCheckbox.prop('checked'), "the checkbox should be ticked");
var $secondCheckbox = $('.modal .custom-control-input').eq(1);
- $secondCheckbox.click();
+ await testUtils.dom.click($secondCheckbox);
assert.notOk($secondCheckbox.prop('checked'), "the checkbox should be unticked");
form.destroy();
});
- QUnit.test('delete a record while adding another one in a multipage', function (assert) {
+ QUnit.test('delete a record while adding another one in a multipage', async function (assert) {
// in a many2one with at least 2 pages, add a new line. Delete the line above it.
// (the onchange makes it so that the virtualID is inserted in the middle of the currentResIDs.)
// it should load the next line to display it on the page.
@@ -370,7 +372,7 @@ QUnit.module('relational_fields', {
obj.turtles = [[5]].concat(obj.turtles);
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -389,12 +391,12 @@ QUnit.module('relational_fields', {
res_id: 1,
});
- form.$buttons.find('.o_form_button_edit').click();
+ await testUtils.form.clickEdit(form);
// add a line (virtual record)
- form.$('.o_field_x2many_list_row_add a').click();
- form.$('.o_input').val('pi').trigger('input');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('.o_input'), 'pi');
// delete the line above it
- form.$('.o_list_record_remove').first().click();
+ await testUtils.dom.click(form.$('.o_list_record_remove').first());
// the next line should be displayed below the newly added one
assert.strictEqual(form.$('.o_data_row').length, 2, "should have 2 records");
assert.strictEqual(form.$('.o_data_row .o_data_cell:first-child').text(), 'pikawa',
@@ -403,7 +405,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('one2many, onchange, edition and multipage...', function (assert) {
+ QUnit.test('one2many, onchange, edition and multipage...', async function (assert) {
assert.expect(7);
this.data.partner.onchanges = {
@@ -414,7 +416,7 @@ QUnit.module('relational_fields', {
this.data.partner.records[0].turtles = [1,2,3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -434,8 +436,8 @@ QUnit.module('relational_fields', {
mode: 'edit',
},
});
- form.$('.o_field_x2many_list_row_add a').click();
- form.$('.o_field_x2many_list_row_add a').click();
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.verifySteps([
'read partner',
@@ -448,7 +450,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('onchange on unloaded record clearing posterious change', function (assert) {
+ QUnit.test('onchange on unloaded record clearing posterious change', async function (assert) {
// when we got onchange result for fields of record that were not
// already available because they were in a inline view not already
// opened, in a given configuration the change were applied ignoring
@@ -480,7 +482,7 @@ QUnit.module('relational_fields', {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'user',
data: this.data,
@@ -503,47 +505,48 @@ QUnit.module('relational_fields', {
});
// open first partner and change turtle name
- form.$buttons.find('.o_form_button_edit').click();
- form.$('.o_data_row:eq(0)').click();
- $('.modal .o_data_cell:eq(0)').click();
- $('.modal input[name="display_name"]').val('Donatello').change();
- $('.modal .btn-primary').click();
-
- // open second partner and add a turtle
- form.$('.o_data_row:eq(1)').click();
- $('.modal .o_field_x2many_list_row_add a').click();
- $('.modal input[name="display_name"]').val('Michelangelo').change();
- $('.modal .btn-primary').click();
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_row:eq(0)'));
+ await testUtils.dom.click($('.modal .o_data_cell:eq(0)'));
+ await testUtils.fields.editAndTrigger($('.modal input[name="display_name"]'),
+ 'Donatello', 'change');
+ await testUtils.dom.click($('.modal .btn-primary'));
+
+ await testUtils.dom.click(form.$('.o_data_row:eq(1)'));
+ await testUtils.dom.click($('.modal .o_field_x2many_list_row_add a'));
+ await testUtils.fields.editAndTrigger($('.modal input[name="display_name"]'),
+ 'Michelangelo', 'change');
+ await testUtils.dom.click($('.modal .btn-primary'));
assert.strictEqual(numUserOnchange, 2,
'there should 2 and only 2 onchange from closing the partner modal');
// check first record still has change
- form.$('.o_data_row:eq(0)').click();
+ await testUtils.dom.click(form.$('.o_data_row:eq(0)'));
assert.strictEqual($('.modal .o_data_row').length, 1,
'only 1 turtle for first partner');
assert.strictEqual($('.modal .o_data_row').text(), 'Donatello',
'first partner turtle is Donatello');
- $('.modal .o_form_button_cancel').click();
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
// check second record still has changes
- form.$('.o_data_row:eq(1)').click();
+ await testUtils.dom.click(form.$('.o_data_row:eq(1)'));
assert.strictEqual($('.modal .o_data_row').length, 1,
'only 1 turtle for second partner');
assert.strictEqual($('.modal .o_data_row').text(), 'Michelangelo',
'second partner turtle is Michelangelo');
- $('.modal .o_form_button_cancel').click();
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
form.destroy();
});
- QUnit.test('quickly switch between pages in one2many list', function (assert) {
+ QUnit.test('quickly switch between pages in one2many list', async function (assert) {
assert.expect(2);
this.data.partner.records[0].turtles = [1, 2, 3];
- var readDefs = [$.when(), $.Deferred(), $.Deferred()];
- var form = createView({
+ var readDefs = [Promise.resolve(), testUtils.makeTestPromise(), testUtils.makeTestPromise()];
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -558,34 +561,35 @@ QUnit.module('relational_fields', {
var result = this._super.apply(this, arguments);
if (args.method === 'read') {
var recordID = args.args[0][0];
- return $.when(readDefs[recordID - 1]).then(_.constant(result));
+ return Promise.resolve(readDefs[recordID - 1]).then(_.constant(result));
}
return result;
},
res_id: 1,
});
- form.$('.o_field_widget[name=turtles] .o_pager_next').click();
- form.$('.o_field_widget[name=turtles] .o_pager_next').click();
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=turtles] .o_pager_next'));
readDefs[1].resolve();
-
+ await testUtils.nextTick();
assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_data_cell').text(), 'donatello');
readDefs[2].resolve();
+ await testUtils.nextTick();
assert.strictEqual(form.$('.o_field_widget[name=turtles] .o_data_cell').text(), 'raphael');
form.destroy();
});
- QUnit.test('many2many read, field context is properly sent', function (assert) {
+ QUnit.test('many2many read, field context is properly sent', async function (assert) {
assert.expect(4);
this.data.partner.fields.timmy.context = {hello: 'world'};
this.data.partner.records[0].timmy = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -603,18 +607,20 @@ QUnit.module('relational_fields', {
assert.verifySteps(['world']);
- form.$buttons.find('.o_form_button_edit').click();
+ await testUtils.form.clickEdit(form);
var $m2mInput = form.$('.o_field_many2manytags input');
$m2mInput.click();
+ await testUtils.nextTick();
$m2mInput.autocomplete('widget').find('li:first()').click();
- assert.verifySteps(['world', 'world']);
+ await testUtils.nextTick();
+ assert.verifySteps(['world']);
form.destroy();
});
QUnit.module('FieldStatus');
- QUnit.test('static statusbar widget on many2one field', function (assert) {
+ QUnit.test('static statusbar widget on many2one field', async function (assert) {
assert.expect(5);
this.data.partner.fields.trululu.domain = "[('bar', '=', True)]";
@@ -622,7 +628,7 @@ QUnit.module('relational_fields', {
var count = 0;
var nb_fields_fetched;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -651,10 +657,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('static statusbar widget on many2one field with domain', function (assert) {
+ QUnit.test('static statusbar widget on many2one field with domain', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -675,10 +681,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('clickable statusbar widget on many2one field', function (assert) {
+ QUnit.test('clickable statusbar widget on many2one field', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -696,7 +702,7 @@ QUnit.module('relational_fields', {
assert.containsN(form, '.o_statusbar_status button.btn-secondary:not(.dropdown-toggle):not(:disabled)', 2);
var $clickable = form.$('.o_statusbar_status button.btn-secondary:not(.dropdown-toggle):not(:disabled)');
- testUtils.dom.click($clickable.last()); // (last is visually the first here (css))
+ await testUtils.dom.click($clickable.last()); // (last is visually the first here (css))
assert.hasClass(form.$('.o_statusbar_status button[data-value="1"]'), "btn-primary");
assert.hasClass(form.$('.o_statusbar_status button[data-value="1"]'), "disabled");
@@ -704,11 +710,11 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('statusbar with no status', function (assert) {
+ QUnit.test('statusbar with no status', async function (assert) {
assert.expect(2);
this.data.product.records = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -725,12 +731,12 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('statusbar with domain but no value (create mode)', function (assert) {
+ QUnit.test('statusbar with domain but no value (create mode)', async function (assert) {
assert.expect(1);
this.data.partner.fields.trululu.domain = "[('bar', '=', True)]";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -745,12 +751,12 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('clickable statusbar should change m2o fetching domain in edit mode', function (assert) {
+ QUnit.test('clickable statusbar should change m2o fetching domain in edit mode', async function (assert) {
assert.expect(2);
this.data.partner.fields.trululu.domain = "[('bar', '=', True)]";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -762,20 +768,20 @@ QUnit.module('relational_fields', {
config: {device: {isMobile: false}},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_statusbar_status button:not(.dropdown-toggle)', 3);
- testUtils.dom.click(form.$('.o_statusbar_status button:not(.dropdown-toggle)').last());
+ await testUtils.dom.click(form.$('.o_statusbar_status button:not(.dropdown-toggle)').last());
assert.containsN(form, '.o_statusbar_status button:not(.dropdown-toggle)', 2);
form.destroy();
});
- QUnit.test('statusbar fold_field option and statusbar_visible attribute', function (assert) {
+ QUnit.test('statusbar fold_field option and statusbar_visible attribute', async function (assert) {
assert.expect(2);
this.data.partner.records[0].bar = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -788,7 +794,7 @@ QUnit.module('relational_fields', {
config: {device: {isMobile: false}},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_statusbar_status:first .dropdown-menu button.disabled');
assert.containsOnce(form, '.o_statusbar_status:last button.disabled');
@@ -796,14 +802,14 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('statusbar with dynamic domain', function (assert) {
+ QUnit.test('statusbar with dynamic domain', async function (assert) {
assert.expect(5);
this.data.partner.fields.trululu.domain = "[('int_field', '>', qux)]";
this.data.partner.records[2].int_field = 0;
var rpcCount = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -823,14 +829,14 @@ QUnit.module('relational_fields', {
config: {device: {isMobile: false}},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_statusbar_status button.disabled', 3);
assert.strictEqual(rpcCount, 1, "should have done 1 search_read rpc");
- testUtils.fields.editInput(form.$('input[name=qux]'), 9.5);
+ await testUtils.fields.editInput(form.$('input[name=qux]'), 9.5);
assert.containsN(form, '.o_statusbar_status button.disabled', 2);
assert.strictEqual(rpcCount, 2, "should have done 1 more search_read rpc");
- testUtils.fields.editInput(form.$('input[name=qux]'), "hey");
+ await testUtils.fields.editInput(form.$('input[name=qux]'), "hey");
assert.strictEqual(rpcCount, 2, "should not have done 1 more search_read rpc");
form.destroy();
@@ -838,14 +844,14 @@ QUnit.module('relational_fields', {
QUnit.module('FieldSelection');
- QUnit.test('widget selection in a list view', function (assert) {
+ QUnit.test('widget selection in a list view', async function (assert) {
assert.expect(3);
this.data.partner.records.forEach(function (r) {
r.color = 'red';
});
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -856,7 +862,7 @@ QUnit.module('relational_fields', {
assert.strictEqual(list.$('td:contains(Red)').length, 3,
"should have 3 rows with correct value");
- testUtils.dom.click(list.$('td:contains(Red):first'));
+ await testUtils.dom.click(list.$('td:contains(Red):first'));
var $td = list.$('tbody tr.o_selected_row td:not(.o_list_record_selector)');
@@ -865,15 +871,15 @@ QUnit.module('relational_fields', {
list.destroy();
});
- QUnit.test('widget selection, edition and on many2one field', function (assert) {
- assert.expect(18);
+ QUnit.test('widget selection, edition and on many2one field', async function (assert) {
+ assert.expect(19);
this.data.partner.onchanges = {product_id: function () {}};
this.data.partner.records[0].product_id = 37;
this.data.partner.records[0].trululu = false;
var count = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -898,7 +904,7 @@ QUnit.module('relational_fields', {
assert.strictEqual(form.$('.o_field_widget[name=color]').text(), 'Red',
"should have rendered the selection field correctly");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form.$('.o_form_view'), 'select', 3);
assert.containsOnce(form, 'select[name="product_id"] option:contains(xphone)',
@@ -909,7 +915,7 @@ QUnit.module('relational_fields', {
"should have correct product_id value");
assert.strictEqual(form.$('select[name="trululu"]').val(), "false",
"should not have any value in trululu field");
- testUtils.fields.editSelect(form.$('select[name="product_id"]'), 41);
+ await testUtils.fields.editSelect(form.$('select[name="product_id"]'), 41);
assert.strictEqual(form.$('select[name="product_id"]').val(), "41",
"should have a value of xphone");
@@ -919,12 +925,14 @@ QUnit.module('relational_fields', {
assert.verifySteps(['read', 'name_search', 'name_search', 'onchange']);
count = 0;
- form.reload();
+ await form.reload();
assert.strictEqual(count, 1, "should not reload product_id relation");
+ assert.verifySteps(['read']);
+
form.destroy();
});
- QUnit.test('unset selection field with 0 as key', function (assert) {
+ QUnit.test('unset selection field with 0 as key', async function (assert) {
// The server doesn't make a distinction between false value (the field
// is unset), and selection 0, as in that case the value it returns is
// false. So the client must convert false to value 0 if it exists.
@@ -935,7 +943,7 @@ QUnit.module('relational_fields', {
selection: [[0, "Value O"], [1, "Value 1"]],
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -953,7 +961,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('unset selection field with string keys', function (assert) {
+ QUnit.test('unset selection field with string keys', async function (assert) {
// The server doesn't make a distinction between false value (the field
// is unset), and selection 0, as in that case the value it returns is
// false. So the client must convert false to value 0 if it exists. In
@@ -965,7 +973,7 @@ QUnit.module('relational_fields', {
selection: [['0', "Value O"], ['1', "Value 1"]],
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -983,10 +991,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('unset selection on a many2one field', function (assert) {
+ QUnit.test('unset selection on a many2one field', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1006,18 +1014,18 @@ QUnit.module('relational_fields', {
},
});
- testUtils.fields.editSelect(form.$('.o_form_view select'), 'false');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editSelect(form.$('.o_form_view select'), 'false');
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('field selection with many2ones and special characters', function (assert) {
+ QUnit.test('field selection with many2ones and special characters', async function (assert) {
assert.expect(1);
// edit the partner with id=4
this.data.partner.records[2].display_name = '<span>hey</span>';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1032,7 +1040,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget selection on a many2one: domain updated by an onchange', function (assert) {
+ QUnit.test('widget selection on a many2one: domain updated by an onchange', async function (assert) {
assert.expect(4);
this.data.partner.onchanges = {
@@ -1040,7 +1048,7 @@ QUnit.module('relational_fields', {
};
var domain = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1052,7 +1060,7 @@ QUnit.module('relational_fields', {
mockRPC: function (route, args) {
if (args.method === 'onchange') {
domain = [['id', 'in', [10]]];
- return $.when({
+ return Promise.resolve({
domain: {
trululu: domain,
}
@@ -1073,7 +1081,7 @@ QUnit.module('relational_fields', {
"should be 4 options in the selection");
// trigger an onchange that will update the domain
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
assert.containsOnce(form, '.o_field_widget[name=trululu] option',
"should be 1 option in the selection");
@@ -1081,7 +1089,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('required selection widget should not have blank option', function (assert) {
+ QUnit.test('required selection widget should not have blank option', async function (assert) {
assert.expect(3);
this.data.partner.fields.feedback_value = {
@@ -1091,7 +1099,7 @@ QUnit.module('relational_fields', {
default: 'good',
string: 'Good'
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1102,14 +1110,14 @@ QUnit.module('relational_fields', {
res_id: 1
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=color]')[0].options.length, 3,
"non required selection field must have 3 options 1 blank option and 2 value options");
assert.strictEqual(form.$('.o_field_widget[name=feedback_value]')[0].options.length, 2,
"should have only 2 options without blank option");
// change value to update widget modifier values
- testUtils.fields.editSelect(form.$('.o_field_widget[name=feedback_value]'), '"bad"');
+ await testUtils.fields.editSelect(form.$('.o_field_widget[name=feedback_value]'), '"bad"');
assert.strictEqual(form.$('.o_field_widget[name=color]')[0].options.length, 2,
"should have only 2 options");
@@ -1118,11 +1126,11 @@ QUnit.module('relational_fields', {
QUnit.module('FieldMany2ManyTags');
- QUnit.test('fieldmany2many tags with and without color', function (assert) {
+ QUnit.test('fieldmany2many tags with and without color', async function (assert) {
assert.expect(5);
this.data.partner.fields.partner_ids = {string: "Partner", type: "many2many", relation: 'partner'};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1141,29 +1149,29 @@ QUnit.module('relational_fields', {
});
// add a tag on field partner_ids
- testUtils.fields.many2one.clickOpenDropdown('partner_ids');
- testUtils.fields.many2one.clickHighlightedItem('partner_ids');
+ await testUtils.fields.many2one.clickOpenDropdown('partner_ids');
+ await testUtils.fields.many2one.clickHighlightedItem('partner_ids');
// add a tag on field timmy
- testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
var $input = form.$('.o_field_many2manytags[name="timmy"] input');
assert.strictEqual($input.autocomplete('widget').find('li').length, 3,
- "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')");
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ "autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')");
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
assert.containsOnce(form, '.o_field_many2manytags[name="timmy"] .badge',
"should contain 1 tag");
- assert.ok(form.$('.o_field_many2manytags[name="timmy"] .badge:contains("gold")').length,
+ assert.containsOnce(form, '.o_field_many2manytags[name="timmy"] .badge:contains("gold")',
"should contain newly added tag 'gold'");
form.destroy();
});
- QUnit.test('fieldmany2many tags with color: rendering and edition', function (assert) {
+ QUnit.test('fieldmany2many tags with color: rendering and edition', async function (assert) {
assert.expect(28);
this.data.partner.records[0].timmy = [12, 14];
this.data.partner_type.records.push({id: 13, display_name: "red", color: 8});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1194,7 +1202,7 @@ QUnit.module('relational_fields', {
assert.strictEqual(form.$('.badge:first()').data('color'), 2,
'should have correctly fetched the color');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 2,
"should still contain 2 tags in edit mode");
@@ -1205,12 +1213,12 @@ QUnit.module('relational_fields', {
// add an other existing tag
var $input = form.$('.o_field_many2manytags input');
- testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
assert.strictEqual($input.autocomplete('widget').find('li').length, 1,
"autocomplete dropdown should have 1 entry");
assert.strictEqual($input.autocomplete('widget').find('li a:contains("red")').length, 1,
"autocomplete dropdown should contain 'red'");
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 3,
"should contain 3 tags");
assert.ok(form.$('.o_field_many2manytags .badge .dropdown-toggle:contains("red")').length,
@@ -1219,34 +1227,34 @@ QUnit.module('relational_fields', {
"should have fetched the color of added tag");
// remove tag with id 14
- testUtils.dom.click(form.$('.o_field_many2manytags .badge[data-id=14] .o_delete'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .badge[data-id=14] .o_delete'));
assert.containsN(form, '.o_field_many2manytags .badge .dropdown-toggle', 2,
"should contain 2 tags");
assert.ok(!form.$('.o_field_many2manytags .badge .dropdown-toggle:contains("silver")').length,
"should not contain tag 'silver' anymore");
// save the record (should do the write RPC with the correct commands)
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// checkbox 'Hide in Kanban'
$input = form.$('.o_field_many2manytags .badge[data-id=13] .dropdown-toggle'); // selects 'red' tag
- testUtils.dom.click($input);
+ await testUtils.dom.click($input);
var $checkBox = form.$('.o_field_many2manytags .badge[data-id=13] .custom-checkbox input');
assert.strictEqual($checkBox.length, 1, "should have a checkbox in the colorpicker dropdown menu");
assert.notOk($checkBox.is(':checked'), "should have unticked checkbox in colorpicker dropdown menu");
- testUtils.fields.editAndTrigger($checkBox, null,['mouseenter','mousedown']);
+ await testUtils.fields.editAndTrigger($checkBox, null,['mouseenter','mousedown']);
$input = form.$('.o_field_many2manytags .badge[data-id=13] .dropdown-toggle'); // refresh
- testUtils.dom.click($input);
+ await testUtils.dom.click($input);
$checkBox = form.$('.o_field_many2manytags .badge[data-id=13] .custom-checkbox input'); // refresh
assert.equal($input.parent().data('color'), "0", "should become transparent when toggling on checkbox");
assert.ok($checkBox.is(':checked'), "should have a ticked checkbox in colorpicker dropdown menu after mousedown");
- testUtils.fields.editAndTrigger($checkBox, null,['mouseenter','mousedown']);
+ await testUtils.fields.editAndTrigger($checkBox, null,['mouseenter','mousedown']);
$input = form.$('.o_field_many2manytags .badge[data-id=13] .dropdown-toggle'); // refresh
- testUtils.dom.click($input);
+ await testUtils.dom.click($input);
$checkBox = form.$('.o_field_many2manytags .badge[data-id=13] .custom-checkbox input'); // refresh
assert.equal($input.parent().data('color'), "8", "should revert to old color when toggling off checkbox");
assert.notOk($checkBox.is(':checked'), "should have an unticked checkbox in colorpicker dropdown menu after 2nd click");
@@ -1257,14 +1265,14 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('fieldmany2many tags view a domain', function (assert) {
+ QUnit.test('fieldmany2many tags view a domain', async function (assert) {
assert.expect(7);
this.data.partner.fields.timmy.domain = [['id', '<', 50]];
this.data.partner.records[0].timmy = [12];
this.data.partner_type.records.push({id: 99, display_name: "red", color: 8});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1276,7 +1284,7 @@ QUnit.module('relational_fields', {
if (args.method === 'name_search') {
assert.deepEqual(args.kwargs.args, [['id', '<', 50], ['id', 'not in', [12]]],
"domain sent to name_search should be correct");
- return $.when([[14, 'silver']]);
+ return Promise.resolve([[14, 'silver']]);
}
return this._super.apply(this, arguments);
}
@@ -1286,16 +1294,16 @@ QUnit.module('relational_fields', {
assert.ok(form.$('.badge:contains(gold)').length,
'should have fetched and rendered gold partner tag');
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// add an other existing tag
var $input = form.$('.o_field_many2manytags input');
- testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
assert.strictEqual($input.autocomplete('widget').find('li').length, 1,
"autocomplete dropdown should have 1 entry");
assert.strictEqual($input.autocomplete('widget').find('li a:contains("silver")').length, 1,
"autocomplete dropdown should contain 'silver'");
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
assert.containsN(form, '.o_field_many2manytags .badge', 2,
"should contain 2 tags");
assert.ok(form.$('.o_field_many2manytags .badge:contains("silver")').length,
@@ -1304,10 +1312,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('fieldmany2many tags in a new record', function (assert) {
+ QUnit.test('fieldmany2many tags in a new record', async function (assert) {
assert.expect(7);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1326,10 +1334,10 @@ QUnit.module('relational_fields', {
});
assert.hasClass(form.$('.o_form_view'),'o_form_editable', "form should be in edit mode");
- testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
assert.strictEqual(form.$('.o_field_many2manytags input').autocomplete('widget').find('li').length, 3,
"autocomplete dropdown should have 3 entries (2 values + 'Search and Edit...')");
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
assert.containsOnce(form, '.o_field_many2manytags .badge',
"should contain 1 tag");
@@ -1337,18 +1345,18 @@ QUnit.module('relational_fields', {
"should contain newly added tag 'gold'");
// save the record (should do the write RPC with the correct commands)
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('fieldmany2many tags: update color', function (assert) {
+ QUnit.test('fieldmany2many tags: update color', async function (assert) {
assert.expect(5);
this.data.partner.records[0].timmy = [12, 14];
this.data.partner_type.records[0].color = 0;
var color;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1371,28 +1379,30 @@ QUnit.module('relational_fields', {
// Update the color in readonly
color = 1;
- testUtils.dom.click(form.$('.badge:first() .dropdown-toggle'));
- $('.o_colorpicker a[data-color="' + color + '"]').trigger('mousedown'); // choose color 1
+ await testUtils.dom.click(form.$('.badge:first() .dropdown-toggle'));
+ await testUtils.dom.triggerEvents($('.o_colorpicker a[data-color="' + color + '"]'), ['mousedown']);
+ await testUtils.nextTick();
assert.strictEqual(form.$('.badge:first()').data('color'), color,
'should have correctly updated the color (in readonly)');
// Update the color in edit
color = 6;
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.badge:first() .dropdown-toggle'));
- $('.o_colorpicker a[data-color="' + color + '"]').trigger('mousedown'); // choose color 6
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.badge:first() .dropdown-toggle'));
+ await testUtils.dom.triggerEvents($('.o_colorpicker a[data-color="' + color + '"]'), ['mousedown']); // choose color 6
+ await testUtils.nextTick();
assert.strictEqual(form.$('.badge:first()').data('color'), color,
'should have correctly updated the color (in edit)');
form.destroy();
});
- QUnit.test('fieldmany2many tags in editable list', function (assert) {
+ QUnit.test('fieldmany2many tags in editable list', async function (assert) {
assert.expect(7);
this.data.partner.records[0].timmy = [12];
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -1414,20 +1424,20 @@ QUnit.module('relational_fields', {
"m2m field should contain one tag");
// edit first row
- testUtils.dom.click(list.$('.o_data_row:first td:nth(2)'));
+ await testUtils.dom.click(list.$('.o_data_row:first td:nth(2)'));
var $m2o = list.$('.o_data_row:first .o_field_many2manytags .o_field_many2one');
assert.strictEqual($m2o.length, 1, "a many2one widget should have been instantiated");
// add a tag
- testUtils.fields.many2one.clickOpenDropdown('timmy');
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
assert.containsN(list, '.o_data_row:first .o_field_many2manytags .badge', 2,
"m2m field should contain 2 tags");
// leave edition
- testUtils.dom.click(list.$('.o_data_row:nth(1) td:nth(2)'));
+ await testUtils.dom.click(list.$('.o_data_row:nth(1) td:nth(2)'));
assert.containsN(list, '.o_data_row:first .o_field_many2manytags .badge', 2,
"m2m field should contain 2 tags");
@@ -1457,9 +1467,8 @@ QUnit.module('relational_fields', {
id: 10,
display_name: "Partner 9",
});
-
this.data.partner.fields.datetime.searchable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1482,23 +1491,23 @@ QUnit.module('relational_fields', {
mode: 'edit',
},
});
- testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
await testUtils.fields.many2one.clickItem('trululu', 'Search');
+ await testUtils.dom.click($('.modal .o_search_options .fa-bars'));
+ await testUtils.dom.click($('.modal .o_search_options .o_group_by_menu a:contains(Bar)'));
- testUtils.dom.click($('.modal .o_search_options .fa-bars'));
- testUtils.dom.click($('.modal .o_search_options .o_group_by_menu a:contains(Bar)'));
+ await testUtils.dom.click($('.modal .o_group_header:first'));
- testUtils.dom.click($('.modal .o_group_header:first'));
assert.strictEqual($('.modal tbody:nth(1) .o_data_row').length, 7,
"should display 7 records in the first page");
- testUtils.dom.click($('.modal .o_group_header:first .o_pager_next'));
+ await testUtils.dom.click($('.modal .o_group_header:first .o_pager_next'));
assert.strictEqual($('.modal tbody:nth(1) .o_data_row').length, 1,
"should display 1 record in the second page");
form.destroy();
});
- QUnit.test('many2many_tags can load more than 40 records', function (assert) {
+ QUnit.test('many2many_tags can load more than 40 records', async function (assert) {
assert.expect(1);
this.data.partner.fields.partner_ids = {string: "Partner", type: "many2many", relation: 'partner'};
@@ -1507,7 +1516,7 @@ QUnit.module('relational_fields', {
this.data.partner.records.push({id: i, display_name: 'walter' + i});
this.data.partner.records[0].partner_ids.push(i);
}
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1521,7 +1530,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('field many2many_tags keeps focus when being edited', function (assert) {
+ QUnit.test('field many2many_tags keeps focus when being edited', async function (assert) {
assert.expect(7);
this.data.partner.records[0].timmy = [12];
@@ -1529,7 +1538,7 @@ QUnit.module('relational_fields', {
obj.timmy = [[5]]; // DELETE command
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1540,22 +1549,22 @@ QUnit.module('relational_fields', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_many2manytags .badge',
"should contain one tag");
// update foo, which will trigger an onchange and update timmy
// -> m2mtags input should not have taken the focus
form.$('input[name=foo]').focus();
- testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger onchange');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger onchange');
assert.containsNone(form, '.o_field_many2manytags .badge',
"should contain no tags");
assert.strictEqual(form.$('input[name=foo]').get(0), document.activeElement,
"foo input should have kept the focus");
// add a tag -> m2mtags input should still have the focus
- testUtils.fields.many2one.clickOpenDropdown('timmy');
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
assert.containsOnce(form, '.o_field_many2manytags .badge',
@@ -1564,7 +1573,7 @@ QUnit.module('relational_fields', {
"m2m tags input should have kept the focus");
// remove a tag -> m2mtags input should still have the focus
- testUtils.dom.click(form.$('.o_field_many2manytags .o_delete'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .o_delete'));
assert.containsNone(form, '.o_field_many2manytags .badge',
"should contain no tags");
assert.strictEqual(form.$('.o_field_many2manytags input').get(0), document.activeElement,
@@ -1573,11 +1582,11 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget many2many_tags in one2many with display_name', function (assert) {
+ QUnit.test('widget many2many_tags in one2many with display_name', async function (assert) {
assert.expect(4);
this.data.turtle.records[0].partner_ids = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1605,26 +1614,26 @@ QUnit.module('relational_fields', {
"secondrecordaaa", "the tags should be correctly rendered");
// open the x2m form view
- form.$('.o_field_one2many[name="turtles"] .o_list_view td.o_data_cell:first').click();
+ await testUtils.dom.click(form.$('.o_field_one2many[name="turtles"] .o_list_view td.o_data_cell:first'));
assert.strictEqual($('.modal .o_form_view .o_field_many2many[name="partner_ids"] .o_list_view .o_data_cell').text(),
"blipMy little Foo Value", "the list view should be correctly rendered with foo");
- $('.modal button.o_form_button_cancel').click();
+ await testUtils.dom.click($('.modal button.o_form_button_cancel'));
assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o_list_view .o_field_many2manytags[name="partner_ids"]').text().replace(/\s/g, ''),
"secondrecordaaa", "the tags should still be correctly rendered");
- form.$buttons.find('.o_form_button_edit').click();
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_one2many[name="turtles"] .o_list_view .o_field_many2manytags[name="partner_ids"]').text().replace(/\s/g, ''),
"secondrecordaaa", "the tags should still be correctly rendered");
form.destroy();
});
- QUnit.test('widget many2many_tags: tags title attribute', function (assert) {
+ QUnit.test('widget many2many_tags: tags title attribute', async function (assert) {
assert.expect(1);
this.data.turtle.records[0].partner_ids = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'turtle',
data: this.data,
@@ -1645,13 +1654,13 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget many2many_tags: toggle colorpicker multiple times', function (assert) {
+ QUnit.test('widget many2many_tags: toggle colorpicker multiple times', async function (assert) {
assert.expect(11);
this.data.partner.records[0].timmy = [12];
this.data.partner_type.records[0].color = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1672,13 +1681,13 @@ QUnit.module('relational_fields', {
"colorpicker should be closed");
// click on the badge to open colorpicker
- testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
assert.strictEqual($('.o_colorpicker:visible').length, 1,
"colorpicker should be open");
// click on the badge again to close colorpicker
- testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
assert.strictEqual($('.o_field_many2manytags .badge').data('color'), 0,
"tag should still have color 0");
@@ -1686,13 +1695,13 @@ QUnit.module('relational_fields', {
"colorpicker should be closed");
// click on the badge to open colorpicker
- testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
assert.strictEqual($('.o_colorpicker:visible').length, 1,
"colorpicker should be open");
// click on the colorpicker, but not on a color
- testUtils.dom.click(form.$('.o_colorpicker'));
+ await testUtils.dom.click(form.$('.o_colorpicker'));
assert.strictEqual($('.o_field_many2manytags .badge').data('color'), 0,
"tag should still have color 0");
@@ -1700,10 +1709,10 @@ QUnit.module('relational_fields', {
"colorpicker should be closed");
// click on the badge to open colorpicker
- testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
+ await testUtils.dom.click(form.$('.o_field_many2manytags .badge .dropdown-toggle'));
// click on a color in the colorpicker
- form.$('.o_colorpicker .o_tag_color_2').trigger('mousedown');
+ await testUtils.dom.triggerEvents(form.$('.o_colorpicker .o_tag_color_2'),['mousedown']);
assert.strictEqual($('.o_field_many2manytags .badge').data('color'), 2,
"tag should have color 2");
@@ -1715,10 +1724,10 @@ QUnit.module('relational_fields', {
QUnit.module('FieldRadio');
- QUnit.test('fieldradio widget on a many2one in a new record', function (assert) {
+ QUnit.test('fieldradio widget on a many2one in a new record', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1732,18 +1741,18 @@ QUnit.module('relational_fields', {
assert.ok(form.$('label.o_form_label:contains(xphone)').length, "one of them should be xphone");
assert.containsNone(form, 'input:checked', "none of the input should be checked");
- testUtils.dom.click(form.$("input.o_radio_input:first"));
+ await testUtils.dom.click(form.$("input.o_radio_input:first"));
assert.containsOnce(form, 'input:checked', "one of the input should be checked");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
var newRecord = _.last(this.data.partner.records);
assert.strictEqual(newRecord.product_id, 37, "should have saved record with correct value");
form.destroy();
});
- QUnit.test('fieldradio change value by onchange', function (assert) {
+ QUnit.test('fieldradio change value by onchange', async function (assert) {
assert.expect(4);
this.data.partner.onchanges = {bar: function (obj) {
@@ -1751,7 +1760,7 @@ QUnit.module('relational_fields', {
obj.color = obj.bar ? 'red' : 'black';
}};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1762,20 +1771,20 @@ QUnit.module('relational_fields', {
'</form>',
});
- testUtils.dom.click(form.$("input[type='checkbox']"));
+ await testUtils.dom.click(form.$("input[type='checkbox']"));
assert.containsOnce(form, 'input.o_radio_input[data-value="37"]:checked', "one of the input should be checked");
assert.containsOnce(form, 'input.o_radio_input[data-value="black"]:checked', "the other of the input should be checked");
- testUtils.dom.click(form.$("input[type='checkbox']"));
+ await testUtils.dom.click(form.$("input[type='checkbox']"));
assert.containsOnce(form, 'input.o_radio_input[data-value="41"]:checked', "the other of the input should be checked");
assert.containsOnce(form, 'input.o_radio_input[data-value="red"]:checked', "one of the input should be checked");
form.destroy();
});
- QUnit.test('fieldradio widget on a selection in a new record', function (assert) {
+ QUnit.test('fieldradio widget on a selection in a new record', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1790,21 +1799,21 @@ QUnit.module('relational_fields', {
assert.ok(form.$('label.o_form_label:contains(Red)').length, "one of them should be Red");
// click on 2nd option
- testUtils.dom.click(form.$("input.o_radio_input").eq(1));
+ await testUtils.dom.click(form.$("input.o_radio_input").eq(1));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
var newRecord = _.last(this.data.partner.records);
assert.strictEqual(newRecord.color, 'black', "should have saved record with correct value");
form.destroy();
});
- QUnit.test('fieldradio widget has o_horizontal or o_vertical class', function (assert) {
+ QUnit.test('fieldradio widget has o_horizontal or o_vertical class', async function (assert) {
assert.expect(2);
this.data.partner.fields.color2 = this.data.partner.fields.color;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1824,7 +1833,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('fieldradio widget with numerical keys encoded as strings', function (assert) {
+ QUnit.test('fieldradio widget with numerical keys encoded as strings', async function (assert) {
assert.expect(5);
this.data.partner.fields.selection = {
@@ -1832,7 +1841,7 @@ QUnit.module('relational_fields', {
selection: [['0', "Red"], ['1', "Black"]],
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1853,19 +1862,19 @@ QUnit.module('relational_fields', {
assert.strictEqual(form.$('.o_field_widget').text(), '',
"field should be unset");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, '.o_radio_input:checked',
"no value should be checked");
- testUtils.dom.click(form.$("input.o_radio_input:nth(1)"));
+ await testUtils.dom.click(form.$("input.o_radio_input:nth(1)"));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget').text(), 'Black',
"value should be 'Black'");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_radio_input[data-index=1]:checked',
"'Black' should be checked");
@@ -1873,7 +1882,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget radio on a many2one: domain updated by an onchange', function (assert) {
+ QUnit.test('widget radio on a many2one: domain updated by an onchange', async function (assert) {
assert.expect(4);
this.data.partner.onchanges = {
@@ -1881,7 +1890,7 @@ QUnit.module('relational_fields', {
};
var domain = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1893,7 +1902,7 @@ QUnit.module('relational_fields', {
mockRPC: function (route, args) {
if (args.method === 'onchange') {
domain = [['id', 'in', [10]]];
- return $.when({
+ return Promise.resolve({
value: {
trululu: false,
},
@@ -1917,8 +1926,7 @@ QUnit.module('relational_fields', {
"should be 3 radio buttons");
// trigger an onchange that will update the domain
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
-
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 2);
assert.containsNone(form, '.o_field_widget[name=trululu] .o_radio_item',
"should be no more radio button");
@@ -1928,10 +1936,10 @@ QUnit.module('relational_fields', {
QUnit.module('FieldSelectionBadge');
- QUnit.test('FieldSelectionBadge widget on a many2one in a new record', function (assert) {
+ QUnit.test('FieldSelectionBadge widget on a many2one in a new record', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1945,21 +1953,21 @@ QUnit.module('relational_fields', {
assert.ok(form.$('span.o_selection_badge:contains(xphone)').length, "one of them should be xphone");
assert.containsNone(form, 'span.active', "none of the input should be checked");
- testUtils.dom.click($("span.o_selection_badge:first"));
+ await testUtils.dom.click($("span.o_selection_badge:first"));
assert.containsOnce(form, 'span.active', "one of the input should be checked");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
var newRecord = _.last(this.data.partner.records);
assert.strictEqual(newRecord.product_id, 37, "should have saved record with correct value");
form.destroy();
});
- QUnit.test('FieldSelectionBadge widget on a selection in a new record', function (assert) {
+ QUnit.test('FieldSelectionBadge widget on a selection in a new record', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1973,19 +1981,19 @@ QUnit.module('relational_fields', {
assert.ok(form.$('span.o_selection_badge:contains(Red)').length, "one of them should be Red");
// click on 2nd option
- testUtils.dom.click(form.$("span.o_selection_badge").eq(1));
+ await testUtils.dom.click(form.$("span.o_selection_badge").eq(1));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
var newRecord = _.last(this.data.partner.records);
assert.strictEqual(newRecord.color, 'black', "should have saved record with correct value");
form.destroy();
});
- QUnit.test('FieldSelectionBadge widget on a selection in a readonly mode', function (assert) {
+ QUnit.test('FieldSelectionBadge widget on a selection in a readonly mode', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2000,11 +2008,11 @@ QUnit.module('relational_fields', {
QUnit.module('FieldMany2ManyCheckBoxes');
- QUnit.test('widget many2many_checkboxes', function (assert) {
+ QUnit.test('widget many2many_checkboxes', async function (assert) {
assert.expect(10);
this.data.partner.records[0].timmy = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2025,23 +2033,23 @@ QUnit.module('relational_fields', {
assert.ok(form.$('div.o_field_widget div.custom-checkbox input').prop('disabled'),
"the checkboxes should be disabled");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').prop('disabled'),
"the checkboxes should not be disabled");
// add a m2m value by clicking on input
- testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(1));
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(1));
+ await testUtils.form.clickSave(form);
assert.deepEqual(this.data.partner.records[0].timmy, [12, 14],
"should have added the second element to the many2many");
assert.containsN(form, 'input:checked', 2,
"both checkboxes should be checked");
// remove a m2m value by clinking on label
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox > label').eq(0));
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox > label').eq(0));
+ await testUtils.form.clickSave(form);
assert.deepEqual(this.data.partner.records[0].timmy, [14],
"should have removed the first element to the many2many");
assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').eq(0).prop('checked'),
@@ -2052,11 +2060,11 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget many2many_checkboxes: start non empty, then remove twice', function (assert) {
+ QUnit.test('widget many2many_checkboxes: start non empty, then remove twice', async function (assert) {
assert.expect(2);
this.data.partner.records[0].timmy = [12,14];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2067,9 +2075,9 @@ QUnit.module('relational_fields', {
viewOptions: {mode: 'edit'},
});
- testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(0));
- testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(1));
- testUtils.form.clickSave(form);
+ await testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(0));
+ await testUtils.dom.click(form.$('div.o_field_widget div.custom-checkbox input').eq(1));
+ await testUtils.form.clickSave(form);
assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').eq(0).prop('checked'),
"first checkbox should not be checked");
assert.notOk(form.$('div.o_field_widget div.custom-checkbox input').eq(1).prop('checked'),
@@ -2080,8 +2088,8 @@ QUnit.module('relational_fields', {
QUnit.module('FieldMany2ManyBinaryMultiFiles');
- QUnit.test('widget many2many_binary', function (assert) {
- assert.expect(14);
+ QUnit.test('widget many2many_binary', async function (assert) {
+ assert.expect(15);
this.data['ir.attachment'] = {
fields: {
name: {string:"Name", type: "char"},
@@ -2100,7 +2108,7 @@ QUnit.module('relational_fields', {
};
this.data.turtle.records[0].picture_ids = [17];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'turtle',
data: this.data,
@@ -2130,7 +2138,7 @@ QUnit.module('relational_fields', {
"there should not be a Delete button (readonly)");
// to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'div.o_field_widget.oe_fileupload .o_attach',
"there should be an Add button");
assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .o_attach').text().trim(), "Pictures",
@@ -2142,7 +2150,7 @@ QUnit.module('relational_fields', {
// no idea how to test this
// delete the attachment
- testUtils.dom.click(form.$('div.o_field_widget.oe_fileupload .oe_attachment .oe_delete'));
+ await testUtils.dom.click(form.$('div.o_field_widget.oe_fileupload .oe_attachment .oe_delete'));
assert.verifySteps([
@@ -2150,17 +2158,23 @@ QUnit.module('relational_fields', {
'/web/dataset/call_kw/ir.attachment/read',
]);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('div.o_field_widget.oe_fileupload .oe_attachments').children().length, 0,
"there should be no attachment");
+ assert.verifySteps([
+ '/web/dataset/call_kw/turtle/write',
+ '/web/dataset/call_kw/turtle/read',
+ ]);
+
form.destroy();
});
QUnit.test('name_create in form dialog', async function (assert) {
assert.expect(2);
- var form = createView({
+
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2184,7 +2198,7 @@ QUnit.module('relational_fields', {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
await testUtils.fields.many2one.searchAndClickItem('product_id',
{selector: '.modal', search: 'new record'});
@@ -2195,14 +2209,14 @@ QUnit.module('relational_fields', {
QUnit.module('FieldReference');
- QUnit.test('Reference field in modal readonly mode', function (assert) {
+ QUnit.test('Reference field in modal readonly mode', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
this.data.partner.records[1].trululu = 1;
this.data.partner.records[1].reference = 'product,41';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2225,7 +2239,7 @@ QUnit.module('relational_fields', {
assert.equal($cell_o2m.text(), 'second record',
'the list should have one record');
- testUtils.dom.click($cell_o2m);
+ await testUtils.dom.click($cell_o2m);
// In modal
var $modal = $('.modal-lg');
@@ -2235,19 +2249,19 @@ QUnit.module('relational_fields', {
assert.equal($modal.find('.o_form_uri.o_field_widget[name=reference]').text(), 'xpad',
'The field reference in the modal should have the right value');
- testUtils.dom.click($modal.find('.o_form_button_cancel'));
+ await testUtils.dom.click($modal.find('.o_form_button_cancel'));
form.destroy();
});
- QUnit.test('Reference field in modal write mode', function (assert) {
+ QUnit.test('Reference field in modal write mode', async function (assert) {
assert.expect(5);
this.data.partner.records[0].p = [2];
this.data.partner.records[1].trululu = 1;
this.data.partner.records[1].reference = 'product,41';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2263,7 +2277,7 @@ QUnit.module('relational_fields', {
});
// current form
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var $fieldRef = form.$('.o_field_widget.o_field_many2one[name=reference]');
assert.equal($fieldRef.find('option:selected').text(), 'Product',
@@ -2271,7 +2285,7 @@ QUnit.module('relational_fields', {
assert.equal($fieldRef.find('.o_input.ui-autocomplete-input').val(), 'xphone',
'The reference field\'s record should be xphone');
- testUtils.dom.click(form.$('.o_data_cell'));
+ await testUtils.dom.click(form.$('.o_data_cell'));
// In modal
var $modal = $('.modal-lg');
@@ -2288,10 +2302,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('reference in form view', function (assert) {
+ QUnit.test('reference in form view', async function (assert) {
assert.expect(15);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2309,7 +2323,7 @@ QUnit.module('relational_fields', {
mockRPC: function (route, args) {
if (args.method === 'get_formview_action') {
assert.deepEqual(args.args[0], [37], "should call get_formview_action with correct id");
- return $.when({
+ return Promise.resolve({
res_id: 17,
type: 'ir.actions.act_window',
target: 'current',
@@ -2318,7 +2332,7 @@ QUnit.module('relational_fields', {
}
if (args.method === 'get_formview_id') {
assert.deepEqual(args.args[0], [37], "should call get_formview_id with correct id");
- return $.when(false);
+ return Promise.resolve(false);
}
if (args.method === 'name_search') {
assert.strictEqual(args.model, 'partner_type',
@@ -2341,9 +2355,9 @@ QUnit.module('relational_fields', {
assert.strictEqual(form.$('a.o_form_uri:contains(xphone)').length, 1,
"should contain a link");
- testUtils.dom.click(form.$('a.o_form_uri'));
+ await testUtils.dom.click(form.$('a.o_form_uri'));
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_field_widget', 2,
"should contain two field widgets (selection and many2one)");
@@ -2360,28 +2374,28 @@ QUnit.module('relational_fields', {
assert.deepEqual(options, ['', 'product', 'partner_type', 'partner'],
"the options should be correctly set");
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: custom label',
"dialog title should display the custom string label");
- testUtils.dom.click($('.modal .o_form_button_cancel'));
+ await testUtils.dom.click($('.modal .o_form_button_cancel'));
- testUtils.fields.editSelect(form.$('.o_field_widget select'), 'partner_type');
+ await testUtils.fields.editSelect(form.$('.o_field_widget select'), 'partner_type');
assert.strictEqual(form.$('.o_field_widget input').val(), "",
"many2one value should be reset after model change");
- testUtils.fields.many2one.clickOpenDropdown('reference');
- testUtils.fields.many2one.clickHighlightedItem('reference');
+ await testUtils.fields.many2one.clickOpenDropdown('reference');
+ await testUtils.fields.many2one.clickHighlightedItem('reference');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
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) {
+ QUnit.test('default_get and onchange with a reference field', async function (assert) {
assert.expect(8);
this.data.partner.fields.reference.default = 'product,37';
@@ -2393,7 +2407,7 @@ QUnit.module('relational_fields', {
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2423,9 +2437,9 @@ QUnit.module('relational_fields', {
"reference field value should be correctly set");
// trigger onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 12);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 12);
- assert.verifySteps(['product', 'partner_type'], "the second name_get should have been done");
+ assert.verifySteps(['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",
@@ -2433,14 +2447,14 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('default_get a reference field in a x2m', function (assert) {
+ QUnit.test('default_get a reference field in a x2m', async function (assert) {
assert.expect(1);
this.data.partner.fields.turtles.default = [
[0, false, {turtle_ref: 'product,37'}]
];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2465,7 +2479,7 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('widget reference on char field, reset by onchange', function (assert) {
+ QUnit.test('widget reference on char field, reset by onchange', async function (assert) {
assert.expect(4);
this.data.partner.records[0].foo = 'product,37';
@@ -2476,7 +2490,7 @@ QUnit.module('relational_fields', {
};
var nbNameGet = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2506,7 +2520,7 @@ QUnit.module('relational_fields', {
"foo field should be correctly set");
// trigger onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 41);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=int_field]'), 41);
assert.strictEqual(nbNameGet, 2,
"the second name_get should have been done");
@@ -2515,10 +2529,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('reference and list navigation', function (assert) {
+ QUnit.test('reference and list navigation', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -2526,25 +2540,25 @@ QUnit.module('relational_fields', {
});
// edit first row
- testUtils.dom.click(list.$('.o_data_row .o_data_cell').first());
+ await testUtils.dom.click(list.$('.o_data_row .o_data_cell').first());
assert.strictEqual(list.$('.o_data_row:eq(0) .o_field_widget[name="reference"] input')[0], document.activeElement,
'input of first data row should be selected');
// press TAB to go to next line
- list.$('.o_data_row:eq(0) input').trigger($.Event('keydown', {
+ await testUtils.dom.triggerEvents(list.$('.o_data_row:eq(0) input:eq(1)'),[$.Event('keydown', {
which: $.ui.keyCode.TAB,
keyCode: $.ui.keyCode.TAB,
- }));
+ })]);
assert.strictEqual(list.$('.o_data_row:eq(1) .o_field_widget[name="reference"] select')[0], document.activeElement,
'select of second data row should be selected');
list.destroy();
});
- QUnit.test('one2many with extra field from server not in form', function (assert) {
+ QUnit.test('one2many with extra field from server not in form', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2569,20 +2583,20 @@ QUnit.module('relational_fields', {
}
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var x2mList = form.$('.o_field_x2many_list[name=p]');
// Add a record in the list
- testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(x2mList.find('.o_field_x2many_list_row_add a'));
var modal = $('.modal-lg');
var nameInput = modal.find('input.o_input[name=display_name]');
- testUtils.fields.editInput(nameInput, 'michelangelo');
+ await testUtils.fields.editInput(nameInput, 'michelangelo');
// Save the record in the modal (though it is still virtual)
- testUtils.dom.click(modal.find('.btn-primary').first());
+ await testUtils.dom.click(modal.find('.btn-primary').first());
assert.equal(x2mList.find('.o_data_row').length, 1,
'There should be 1 records in the x2m list');
@@ -2595,7 +2609,7 @@ QUnit.module('relational_fields', {
'The display name field should have the right value');
// Save the whole thing
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
x2mList = form.$('.o_field_x2many_list[name=p]');
@@ -2613,11 +2627,11 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('one2many invisible depends on parent field', function (assert) {
+ QUnit.test('one2many invisible depends on parent field', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2643,21 +2657,22 @@ QUnit.module('relational_fields', {
});
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.many2one.clickOpenDropdown("product_id");
+ await testUtils.fields.many2one.clickHighlightedItem("product_id");
assert.containsOnce(form, 'th',
"should be 1 column when the product_id is set");
- form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
+ '', 'keyup');
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many when product_id is not set");
- testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
assert.containsOnce(form, 'th',
"should be 1 column after the value change");
form.destroy();
});
- QUnit.test('one2many column visiblity depends on onchange of parent field', function (assert) {
+ QUnit.test('one2many column visiblity depends on onchange of parent field', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [2];
@@ -2670,7 +2685,7 @@ QUnit.module('relational_fields', {
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2691,24 +2706,24 @@ QUnit.module('relational_fields', {
"should be only 1 column ('foo') in the one2many");
assert.containsOnce(form, '.o_list_view .o_data_row', "should contain one row");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// add a new o2m record
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.$('.o_field_one2many input:first').focus();
- testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line');
- testUtils.dom.click(form.$el);
+ await testUtils.fields.editInput(form.$('.o_field_one2many input:first'), 'New line');
+ await testUtils.dom.click(form.$el);
assert.containsN(form, 'th', 2, "should be 2 columns('foo' + 'int_field')");
form.destroy();
});
- QUnit.test('one2many column_invisible on view not inline', function (assert) {
+ QUnit.test('one2many column_invisible on view not inline', async function (assert) {
assert.expect(4);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2735,25 +2750,26 @@ QUnit.module('relational_fields', {
});
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
- testUtils.dom.click($('li.ui-menu-item a:contains(xpad)').trigger('mouseenter'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_many2one[name="product_id"] input'));
+ await testUtils.fields.many2one.clickHighlightedItem("product_id");
assert.containsOnce(form, 'th',
"should be 1 column when the product_id is set");
- form.$('.o_field_many2one[name="product_id"] input').val('').trigger('keyup');
+ await testUtils.fields.editAndTrigger(form.$('.o_field_many2one[name="product_id"] input'),
+ '', 'keyup');
assert.containsN(form, 'th', 2,
"should be 2 columns in the one2many when product_id is not set");
- testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
+ await testUtils.dom.click(form.$('.o_field_boolean[name="bar"] input'));
assert.containsOnce(form, 'th',
"should be 1 column after the value change");
form.destroy();
});
QUnit.module('TabNavigation');
- QUnit.test('when Navigating to a many2one with tabs, it receives the focus and adds a new line', function (assert) {
+ QUnit.test('when Navigating to a many2one with tabs, it receives the focus and adds a new line', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
viewOptions: {
@@ -2782,10 +2798,7 @@ QUnit.module('relational_fields', {
assert.strictEqual(form.$el.find('input[name="qux"]')[0],
document.activeElement,
"initially, the focus should be on the 'qux' field because it is the first input");
- form.$el.find('input[name="qux"]').trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
+ await testUtils.fields.triggerKeydown(form.$el.find('input[name="qux"]'), 'tab');
assert.strictEqual(assert.strictEqual(form.$el.find('input[name="turtle_foo"]')[0],
document.activeElement,
"after tab, the focus should be on the many2one on the first input of the newly added line"));
@@ -2793,10 +2806,10 @@ QUnit.module('relational_fields', {
form.destroy();
});
- QUnit.test('when Navigating to a many to one with tabs, it places the focus on the first visible field', function (assert) {
+ QUnit.test('when Navigating to a many to one with tabs, it places the focus on the first visible field', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
viewOptions: {
@@ -2830,7 +2843,7 @@ QUnit.module('relational_fields', {
which: $.ui.keyCode.TAB,
keyCode: $.ui.keyCode.TAB,
}));
- testUtils.dom.click(document.activeElement);
+ await testUtils.dom.click(document.activeElement);
assert.strictEqual(assert.strictEqual(form.$el.find('input[name="turtle_foo"]')[0],
document.activeElement,
"after tab, the focus should be on the many2one"));
@@ -2839,12 +2852,12 @@ QUnit.module('relational_fields', {
});
QUnit.test('when Navigating to a many2one with tabs, not filling any field and hitting tab,' +
- ' we should not add a first line but navigate to the next control', function (assert) {
+ ' we should not add a first line but navigate to the next control', async function (assert) {
assert.expect(3);
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
viewOptions: {
@@ -2875,32 +2888,27 @@ QUnit.module('relational_fields', {
});
assert.strictEqual(form.$el.find('input[name="qux"]')[0],
- document.activeElement,
- "initially, the focus should be on the 'qux' field because it is the first input");
- form.$el.find('input[name="qux"]').trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
+ document.activeElement,
+ "initially, the focus should be on the 'qux' field because it is the first input");
+ await testUtils.fields.triggerKeydown(form.$el.find('input[name="qux"]'), 'tab');
// skips the first field of the one2many
- $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
-
+ await testUtils.fields.triggerKeydown($(document.activeElement), 'tab');
// skips the second (and last) field of the one2many
- $(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
-
+ await testUtils.fields.triggerKeydown($(document.activeElement), 'tab');
assert.strictEqual(assert.strictEqual(form.$el.find('input[name="foo"]')[0],
- document.activeElement,
- "after tab, the focus should be on the many2one"));
+ document.activeElement,
+ "after tab, the focus should be on the many2one"));
form.destroy();
});
- QUnit.test('when Navigating to a many to one with tabs, editing in a popup, the popup should receive the focus then give it back', function (assert) {
+ QUnit.test('when Navigating to a many to one with tabs, editing in a popup, the popup should receive the focus then give it back', async function (assert) {
assert.expect(3);
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
viewOptions: {
@@ -2934,22 +2942,14 @@ QUnit.module('relational_fields', {
});
assert.strictEqual(form.$el.find('input[name="qux"]')[0],
- document.activeElement,
- "initially, the focus should be on the 'qux' field because it is the first input");
- form.$el.find('input[name="qux"]').trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
-
+ document.activeElement,
+ "initially, the focus should be on the 'qux' field because it is the first input");
+ await testUtils.fields.triggerKeydown(form.$el.find('input[name="qux"]'), 'tab');
assert.strictEqual($.find('input[name="turtle_foo"]')[0],
document.activeElement,
"when the one2many received the focus, the popup should open because it automatically adds a new line");
- $('input[name="turtle_foo"]').trigger($.Event('keydown', {
- which: $.ui.keyCode.ESCAPE,
- keyCode: $.ui.keyCode.ESCAPE,
- }));
-
+ await testUtils.fields.triggerKeydown($('input[name="turtle_foo"]'), 'escape');
assert.strictEqual(form.$el.find('.o_field_x2many_list_row_add a')[0],
document.activeElement,
"after escape, the focus should be back on the add new line link");
@@ -2957,13 +2957,12 @@ 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();
+ QUnit.test('when creating a new many2one on a x2many then discarding it immediately with ESCAPE, it should not crash', async function (assert) {
assert.expect(1);
this.data.partner.records[0].turtles = [];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
viewOptions: {
@@ -2987,33 +2986,30 @@ QUnit.module('relational_fields', {
});
// add a new line
- testUtils.dom.click(form.$el.find('.o_field_x2many_list_row_add>a'));
+ await testUtils.dom.click(form.$el.find('.o_field_x2many_list_row_add>a'));
// open the field turtle_trululu (one2many)
var M2O_DELAY = relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY;
relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
- testUtils.dom.click(form.$el.find('.o_input_dropdown>input'));
+ await testUtils.dom.click(form.$el.find('.o_input_dropdown>input'));
- concurrency.delay(0).then(function () {
- // click create and edit
- testUtils.dom.click($('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter'));
+ // click create and edit
+ await testUtils.dom.click($('.ui-autocomplete .ui-menu-item a:contains(Create and)').trigger('mouseenter'));
- // hit escape immediately
- var escapeKey = $.ui.keyCode.ESCAPE;
- $(document.activeElement).trigger(
- $.Event('keydown', {which: escapeKey, keyCode: escapeKey}));
+ // 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();
- });
+ assert.ok('did not crash');
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = M2O_DELAY;
+ form.destroy();
});
- QUnit.test('navigating through an editable list with custom controls [REQUIRE FOCUS]', function (assert) {
+ QUnit.test('navigating through an editable list with custom controls [REQUIRE FOCUS]', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3040,44 +3036,29 @@ QUnit.module('relational_fields', {
"first input should be focused by default");
// press tab to navigate to the list
- form.$('.o_field_widget[name="display_name"]').trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
-
+ await testUtils.fields.triggerKeydown(
+ form.$('.o_field_widget[name="display_name"]'), 'tab');
// press ESC to cancel 1st control click (create)
- form.$('.o_data_cell input').trigger($.Event('keydown', {
- which: $.ui.keyCode.ESCAPE,
- keyCode: $.ui.keyCode.ESCAPE,
- }));
-
+ await testUtils.fields.triggerKeydown(
+ form.$('.o_data_cell input'), 'escape');
assert.strictEqual(document.activeElement, form.$('.o_field_x2many_list_row_add a:first')[0],
"first editable list control should now have the focus");
// press right to focus the second control
- form.$('.o_field_x2many_list_row_add a:first').trigger($.Event('keydown', {
- which: $.ui.keyCode.RIGHT,
- keyCode: $.ui.keyCode.RIGHT,
- }));
-
+ await testUtils.fields.triggerKeydown(
+ form.$('.o_field_x2many_list_row_add a:first'), 'right');
assert.strictEqual(document.activeElement, form.$('.o_field_x2many_list_row_add a:nth(1)')[0],
"second editable list control should now have the focus");
// press left to come back to first control
- form.$('.o_field_x2many_list_row_add a:nth(1)').trigger($.Event('keydown', {
- which: $.ui.keyCode.LEFT,
- keyCode: $.ui.keyCode.LEFT,
- }));
-
+ await testUtils.fields.triggerKeydown(
+ form.$('.o_field_x2many_list_row_add a:nth(1)'), 'left');
assert.strictEqual(document.activeElement, form.$('.o_field_x2many_list_row_add a:first')[0],
"first editable list control should now have the focus");
// press tab to leave the list
- form.$('.o_field_x2many_list_row_add a:first').trigger($.Event('keydown', {
- which: $.ui.keyCode.TAB,
- keyCode: $.ui.keyCode.TAB,
- }));
-
+ await testUtils.fields.triggerKeydown(
+ form.$('.o_field_x2many_list_row_add a:first'), 'tab');
assert.strictEqual(document.activeElement, form.$('.o_field_widget[name="int_field"]')[0],
"last input should now be focused");
diff --git a/addons/web/static/tests/fields/special_fields.js b/addons/web/static/tests/fields/special_fields.js
index 6acc2be521b..2a674be19ba 100644
--- a/addons/web/static/tests/fields/special_fields.js
+++ b/addons/web/static/tests/fields/special_fields.js
@@ -141,7 +141,7 @@ QUnit.module('special_fields', {
QUnit.module('FieldTimezoneMismatch');
- QUnit.test('widget timezone_mismatch in a list view', function (assert) {
+ QUnit.test('widget timezone_mismatch in a list view', async function (assert) {
assert.expect(5);
this.data.partner.fields.tz_offset = {
@@ -158,7 +158,7 @@ QUnit.module('special_fields', {
}
};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -170,21 +170,21 @@ QUnit.module('special_fields', {
assert.strictEqual(list.$('td:contains(Red)').length, 3,
"should have 3 rows with correct value");
- list.$('td:contains(Red):first').click();
+ await testUtils.dom.click(list.$('td:contains(Red):first'));
var $td = list.$('tbody tr.o_selected_row td:not(.o_list_record_selector)');
assert.strictEqual($td.find('select').length, 1, "td should have a child 'select'");
assert.strictEqual($td.contents().length, 1, "select tag should be only child of td");
- $td.find('select').val('"black"').trigger('change');
+ await testUtils.fields.editSelect($td.find('select'), '"black"');
assert.strictEqual($td.find('.o_tz_warning').length, 1, "Should display icon alert");
assert.ok($td.find('select option:selected').text().match(/Black\s+\([0-9]+\/[0-9]+\/[0-9]+ [0-9]+:[0-9]+:[0-9]+\)/), "Should display the datetime in the selected timezone");
list.destroy();
});
- QUnit.test('widget timezone_mismatch in a form view', function (assert) {
+ QUnit.test('widget timezone_mismatch in a form view', async function (assert) {
assert.expect(1);
this.data.partner.fields.tz_offset = {
@@ -198,7 +198,7 @@ QUnit.module('special_fields', {
this.data.partner.records[0].tz = false;
this.data.partner.records[0].tz_offset = '+4800';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 1,
@@ -208,12 +208,12 @@ QUnit.module('special_fields', {
'<field name="tz" widget="timezone_mismatch"/>' +
'</form>',
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'select[name=tz]');
form.destroy();
});
- QUnit.test('widget timezone_mismatch in a form view edit mode with mismatch', function (assert) {
+ QUnit.test('widget timezone_mismatch in a form view edit mode with mismatch', async function (assert) {
assert.expect(3);
this.data.partner.fields.tz_offset = {
@@ -227,7 +227,7 @@ QUnit.module('special_fields', {
this.data.partner.records[0].tz = 'America/Los_Angeles';
this.data.partner.records[0].tz_offset = '+4800';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 1,
@@ -256,7 +256,7 @@ QUnit.module('special_fields', {
QUnit.module('FieldReportLayout');
- QUnit.test('report_layout widget in form view', function (assert) {
+ QUnit.test('report_layout widget in form view', async function (assert) {
assert.expect(3);
this.data['report.layout'] = {
@@ -275,11 +275,11 @@ QUnit.module('special_fields', {
view_id: 41,
image: "/web/static/tata.png",
pdf: "/web/static/tata.pdf",
- }]
+ }],
};
this.data.partner.records[1].product_id = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -287,6 +287,9 @@ QUnit.module('special_fields', {
'<field name="product_id" widget="report_layout"/> '+
'</form>',
res_id: 2,
+ viewOptions: {
+ mode: 'edit',
+ },
});
assert.strictEqual(form.$('.img.img-fluid').length, 2,
@@ -295,7 +298,7 @@ QUnit.module('special_fields', {
"No image should be selected");
// select first image
- form.$(".img.img-fluid:first").click();
+ await testUtils.dom.click(form.$(".img.img-fluid:first"));
assert.ok(form.$(".img.img-fluid:first").hasClass('btn-info'),
"First image should be selected");
diff --git a/addons/web/static/tests/fields/upgrade_fields_tests.js b/addons/web/static/tests/fields/upgrade_fields_tests.js
index 65de67a7951..d908fd48b61 100644
--- a/addons/web/static/tests/fields/upgrade_fields_tests.js
+++ b/addons/web/static/tests/fields/upgrade_fields_tests.js
@@ -22,27 +22,27 @@ QUnit.module('upgrade_fields', {
QUnit.module('UpgradeBoolean');
- QUnit.test('widget upgrade_boolean in a form view', function (assert) {
+ QUnit.test('widget upgrade_boolean in a form view', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form><field name="bar" widget="upgrade_boolean"/></form>',
});
- testUtils.dom.click(form.$('input:checkbox'));
+ await testUtils.dom.click(form.$('input:checkbox'));
assert.strictEqual($('.modal').length, 1,
"the 'Upgrade to Enterprise' dialog should be opened");
form.destroy();
});
- QUnit.test('widget upgrade_boolean in a form view', function (assert) {
+ QUnit.test('widget upgrade_boolean in a form view', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
diff --git a/addons/web/static/tests/helpers/mock_server.js b/addons/web/static/tests/helpers/mock_server.js
index ff75722b333..44cc276e1c8 100644
--- a/addons/web/static/tests/helpers/mock_server.js
+++ b/addons/web/static/tests/helpers/mock_server.js
@@ -103,9 +103,9 @@ var MockServer = Class.extend({
*
* @param {string} route
* @param {Object} args
- * @returns {Deferred<any>}
+ * @returns {Promise<any>}
* Resolved with the result of the RPC, stringified then parsed.
- * If the RPC should fail, the deferred will be rejected with the
+ * If the RPC should fail, the promise will be rejected with the
* error object, stringified then parsed.
*/
performRpc: function (route, args) {
@@ -132,17 +132,18 @@ var MockServer = Class.extend({
console.log('%c[rpc] response' + route, 'color: blue; font-weight: bold;', JSON.parse(resultString));
}
return JSON.parse(resultString);
- }, function (result, event) {
- var errorString = JSON.stringify(result || false);
+ }, function (result) {
+ var message = result && result.message;
+ var event = result && result.event;
+ var errorString = JSON.stringify(message || false);
if (debug) {
console.log('%c[rpc] response (error) ' + route, 'color: orange; font-weight: bold;', JSON.parse(errorString));
}
- return $.Deferred().reject(errorString, event || $.Event());
+ return Promise.reject({message: errorString, event: event || $.Event()});
});
- var promise = def.promise();
- promise.abort = abort;
- return promise;
+ def.abort = abort;
+ return def;
},
//--------------------------------------------------------------------------
@@ -861,7 +862,7 @@ var MockServer = Class.extend({
}
}
if (type === 'many2one') {
- var ids = _.pluck(records, aggregatedFields[i]);
+ var ids = _.pluck(records, aggregatedFields[i]);
group[aggregatedFields[i]] = _.uniq(ids).length || null;
}
}
@@ -1064,7 +1065,7 @@ var MockServer = Class.extend({
var result = this._mockSearchReadController({
model: model,
domain: kwargs.domain || args[0],
- fields: kwargs.fields || args[1],
+ fields: kwargs.fields || args[1],
offset: kwargs.offset || args[2],
limit: kwargs.limit || args[3],
order: kwargs.order || args[4],
@@ -1181,83 +1182,83 @@ var MockServer = Class.extend({
* @private
* @param {string} route
* @param {Object} args
- * @returns {Deferred<any>}
+ * @returns {Promise<any>}
* Resolved with the result of the RPC. If the RPC should fail, the
- * deferred should either be rejected or the call should throw an
+ * promise should either be rejected or the call should throw an
* exception (@see performRpc for error handling).
*/
_performRpc: function (route, args) {
switch (route) {
case '/web/action/load':
- return $.when(this._mockLoadAction(args.kwargs));
+ return Promise.resolve(this._mockLoadAction(args.kwargs));
case '/web/dataset/search_read':
- return $.when(this._mockSearchReadController(args));
+ return Promise.resolve(this._mockSearchReadController(args));
case '/web/dataset/resequence':
- return $.when(this._mockResequence(args));
+ return Promise.resolve(this._mockResequence(args));
}
if (route.indexOf('/web/image') >= 0 || _.contains(['.png', '.jpg'], route.substr(route.length - 4))) {
- return $.when();
+ return Promise.resolve();
}
switch (args.method) {
case 'copy':
- return $.when(this._mockCopy(args.model, args.args[0]));
+ return Promise.resolve(this._mockCopy(args.model, args.args[0]));
case 'create':
- return $.when(this._mockCreate(args.model, args.args[0]));
+ return Promise.resolve(this._mockCreate(args.model, args.args[0]));
case 'default_get':
- return $.when(this._mockDefaultGet(args.model, args.args, args.kwargs));
+ return Promise.resolve(this._mockDefaultGet(args.model, args.args, args.kwargs));
case 'fields_get':
- return $.when(this._mockFieldsGet(args.model, args.args));
+ return Promise.resolve(this._mockFieldsGet(args.model, args.args));
case 'search_panel_select_range':
- return $.when(this._mockSearchPanelSelectRange(args.model, args.args, args.kwargs));
+ return Promise.resolve(this._mockSearchPanelSelectRange(args.model, args.args, args.kwargs));
case 'search_panel_select_multi_range':
- return $.when(this._mockSearchPanelSelectMultiRange(args.model, args.args, args.kwargs));
+ return Promise.resolve(this._mockSearchPanelSelectMultiRange(args.model, args.args, args.kwargs));
case 'load_views':
- return $.when(this._mockLoadViews(args.model, args.kwargs));
+ return Promise.resolve(this._mockLoadViews(args.model, args.kwargs));
case 'name_get':
- return $.when(this._mockNameGet(args.model, args.args));
+ return Promise.resolve(this._mockNameGet(args.model, args.args));
case 'name_create':
- return $.when(this._mockNameCreate(args.model, args.args));
+ return Promise.resolve(this._mockNameCreate(args.model, args.args));
case 'name_search':
- return $.when(this._mockNameSearch(args.model, args.args, args.kwargs));
+ return Promise.resolve(this._mockNameSearch(args.model, args.args, args.kwargs));
case 'onchange':
- return $.when(this._mockOnchange(args.model, args.args));
+ return Promise.resolve(this._mockOnchange(args.model, args.args));
case 'read':
- return $.when(this._mockRead(args.model, args.args, args.kwargs));
+ return Promise.resolve(this._mockRead(args.model, args.args, args.kwargs));
case 'read_group':
- return $.when(this._mockReadGroup(args.model, args.kwargs));
+ return Promise.resolve(this._mockReadGroup(args.model, args.kwargs));
case 'read_progress_bar':
- return $.when(this._mockReadProgressBar(args.model, args.kwargs));
+ return Promise.resolve(this._mockReadProgressBar(args.model, args.kwargs));
case 'search_count':
- return $.when(this._mockSearchCount(args.model, args.args));
+ return Promise.resolve(this._mockSearchCount(args.model, args.args));
case 'search_read':
- return $.when(this._mockSearchRead(args.model, args.args, args.kwargs));
+ return Promise.resolve(this._mockSearchRead(args.model, args.args, args.kwargs));
case 'unlink':
- return $.when(this._mockUnlink(args.model, args.args));
+ return Promise.resolve(this._mockUnlink(args.model, args.args));
case 'write':
- return $.when(this._mockWrite(args.model, args.args));
+ return Promise.resolve(this._mockWrite(args.model, args.args));
}
var model = this.data[args.model];
if (model && typeof model[args.method] === 'function') {
- return $.when(this.data[args.model][args.method](args.args, args.kwargs));
+ return Promise.resolve(this.data[args.model][args.method](args.args, args.kwargs));
}
throw new Error("Unimplemented route: " + route);
diff --git a/addons/web/static/tests/helpers/qunit_asserts.js b/addons/web/static/tests/helpers/qunit_asserts.js
index bce6ef2a777..e8f9948d347 100644
--- a/addons/web/static/tests/helpers/qunit_asserts.js
+++ b/addons/web/static/tests/helpers/qunit_asserts.js
@@ -37,7 +37,7 @@ function _checkClass(w, className, shouldHaveClass, msg) {
var descr = `${shouldHaveClass ? 'hasClass' : 'doesNotHaveClass'} ${className}`;
QUnit.assert.ok(false, `Assertion '${descr}' targets ${$el.length} elements instead of 1`);
} else {
- msg = msg || `target ${$el.selector || ''} should ${shouldHaveClass ? '' : 'not'} have class ${className}`;
+ msg = msg || `target should ${shouldHaveClass ? '' : 'not'} have class ${className}`;
var hasClass = $el.hasClass(className);
var condition = shouldHaveClass ? hasClass : !hasClass;
QUnit.assert.ok(condition, msg);
@@ -63,8 +63,15 @@ function _checkVisible(w, shouldBeVisible, msg) {
var descr = `${shouldBeVisible ? 'isVisible' : 'isNotVisible'}`;
QUnit.assert.ok(false, `Assertion '${descr}' targets ${$el.length} elements instead of 1`);
} else {
- msg = msg || `target ${$el.selector} should ${shouldBeVisible ? '' : 'not'} be visible`;
+ msg = msg || `target should ${shouldBeVisible ? '' : 'not'} be visible`;
var isVisible = $el.is(':visible');
+ if (isVisible) {
+ // Additional test to see if $el is really visible, since jQuery
+ // considers an element visible if it has a DOWRect, even if its
+ // width and height are equal to zero.
+ var boundingClientRect = $el[0].getBoundingClientRect();
+ isVisible = boundingClientRect.width + boundingClientRect.height;
+ }
var condition = shouldBeVisible ? isVisible : !isVisible;
QUnit.assert.ok(condition, msg);
}
@@ -96,9 +103,7 @@ function containsN(w, selector, n, msg) {
var $matches = $el.find(selector);
if (!msg) {
msg = `Selector '${selector}' should have exactly ${n} matches`;
- if ($el.selector) {
- msg += ` (inside '${$el.selector}')`;
- }
+ msg += ` (inside the target)`;
}
QUnit.assert.strictEqual($matches.length, n, msg);
}
@@ -181,7 +186,7 @@ function hasAttrValue(w, attr, value, msg) {
var descr = `hasAttrValue (${attr}: ${value})`;
QUnit.assert.ok(false, `Assertion '${descr}' targets ${$el.length} elements instead of 1`);
} else {
- msg = msg || `attribute '${attr}' of target ${$el.selector || ''} should be '${value}'`;
+ msg = msg || `attribute '${attr}' of target should be '${value}'`;
QUnit.assert.strictEqual($el.attr(attr), value, msg);
}
}
diff --git a/addons/web/static/tests/helpers/qunit_config.js b/addons/web/static/tests/helpers/qunit_config.js
index 511b9cd2fce..8c6496bb8f9 100644
--- a/addons/web/static/tests/helpers/qunit_config.js
+++ b/addons/web/static/tests/helpers/qunit_config.js
@@ -92,6 +92,64 @@ QUnit.moduleDone(function(result) {
});
/**
+ * After each test, we check that there is no leftover in the DOM.
+ *
+ * Note: this event is not QUnit standard, we added it for this specific use case.
+ */
+QUnit.on('OdooAfterTestHook', function () {
+ // check for leftover elements in the body
+ var $bodyChilds = $('body > *');
+ var validElements = [
+ // always in the body:
+ {tagName: 'DIV', attrToCompare: 'id', value: 'qunit'},
+ {tagName: 'DIV', attrToCompare: 'id', value: 'qunit-fixture'},
+ {tagName: 'SCRIPT', attrToCompare: 'id', value: ''},
+ // shouldn't be in the body after a test but are tolerated:
+ {tagName: 'DIV', attrToCompare: 'className', value: 'o_notification_manager'},
+ {tagName: 'DIV', attrToCompare: 'className', value: 'tooltip fade bs-tooltip-auto'},
+ {tagName: 'DIV', attrToCompare: 'className', value: 'tooltip fade bs-tooltip-auto show'},
+ {tagName: 'I', attrToCompare: 'title', value: 'Raphaël Colour Picker'},
+ {tagName: 'SPAN', attrToCompare: 'className', value: 'select2-hidden-accessible'},
+ // Due to a Document Kanban bug (already present in 12.0)
+ {tagName: 'DIV', attrToCompare: 'className', value: 'ui-helper-hidden-accessible'},
+ {tagName: 'UL', attrToCompare: 'className', value: 'ui-menu ui-widget ui-widget-content ui-autocomplete ui-front'},
+ ];
+ if ($bodyChilds.length > 3) {
+ for (var i = 0; i < $bodyChilds.length; i++) {
+ var bodyChild = $bodyChilds[i];
+ var isValid = false;
+
+ for (var j = 0; j < validElements.length; j++) {
+ var toleratedElement = validElements[j];
+ if (toleratedElement.tagName === bodyChild.tagName) {
+ var attr = toleratedElement.attrToCompare;
+ if (toleratedElement.value === bodyChild[attr]) {
+ isValid = true;
+ break;
+ }
+ }
+ }
+
+ if (!isValid) {
+ if (!document.body.classList.contains('debug')) {
+ $(bodyChild).remove();
+ }
+ QUnit.pushFailure(`Body still contains undesirable elements`);
+ }
+ }
+ }
+
+ // check for leftovers in #qunit-fixture
+ var qunitFixture = document.getElementById('qunit-fixture');
+ if (qunitFixture.children.length) {
+ QUnit.pushFailure(`#qunit-fixture still contains elements`);
+ if (!document.body.classList.contains('debug')) {
+ $(qunitFixture.children).remove();
+ }
+ }
+});
+
+/**
* Add a sort button on top of the QUnit result page, so we can see which tests
* take the most time.
*/
diff --git a/addons/web/static/tests/helpers/test_utils.js b/addons/web/static/tests/helpers/test_utils.js
index 2897b02214c..ccf5d8daf6b 100644
--- a/addons/web/static/tests/helpers/test_utils.js
+++ b/addons/web/static/tests/helpers/test_utils.js
@@ -11,7 +11,9 @@ odoo.define('web.test_utils', function (require) {
*/
var ajax = require('web.ajax');
+var concurrency = require('web.concurrency');
var core = require('web.core');
+var relationalFields = require('web.relational_fields');
var session = require('web.session');
var testUtilsCreate = require('web.test_utils_create');
var testUtilsDom = require('web.test_utils_dom');
@@ -25,22 +27,89 @@ var testUtilsModal = require('web.test_utils_modal');
var testUtilsPivot = require('web.test_utils_pivot');
var tools = require('web.tools');
+
function deprecated(fn, type) {
var msg = `Helper 'testUtils.${fn.name}' is deprecated. ` +
`Please use 'testUtils.${type}.${fn.name}' instead.`;
return tools.deprecated(fn, msg);
}
+/**
+ * Helper function, make a promise with a public resolve function. Note that
+ * this is not standard and should not be used outside of tests...
+ *
+ * @returns {Promise + resolve and reject function}
+ */
+function makeTestPromise() {
+ var resolve;
+ var reject;
+ var promise = new Promise(function (_resolve, _reject) {
+ resolve = _resolve;
+ reject = _reject;
+ });
+ promise.resolve = function () {
+ resolve.apply(null, arguments);
+ return promise;
+ };
+ promise.reject = function () {
+ reject.apply(null, arguments);
+ return promise;
+ };
+ return promise;
+}
+
+/**
+ * Make a promise with public resolve and reject functions (see
+ * @makeTestPromise). Perform an assert.step when the promise is
+ * resolved/rejected.
+ *
+ * @param {Object} assert instance object with the assertion methods
+ * @param {function} assert.step
+ * @param {string} str message to pass to assert.step
+ * @returns {Promise + resolve and reject function}
+ */
+function makeTestPromiseWithAssert(assert, str) {
+ var prom = makeTestPromise();
+ prom.then(() => assert.step('ok ' + str)).catch(function () {});
+ prom.catch(() => assert.step('ko ' + str));
+ return prom;
+}
+
+/**
+ * Create a new promise that can be waited by the caller in order to execute
+ * code after the next microtask tick and before the next jobqueue tick.
+ *
+ * @return {Promise} an already fulfilled promise
+ */
+async function nextMicrotaskTick() {
+ return Promise.resolve();
+}
+
+/**
+ * Returns a promise that is resolved in the next jobqueue tick so that the
+ * caller can wait on it in order to execute code in the next jobqueue tick.
+ *
+ * @return {Promise} a promise that will be fulfilled in the next jobqueue tick
+ */
+async function nextTick() {
+ return concurrency.delay(0);
+}
+
// Loading static files cannot be properly simulated when their real content is
// really needed. This is the case for static XML files so we load them here,
// before starting the qunit test suite.
// (session.js is in charge of loading the static xml bundle and we also have
// to load xml files that are normally lazy loaded by specific widgets).
-return $.when(
+return Promise.all([
session.is_bound,
ajax.loadXML('/web/static/src/xml/dialog.xml', core.qweb)
-).then(function () {
+]).then(function () {
setTimeout(function () {
+ // jquery autocomplete refines the search in a setTimeout() parameterized
+ // with a delay, so we force this delay to 0 s.t. the dropdown is filtered
+ // directly on the next tick
+ relationalFields.FieldMany2One.prototype.AUTOCOMPLETE_DELAY = 0;
+
// this is done with the hope that tests are
// only started all together...
QUnit.start();
@@ -53,6 +122,7 @@ return $.when(
patchDate: testUtilsMock.patchDate,
unpatch: testUtilsMock.unpatch,
fieldsViewGet: testUtilsMock.fieldsViewGet,
+ patchSetTimeout: testUtilsMock.patchSetTimeout,
},
dom: {
triggerKeypressEvent: testUtilsDom.triggerKeypressEvent,
@@ -63,6 +133,7 @@ return $.when(
click: testUtilsDom.click,
clickFirst: testUtilsDom.clickFirst,
clickLast: testUtilsDom.clickLast,
+ triggerEvents: testUtilsDom.triggerEvents,
},
form: {
clickEdit: testUtilsForm.clickEdit,
@@ -99,6 +170,9 @@ return $.when(
editInput: testUtilsFields.editInput,
editSelect: testUtilsFields.editSelect,
editAndTrigger: testUtilsFields.editAndTrigger,
+ triggerKey: testUtilsFields.triggerKey,
+ triggerKeydown: testUtilsFields.triggerKeydown,
+ triggerKeyup: testUtilsFields.triggerKeyup,
},
file: {
createFile: testUtilsFile.createFile,
@@ -108,11 +182,16 @@ return $.when(
createActionManager: testUtilsCreate.createActionManager,
createDebugManager: testUtilsCreate.createDebugManager,
- createAsyncView: testUtilsCreate.createAsyncView,
+ createAsyncView: testUtilsCreate.createView,
+ createCalendarView: testUtilsCreate.createCalendarView,
createControlPanel: testUtilsCreate.createControlPanel,
createView: testUtilsCreate.createView,
createModel: testUtilsCreate.createModel,
createParent: testUtilsCreate.createParent,
+ makeTestPromise: makeTestPromise,
+ makeTestPromiseWithAssert: makeTestPromiseWithAssert,
+ nextMicrotaskTick: nextMicrotaskTick,
+ nextTick: nextTick,
// backward-compatibility
addMockEnvironment: deprecated(testUtilsMock.addMockEnvironment, 'mock'),
diff --git a/addons/web/static/tests/helpers/test_utils_create.js b/addons/web/static/tests/helpers/test_utils_create.js
index 5a64512260e..7e4de1060bc 100644
--- a/addons/web/static/tests/helpers/test_utils_create.js
+++ b/addons/web/static/tests/helpers/test_utils_create.js
@@ -13,6 +13,7 @@ odoo.define('web.test_utils_create', function (require) {
var ActionManager = require('web.ActionManager');
var config = require('web.config');
var ControlPanelView = require('web.ControlPanelView');
+var concurrency = require('web.concurrency');
var DebugManager = require('web.DebugManager');
var dom = require('web.dom');
var testUtilsMock = require('web.test_utils_mock');
@@ -30,7 +31,7 @@ var Widget = require('web.Widget');
* @param {function} [params.mockRPC]
* @returns {ActionManager}
*/
-function createActionManager (params) {
+var createActionManager = async function (params) {
params = params || {};
var $target = $('#qunit-fixture');
if (params.debug) {
@@ -47,7 +48,7 @@ function createActionManager (params) {
_.extend(params, {
mockRPC: function (route, args) {
if (args.model === 'ir.attachment') {
- return $.when([]);
+ return Promise.resolve([]);
}
if (mockRPC) {
return mockRPC.apply(this, arguments);
@@ -56,7 +57,7 @@ function createActionManager (params) {
},
});
testUtilsMock.addMockEnvironment(widget, _.defaults(params, { debounce: false }));
- widget.prependTo($target);
+ await widget.prependTo($target);
widget.$el.addClass('o_web_client');
if (config.device.isMobile) {
widget.$el.addClass('o_touch_device');
@@ -71,14 +72,14 @@ function createActionManager (params) {
widget.destroy();
};
var fragment = document.createDocumentFragment();
- actionManager.appendTo(fragment).then(function () {
+ return actionManager.appendTo(fragment).then(function () {
dom.append(widget.$el, fragment, {
callbacks: [{ widget: actionManager }],
in_DOM: true,
});
+ return actionManager;
});
- return actionManager;
-}
+};
/**
* create a view from various parameters. Here, a view means a javascript
@@ -89,10 +90,6 @@ function createActionManager (params) {
* through a mock method using the data object as source, and already loaded/
* started.
*
- * Most views can be tested synchronously (@see createView), but some view have
- * external dependencies (like lazy loaded libraries). In that case, it is
- * necessary to use this method.
- *
* @param {Object} params
* @param {string} params.arch the xml (arch) of the view to be instantiated
* @param {any[]} [params.domain] the initial domain for the view
@@ -109,9 +106,9 @@ function createActionManager (params) {
* Note that this is particularly useful if you want to intercept events going
* up in the init process of the view, because there are no other way to do it
* after this method returns
- * @returns {Deferred<AbstractView>} resolves with the instance of the view
+ * @returns {Promise<AbstractController>} resolves with the instance of the view
*/
-function createAsyncView(params) {
+async function createView(params) {
var $target = $('#qunit-fixture');
var widget = new Widget();
if (params.debug) {
@@ -175,6 +172,7 @@ function createAsyncView(params) {
// when it will be called the second time (by its parent)
delete view.destroy;
widget.destroy();
+ $webClient.remove();
testUtilsMock.unpatch(View);
};
@@ -187,14 +185,45 @@ function createAsyncView(params) {
callbacks: [{ widget: view }],
in_DOM: true,
});
+
view.$el.on('click', 'a', function (ev) {
ev.preventDefault();
});
-
return view;
});
});
}
+
+/**
+ * Similar as createView, but specific for calendar views. Some calendar
+ * tests need to trigger positional clicks on the DOM produced by fullcalendar.
+ * Those tests must use this helper with option positionalClicks set to true.
+ * This will move the rendered calendar to the body (required to do positional
+ * clicks), and wait for a setTimeout(0) before returning, because fullcalendar
+ * makes the calendar scroll to 6:00 in a setTimeout(0), which might have an
+ * impact according to where we want to trigger positional clicks.
+ *
+ * @param {Object} params see @createView
+ * @param {Object} [options]
+ * @param {boolean} [options.positionalClicks=false]
+ * @returns {Promise<CalendarController>}
+ */
+async function createCalendarView(params, options) {
+ var calendar = await createView(params);
+ if (!options || !options.positionalClicks) {
+ return calendar;
+ }
+ var $view = $('#qunit-fixture').contents();
+ $view.prependTo('body');
+ var destroy = calendar.destroy;
+ calendar.destroy = function () {
+ $view.remove();
+ destroy();
+ };
+ await concurrency.delay(0);
+ return calendar;
+}
+
/**
* create a controlPanel from various parameters.
*
@@ -227,7 +256,7 @@ function createAsyncView(params) {
* @param {boolean} [params.withSearchBar=true] if set to false, no default
* search bar will be rendered
*
- * @returns {Deferred<ControlPanel>} resolves with an instance of the ControlPanelController
+ * @returns {Promise<ControlPanel>} resolves with an instance of the ControlPanelController
*/
function createControlPanel(params) {
params = params || {};
@@ -270,6 +299,7 @@ function createControlPanel(params) {
// children when it will be called the second time (by its parent)
delete controlPanel.destroy;
widget.destroy();
+ $webClient.remove();
};
// render the controlPanel in a fragment as it must be able to render
@@ -290,16 +320,16 @@ function createControlPanel(params) {
*
* @param {Object} [params={}]
*/
-function createDebugManager (params) {
+var createDebugManager = function (params) {
params = params || {};
var mockRPC = params.mockRPC;
_.extend(params, {
mockRPC: function (route, args) {
if (args.method === 'check_access_rights') {
- return $.when(true);
+ return Promise.resolve(true);
}
if (args.method === 'xmlid_to_res_id') {
- return $.when(true);
+ return Promise.resolve(true);
}
if (mockRPC) {
return mockRPC.apply(this, arguments);
@@ -309,7 +339,7 @@ function createDebugManager (params) {
session: {
user_has_group: function (group) {
if (group === 'base.group_no_one') {
- return $.when(true);
+ return Promise.resolve(true);
}
return this._super.apply(this, arguments);
},
@@ -318,7 +348,7 @@ function createDebugManager (params) {
var debugManager = new DebugManager();
testUtilsMock.addMockEnvironment(debugManager, params);
return debugManager;
-}
+};
/**
* create a model from given parameters.
@@ -360,32 +390,10 @@ function createParent(params) {
return widget;
}
-/**
- * create a view synchronously. This method uses the createAsyncView method.
- * Most views are synchronous, so the deferred can be resolved immediately and
- * this method will work.
- *
- * Be careful, if for some reason a view is async, this method will crash.
- * @see createAsyncView
- *
- * @param {Object} params will be given to createAsyncView
- * @returns {AbstractView}
- */
-function createView(params) {
- var view;
- createAsyncView(params).then(function (result) {
- view = result;
- });
- if (!view) {
- throw "The view that you are trying to create is async. Please use createAsyncView instead";
- }
- return view;
-}
-
-
return {
createActionManager: createActionManager,
- createAsyncView: createAsyncView,
+ createView: createView,
+ createCalendarView: createCalendarView,
createControlPanel: createControlPanel,
createDebugManager: createDebugManager,
createModel: createModel,
diff --git a/addons/web/static/tests/helpers/test_utils_dom.js b/addons/web/static/tests/helpers/test_utils_dom.js
index dcf9eab6e15..315a00cbfe7 100644
--- a/addons/web/static/tests/helpers/test_utils_dom.js
+++ b/addons/web/static/tests/helpers/test_utils_dom.js
@@ -1,6 +1,8 @@
-odoo.define('web.test_utils_dom', function () {
+odoo.define('web.test_utils_dom', function (require) {
"use strict";
+var concurrency = require('web.concurrency');
+
/**
* DOM Test Utils
*
@@ -101,6 +103,7 @@ function dragAndDrop($el, $to, options) {
$el.trigger($.Event("mouseup"));
});
}
+ return concurrency.delay(0);
}
/**
@@ -114,7 +117,8 @@ function dragAndDrop($el, $to, options) {
function triggerMouseEvent($el, type) {
var pos = $el.offset();
var e = new $.Event(type);
- e.pageX = e.layerX = e.screenX = pos.left;
+ // little fix since it seems on chrome, it triggers 1px too on the left
+ e.pageX = e.layerX = e.screenX = pos.left + 1;
e.pageY = e.layerY = e.screenY = pos.top;
e.which = 1;
$el.trigger(e);
@@ -154,6 +158,8 @@ function triggerKeypressEvent(char) {
var keycode;
if (char === "Enter") {
keycode = $.ui.keyCode.ENTER;
+ } else if (char === "Tab") {
+ keycode = $.ui.keyCode.TAB;
} else {
keycode = char.charCodeAt(0);
}
@@ -177,37 +183,47 @@ function openDatepicker($datepickerEl) {
* @param {Object} [options]
* @param {boolean} [options.first=false] if true, clicks on the first element
* @param {boolean} [options.last=false] if true, clicks on the last element
+ * @param {boolean} [options.allowInvisible=false] if true, clicks on the
+ * element event if it is invisible
+ * @param {boolean} [options.shouldTriggerClick=false] if true, trigger the
+ * click event without calling the function click of jquery
*/
function click(el, options) {
options = options || {};
var matches = typeof el === 'string' ? $(el) : el;
- var selectorMsg = el.selector ? `(selector: ${el.selector})` : '';
+ var selectorMsg = typeof el === 'string' ? `(selector: ${el})` : '';
if (!matches.filter) { // it might be an array of dom elements
matches = $(matches);
}
+ var validMatches = options.allowInvisible ? matches : matches.filter(':visible');
- var visibleMatches = matches.filter(':visible');
if (options.first) {
- if (visibleMatches.length === 1) {
+ if (validMatches.length === 1) {
throw new Error(`There should be more than one visible target ${selectorMsg}. If` +
' you are sure that there is exactly one target, please use the ' +
'click function instead of the clickFirst function');
}
- visibleMatches = visibleMatches.first();
+ validMatches = validMatches.first();
} else if (options.last) {
- if (visibleMatches.length === 1) {
+ if (validMatches.length === 1) {
throw new Error(`There should be more than one visible target ${selectorMsg}. If` +
' you are sure that there is exactly one target, please use the ' +
'click function instead of the clickLast function');
}
- visibleMatches = visibleMatches.last();
+ validMatches = validMatches.last();
}
- if (visibleMatches.length === 0 && matches.length > 0) {
+ if (validMatches.length === 0 && matches.length > 0) {
throw new Error(`Element to click on is not visible ${selectorMsg}`);
- } else if (visibleMatches.length !== 1) {
- throw new Error(`Found ${visibleMatches.length} elements to click on, instead of 1 ${selectorMsg}`);
+ } else if (validMatches.length !== 1) {
+ throw new Error(`Found ${validMatches.length} elements to click on, instead of 1 ${selectorMsg}`);
+ }
+ if (options.shouldTriggerClick) {
+ validMatches.trigger('click');
+ } else {
+ validMatches.click();
}
- visibleMatches.click();
+
+ return concurrency.delay(0);
}
/**
@@ -216,9 +232,13 @@ function click(el, options) {
* use the click helper instead.
*
* @param {string|NodeList|jQuery} el (if string: it is a (jquery) selector)
+ * @param {boolean} [options.allowInvisible=false] if true, clicks on the
+ * element event if it is invisible
+ * @param {boolean} [options.shouldTriggerClick=false] if true, trigger the
+ * click event without calling the function click of jquery
*/
-function clickFirst(el) {
- click(el, {first: true});
+function clickFirst(el, options) {
+ return click(el, _.extend({}, options, {first: true}));
}
/**
@@ -227,11 +247,36 @@ function clickFirst(el) {
* use the click helper instead.
*
* @param {string|NodeList|jQuery} el
+ * @param {boolean} [options.allowInvisible=false] if true, clicks on the
+ * element event if it is invisible
+ * @param {boolean} [options.shouldTriggerClick=false] if true, trigger the
+ * click event without calling the function click of jquery
+ */
+function clickLast(el, options) {
+ return click(el, _.extend({}, options, {last: true}));
+}
+
+
+/**
+ * trigger events on the specified target
+ * @param {jQuery} $el should target a single dom node
+ * @param {string[]} events the events you want to trigger
+ * @returns Promise
*/
-function clickLast(el) {
- click(el, {last: true});
+function triggerEvents($el, events) {
+ if ($el.length !== 1) {
+ throw new Error(`target has length ${$el.length} instead of 1`);
+ }
+ if (typeof events === 'string') {
+ events = [events];
+ }
+ events.forEach(function (event) {
+ $el.trigger(event);
+ });
+ return concurrency.delay(0);
}
+
return {
triggerKeypressEvent: triggerKeypressEvent,
triggerMouseEvent: triggerMouseEvent,
@@ -241,6 +286,7 @@ return {
click: click,
clickFirst: clickFirst,
clickLast: clickLast,
+ triggerEvents: triggerEvents,
};
});
diff --git a/addons/web/static/tests/helpers/test_utils_fields.js b/addons/web/static/tests/helpers/test_utils_fields.js
index f0f29839a9d..359f5f56b08 100644
--- a/addons/web/static/tests/helpers/test_utils_fields.js
+++ b/addons/web/static/tests/helpers/test_utils_fields.js
@@ -11,6 +11,7 @@ odoo.define('web.test_utils_fields', function (require) {
*/
var concurrency = require('web.concurrency');
+var domUtils = require('web.test_utils_dom');
//------------------------------------------------------------------------------
// Public functions
@@ -32,9 +33,7 @@ function editAndTrigger($el, value, events) {
throw new Error(`target ${$el.selector} has length ${$el.length} instead of 1`);
}
$el.val(value);
- events.forEach(function (event) {
- $el.trigger(event);
- });
+ return domUtils.triggerEvents($el, events);
}
/**
@@ -49,7 +48,7 @@ function editAndTrigger($el, value, events) {
* @param {string|number} value
*/
function editInput($el, value) {
- editAndTrigger($el, value, ['input']);
+ return editAndTrigger($el, value, ['input']);
}
/**
@@ -65,6 +64,7 @@ function editInput($el, value) {
*/
function editSelect($el, value) {
editAndTrigger($el, value, ['change']);
+ return concurrency.delay(0);
}
/**
@@ -75,14 +75,16 @@ function editSelect($el, value) {
* input
* @returns {HTMLInputElement} the main many2one input
*/
-function clickOpenM2ODropdown(fieldName, selector) {
+async function clickOpenM2ODropdown(fieldName, selector) {
var m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`;
var matches = document.querySelectorAll(m2oSelector);
if (matches.length !== 1) {
throw new Error(`cannot open m2o: selector ${selector} has been found ${matches.length} instead of 1`);
}
matches[0].click();
- return matches[0];
+ return await concurrency.delay(0).then(function () {
+ return matches[0];
+ });
}
/**
@@ -97,6 +99,7 @@ function clickM2OHighlightedItem(fieldName, selector) {
var $dropdown = $(m2oSelector).autocomplete('widget');
// clicking on an li (no matter which one), will select the focussed one
$dropdown.find('li:first()').click();
+ return concurrency.delay(0);
}
/**
@@ -117,7 +120,10 @@ function clickM2OItem(fieldName, searchText) {
if ($target.length !== 1 || !$target.is(':visible')) {
throw new Error('Menu item should be unique and visible');
}
- $target.mouseenter().click();
+ $target.mouseenter();
+ $target.click();
+
+ return concurrency.delay(0);
}
/**
@@ -140,30 +146,69 @@ function clickM2OItem(fieldName, searchText) {
function searchAndClickM2OItem(fieldName, options) {
options = options || {};
- var input = clickOpenM2ODropdown(fieldName, options.selector);
-
- var def;
- if (options.search) {
- // jquery autocomplete refines the search in a setTimeout() parameterized
- // with a delay, so we force this delay to 0 s.t. the dropdown is filtered
- // directly on the next tick
- var $input = $(input);
- var delay = $input.autocomplete('option', 'delay');
- $input.autocomplete('option', 'delay', 0);
- input.value = options.search;
- input.dispatchEvent(new Event('input'));
- $input.autocomplete('option', 'delay', delay);
- def = concurrency.delay(0);
- }
+ return clickOpenM2ODropdown(fieldName, options.selector).then(function (input) {
+ var def;
+ if (options.search) {
+ input.value = options.search;
+ input.dispatchEvent(new Event('input'));
+ def = concurrency.delay(0);
+ }
+ return Promise.resolve(def).then(function () {
+ if (options.item) {
+ return clickM2OItem(fieldName, options.item);
+ } else {
+ return clickM2OHighlightedItem(fieldName, options.selector);
+ }
+ });
+ });
+}
- return $.when(def).then(function () {
- if (options.item) {
- clickM2OItem(fieldName, options.item);
+/**
+ * Helper to trigger a key event on an element.
+ *
+ * @param {string} type type of key event ('press', 'up' or 'down')
+ * @param {jQuery} $el
+ * @param {number|string} keyCode used as number, but if string, it'll check if
+ * the string corresponds to a key -otherwise it will keep only the first
+ * char to get a letter key- and convert it into a keyCode.
+ * @returns {Promise}
+ */
+function triggerKey(type, $el, keyCode) {
+ type = 'key' + type;
+ if (typeof keyCode === 'string') {
+ if (keyCode.length > 1) {
+ keyCode = keyCode.toUpperCase();
+ keyCode = $.ui.keyCode[keyCode];
} else {
- clickM2OHighlightedItem(fieldName, options.selector);
+ keyCode = keyCode.charCodeAt(0);
}
- });
+ }
+ $el.trigger({type: type, which: keyCode, keyCode: keyCode});
+ return concurrency.delay(0);
}
+
+/**
+ * Helper to trigger a keydown event on an element.
+ *
+ * @param {jQuery} $el
+ * @param {number|string} keyCode @see triggerKey
+ * @returns {Promise}
+ */
+function triggerKeydown($el, keyCode) {
+ return triggerKey('down', $el, keyCode);
+}
+
+/**
+ * Helper to trigger a keyup event on an element.
+ *
+ * @param {jQuery} $el
+ * @param {number|string} keyCode @see triggerKey
+ * @returns {Promise}
+ */
+function triggerKeyup($el, keyCode) {
+ return triggerKey('up', $el, keyCode);
+}
+
return {
clickOpenM2ODropdown: clickOpenM2ODropdown,
clickM2OHighlightedItem: clickM2OHighlightedItem,
@@ -172,6 +217,9 @@ return {
editInput: editInput,
editSelect: editSelect,
searchAndClickM2OItem: searchAndClickM2OItem,
+ triggerKey: triggerKey,
+ triggerKeydown: triggerKeydown,
+ triggerKeyup: triggerKeyup,
};
});
diff --git a/addons/web/static/tests/helpers/test_utils_file.js b/addons/web/static/tests/helpers/test_utils_file.js
index 64e044e3180..e5b68a28e0b 100644
--- a/addons/web/static/tests/helpers/test_utils_file.js
+++ b/addons/web/static/tests/helpers/test_utils_file.js
@@ -47,29 +47,30 @@ function _createFakeDataTransfer(file) {
* @param {string} data.name
* @param {string} data.content
* @param {string} data.contentType
- * @returns {$.Promise<Object>} resolved with file created
+ * @returns {Promise<Object>} resolved with file created
*/
function createFile(data) {
- var def = $.Deferred();
- var requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
- if (!requestFileSystem) {
- throw new Error('FileSystem API is not supported');
- }
- requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fileSystem) {
- fileSystem.root.getFile(data.name, { create: true }, function (fileEntry) {
- fileEntry.createWriter(function (fileWriter) {
- fileWriter.onwriteend = function (e) {
- fileSystem.root.getFile(data.name, {}, function (fileEntry) {
- fileEntry.file(function (file) {
- def.resolve(file);
+ // Note: this is only supported by Chrome, and does not work in Incognito mode
+ return new Promise(function (resolve, reject) {
+ var requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
+ if (!requestFileSystem) {
+ throw new Error('FileSystem API is not supported');
+ }
+ requestFileSystem(window.TEMPORARY, 1024 * 1024, function (fileSystem) {
+ fileSystem.root.getFile(data.name, { create: true }, function (fileEntry) {
+ fileEntry.createWriter(function (fileWriter) {
+ fileWriter.onwriteend = function (e) {
+ fileSystem.root.getFile(data.name, {}, function (fileEntry) {
+ fileEntry.file(function (file) {
+ resolve(file);
+ });
});
- });
- };
- fileWriter.write(new Blob([ data.content ], { type: data.contentType }));
+ };
+ fileWriter.write(new Blob([ data.content ], { type: data.contentType }));
+ });
});
});
});
- return def;
}
/**
diff --git a/addons/web/static/tests/helpers/test_utils_form.js b/addons/web/static/tests/helpers/test_utils_form.js
index 379350e1ca6..b4bff154ce7 100644
--- a/addons/web/static/tests/helpers/test_utils_form.js
+++ b/addons/web/static/tests/helpers/test_utils_form.js
@@ -20,7 +20,7 @@ var testUtilsDom = require('web.test_utils_dom');
* @param {FormController} form
*/
function clickEdit(form) {
- testUtilsDom.click(form.$buttons.find('.o_form_button_edit'));
+ return testUtilsDom.click(form.$buttons.find('.o_form_button_edit'));
}
/**
@@ -30,7 +30,7 @@ function clickEdit(form) {
* @param {FormController} form
*/
function clickSave(form) {
- testUtilsDom.click(form.$buttons.find('.o_form_button_save'));
+ return testUtilsDom.click(form.$buttons.find('.o_form_button_save'));
}
/**
@@ -40,7 +40,7 @@ function clickSave(form) {
* @param {FormController} form
*/
function clickCreate(form) {
- testUtilsDom.click(form.$buttons.find('.o_form_button_create'));
+ return testUtilsDom.click(form.$buttons.find('.o_form_button_create'));
}
/**
@@ -50,7 +50,7 @@ function clickCreate(form) {
* @param {FormController} form
*/
function clickDiscard(form) {
- testUtilsDom.click(form.$buttons.find('.o_form_button_cancel'));
+ return testUtilsDom.click(form.$buttons.find('.o_form_button_cancel'));
}
/**
@@ -60,7 +60,7 @@ function clickDiscard(form) {
* @param {[Object]} params given to the controller reload method
*/
function reload(form, params) {
- form.reload(params);
+ return form.reload(params);
}
return {
diff --git a/addons/web/static/tests/helpers/test_utils_graph.js b/addons/web/static/tests/helpers/test_utils_graph.js
index 8867f82c349..f6b50a1b571 100644
--- a/addons/web/static/tests/helpers/test_utils_graph.js
+++ b/addons/web/static/tests/helpers/test_utils_graph.js
@@ -18,7 +18,7 @@ odoo.define('web.test_utils_graph', function () {
* @param {[Object]} params given to the controller reload method
*/
function reload(graph, params) {
- graph.reload(params);
+ return graph.reload(params);
}
return {
diff --git a/addons/web/static/tests/helpers/test_utils_kanban.js b/addons/web/static/tests/helpers/test_utils_kanban.js
index 166ae2a2572..76af632b417 100644
--- a/addons/web/static/tests/helpers/test_utils_kanban.js
+++ b/addons/web/static/tests/helpers/test_utils_kanban.js
@@ -18,22 +18,24 @@ var testUtilsFields = require('web.test_utils_fields');
* the Create button is visible.
*
* @param {KanbanController} kanban
+ * @returns {Promise}
*/
function clickCreate(kanban) {
- testUtilsDom.click(kanban.$buttons.find('.o-kanban-button-new'));
+ return testUtilsDom.click(kanban.$buttons.find('.o-kanban-button-new'));
}
/**
* Open the settings menu for a column (in a grouped kanban view)
*
* @param {jQuery} $column
+ * @returns {Promise}
*/
function toggleGroupSettings($column) {
var $dropdownToggler = $column.find('.o_kanban_config > a.dropdown-toggle');
if (!$dropdownToggler.is(':visible')) {
$dropdownToggler.css('display', 'block');
}
- testUtilsDom.click($dropdownToggler);
+ return testUtilsDom.click($dropdownToggler);
}
/**
@@ -43,6 +45,7 @@ function toggleGroupSettings($column) {
* @param {kanbanController} kanban
* @param {string|number} value
* @param {[string]} fieldName
+ * @returns {Promise}
*/
function quickCreate(kanban, value, fieldName) {
var additionalSelector = fieldName ? ('[name=' + fieldName + ']'): '';
@@ -53,7 +56,7 @@ function quickCreate(kanban, value, fieldName) {
keyCode: $.ui.keyCode.ENTER,
}
);
- testUtilsFields.editAndTrigger(
+ return testUtilsFields.editAndTrigger(
kanban.$('.o_kanban_quick_create input' + additionalSelector),
value,
['input', enterEvent]
@@ -65,9 +68,10 @@ function quickCreate(kanban, value, fieldName) {
*
* @param {KanbanController} kanban
* @param {[Object]} params given to the controller reload method
+ * @returns {Promise}
*/
function reload(kanban, params) {
- kanban.reload(params);
+ return kanban.reload(params);
}
/**
@@ -76,13 +80,14 @@ function reload(kanban, params) {
* does not comply with the usual dom structure.
*
* @param {jQuery} $record
+ * @returns {Promise}
*/
function toggleRecordDropdown($record) {
var $dropdownToggler = $record.find('.o_dropdown_kanban > a.dropdown-toggle');
if (!$dropdownToggler.is(':visible')) {
$dropdownToggler.css('display', 'block');
}
- testUtilsDom.click($dropdownToggler);
+ return testUtilsDom.click($dropdownToggler);
}
diff --git a/addons/web/static/tests/helpers/test_utils_mock.js b/addons/web/static/tests/helpers/test_utils_mock.js
index 2ecc655db7e..ccb4d20959e 100644
--- a/addons/web/static/tests/helpers/test_utils_mock.js
+++ b/addons/web/static/tests/helpers/test_utils_mock.js
@@ -124,7 +124,7 @@ function removeSrcAttribute(el, widget) {
* is completely removed by default.
*
* @returns {MockServer} the instance of the mock server, created by this
- * function. It is necessary for createAsyncView so that method can call some
+ * function. It is necessary for createView so that method can call some
* other methods on it.
*/
function addMockEnvironment(widget, params) {
@@ -199,10 +199,11 @@ function addMockEnvironment(widget, params) {
// widget is destroyed, at the end of each test to avoid collisions
core.bus.trigger('clear_cache');
- _(services).chain()
- .compact() // services can be defined but null (e.g. ajax)
- .reject(function (s) { return s.isDestroyed(); })
- .invoke('destroy');
+ Object.keys(services).forEach(function(s) {
+ var service = services[s];
+ if (service && !service.isDestroyed())
+ service.destroy();
+ });
DebouncedField.prototype.DEBOUNCE = initialDebounceValue;
dom.DEBOUNCE = initialDOMDebounceValue;
@@ -543,6 +544,25 @@ function unpatch(target) {
delete target.__patchID;
}
+window.originalSetTimeout = window.setTimeout;
+function patchSetTimeout() {
+ var original = window.setTimeout;
+ var self = this;
+ window.setTimeout = function (handler, delay) {
+ console.log("calling setTimeout on " + (handler.name || "some function") + "with delay of " + delay);
+ console.trace();
+ var handlerArguments = Array.prototype.slice.call(arguments, 1);
+ return original(function () {
+ handler.bind(self, handlerArguments)();
+ console.log('after doing the action of the setTimeout');
+ }, delay);
+ };
+
+ return function () {
+ window.setTimeout = original;
+ };
+}
+
return {
addMockEnvironment: addMockEnvironment,
@@ -551,6 +571,7 @@ return {
patchDate: patchDate,
patch: patch,
unpatch: unpatch,
+ patchSetTimeout: patchSetTimeout,
};
});
diff --git a/addons/web/static/tests/helpers/test_utils_modal.js b/addons/web/static/tests/helpers/test_utils_modal.js
index d2162aebfa0..5587eecfc01 100644
--- a/addons/web/static/tests/helpers/test_utils_modal.js
+++ b/addons/web/static/tests/helpers/test_utils_modal.js
@@ -11,6 +11,7 @@ odoo.define('web.test_utils_modal', function (require) {
*/
var core = require('web.core');
+var concurrency = require('web.concurrency');
/**
* Click on a button in the footer of a modal (which contains a given string).
@@ -25,6 +26,7 @@ function clickButton(text) {
throw new Error(`Found ${$button.length} button(s) containing '${text}'`);
}
$button.click();
+ return concurrency.delay(0);
}
return {
diff --git a/addons/web/static/tests/helpers/test_utils_pivot.js b/addons/web/static/tests/helpers/test_utils_pivot.js
index 18a5a7307f3..fe059b533ed 100644
--- a/addons/web/static/tests/helpers/test_utils_pivot.js
+++ b/addons/web/static/tests/helpers/test_utils_pivot.js
@@ -24,7 +24,7 @@ var testUtilsDom = require('web.test_utils_dom');
* @param {string} measure
*/
function clickMeasure(pivot, measure) {
- testUtilsDom.click(pivot.$buttons.find(`.dropdown-item[data-field=${measure}]`));
+ return testUtilsDom.click(pivot.$buttons.find(`.dropdown-item[data-field=${measure}]`));
}
/**
@@ -35,7 +35,7 @@ function clickMeasure(pivot, measure) {
* @param {PivotController} pivot
*/
function toggleMeasuresDropdown(pivot) {
- testUtilsDom.click(pivot.$buttons.filter('.btn-group:first').find('> button'));
+ return testUtilsDom.click(pivot.$buttons.filter('.btn-group:first').find('> button'));
}
/**
@@ -45,7 +45,7 @@ function toggleMeasuresDropdown(pivot) {
* @param {[Object]} params given to the controller reload method
*/
function reload(pivot, params) {
- pivot.reload(params);
+ return pivot.reload(params);
}
return {
diff --git a/addons/web/static/tests/qweb_tests.js b/addons/web/static/tests/qweb_tests.js
index fbb710d8cfc..fda72e2392b 100644
--- a/addons/web/static/tests/qweb_tests.js
+++ b/addons/web/static/tests/qweb_tests.js
@@ -15,20 +15,20 @@ function loadTest(assert, template, context) {
var done = assert.async();
assert.expect(1);
- var def = $.Deferred();
var qweb = new window.QWeb2.Engine();
-
- qweb.add_template(qwebPath + template, function (error, doc) {
- if (error) {
- return $.Deferred().reject(error);
- }
- def.resolve({
- qweb: qweb,
- doc: doc
+ var prom = new Promise(function (resolve, reject) {
+ qweb.add_template(qwebPath + template, function (error, doc) {
+ if (error) {
+ return reject(error);
+ }
+ resolve({
+ qweb: qweb,
+ doc: doc
+ });
});
});
- def.then(function (r) {
+ prom.then(function (r) {
var qweb = r.qweb;
var doc = r.doc;
assert.expect(doc.querySelectorAll('result').length);
@@ -60,7 +60,7 @@ function loadTest(assert, template, context) {
}
done();
});
- return def;
+ return prom;
}
QUnit.module('QWeb', {}, function () {
@@ -87,7 +87,9 @@ QUnit.module('QWeb', {}, function () {
var WORD_REPLACEMENT = window.QWeb2.WORD_REPLACEMENT;
window.QWeb2.WORD_REPLACEMENT = _.extend({not: '!', None: 'undefined'}, WORD_REPLACEMENT);
loadTest(assert, 'qweb-test-global.xml', {bool: function (v) { return !!v ? 'True' : 'False';}})
- .always(function () {
+ .then(function () {
+ window.QWeb2.WORD_REPLACEMENT = WORD_REPLACEMENT;
+ }, function () {
window.QWeb2.WORD_REPLACEMENT = WORD_REPLACEMENT;
});
});
diff --git a/addons/web/static/tests/services/notification_service_tests.js b/addons/web/static/tests/services/notification_service_tests.js
index 8a10b9f2df9..aed8d2fa847 100644
--- a/addons/web/static/tests/services/notification_service_tests.js
+++ b/addons/web/static/tests/services/notification_service_tests.js
@@ -41,76 +41,68 @@ QUnit.module('Services', {
}, function () {
QUnit.module('Notification');
- QUnit.test('Display a simple notification', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a simple notification', async function (assert) {
assert.expect(4);
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
view.call('notification', 'notify', {
title: 'a',
message: 'b',
});
+ await testUtils.nextMicrotaskTick();
var $notification = $('body .o_notification_manager .o_notification');
assert.strictEqual(_.str.trim($notification.html().replace(/\s+/g, ' ')),
"<div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-lightbulb-o\" title=\"Notification undefined\"></span> a </div> <div class=\"o_notification_content\">b</div>",
"should display notification");
- assert.strictEqual($notification.find('.o_close').length, 0, "should not display the close button in ");
- setTimeout(function () {
- assert.strictEqual($notification.is(':hidden'), true, "should hide the notification");
- assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notification");
- view.destroy();
- done();
- });
+ assert.containsNone($notification, '.o_close', "should not display the close button in ");
+ await testUtils.nextTick();
+ assert.strictEqual($notification.is(':hidden'), true, "should hide the notification");
+ assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notification");
+ view.destroy();
});
- QUnit.test('Display a warning', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a warning', async function (assert) {
assert.expect(1);
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
view.call('notification', 'notify', {
title: 'a',
message: 'b',
type: 'warning'
});
+ await testUtils.nextMicrotaskTick();
var $notification = $('body .o_notification_manager .o_notification');
assert.strictEqual(_.str.trim($notification.html().replace(/\s+/g, ' ')),
"<div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-exclamation\" title=\"Notification undefined\"></span> a </div> <div class=\"o_notification_content\">b</div>",
"should display notification");
view.destroy();
- setTimeout(done);
});
- QUnit.test('Display a sticky notification', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a sticky notification', async function (assert) {
assert.expect(3);
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
view.call('notification', 'notify', {
title: 'a',
message: 'b',
sticky: true,
});
+ await testUtils.nextTick();
var $notification = $('body .o_notification_manager .o_notification');
- assert.strictEqual($notification.find('.o_close').length, 1, "should display the close button in notification");
+ assert.containsOnce($notification, '.o_close', "should display the close button in notification");
- setTimeout(function () {
- assert.strictEqual($notification.is(':hidden'), false, "should not hide the notification automatically");
- testUtils.dom.click($notification.find('.o_close'));
- setTimeout(function () {
- assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notification");
- view.destroy();
- done();
- });
- });
+ assert.strictEqual($notification.is(':hidden'), false, "should not hide the notification automatically");
+ await testUtils.dom.click($notification.find('.o_close'));
+ assert.strictEqual($('body .o_notification_manager .o_notification').length,
+ 0, "should destroy the notification");
+ view.destroy();
});
- QUnit.test('Display a simple notification with onClose callback when automatically close', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a simple notification with onClose callback when automatically close', async function (assert) {
assert.expect(2);
var close = 0;
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
view.call('notification', 'notify', {
title: 'a',
message: 'b',
@@ -118,16 +110,14 @@ QUnit.module('Services', {
close++;
}
});
+ await testUtils.nextMicrotaskTick();
view.destroy();
assert.strictEqual(close, 0, "should wait to call onClose method once");
- setTimeout(function () {
- assert.strictEqual(close, 1, "should call onClose method once");
- done();
- });
+ await testUtils.nextTick();
+ assert.strictEqual(close, 1, "should call onClose method once");
});
- QUnit.test('Display a sticky notification with onClose callback', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a sticky notification with onClose callback', async function (assert) {
assert.expect(2);
testUtils.mock.unpatch(Notification);
@@ -135,7 +125,7 @@ QUnit.module('Services', {
_autoCloseDelay: 2500,
_animationDelay: 0,
});
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
var close = 0;
view.call('notification', 'notify', {
@@ -146,20 +136,17 @@ QUnit.module('Services', {
close++;
}
});
+ await testUtils.nextMicrotaskTick();
assert.strictEqual(close, 0, "should wait to call onClose method once");
testUtils.dom.click($('body .o_notification_manager .o_notification .o_close'));
- setTimeout(function () {
- assert.strictEqual(close, 1, "should call onClose method once");
- view.destroy();
- done();
- });
+ assert.strictEqual(close, 1, "should call onClose method once");
+ view.destroy();
});
- QUnit.test('Display a question', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a question', async function (assert) {
assert.expect(8);
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
function notification (inc) {
return {
title: 'a' + inc,
@@ -187,9 +174,11 @@ QUnit.module('Services', {
view.call('notification', 'notify', notification(0));
view.call('notification', 'notify', notification(1));
view.call('notification', 'notify', notification(2));
+ await testUtils.nextTick();
var $notification = $('body .o_notification_manager .o_notification');
- assert.strictEqual($notification.eq(0).find('.o_close').length, 1, "should display the close button in notification");
+ assert.containsOnce($notification.eq(0), '.o_close',
+ "should display the close button in notification");
assert.strictEqual(_.str.trim($notification.eq(0).html().replace(/\s+/g, ' ')),
"<a aria-label=\"Close\" class=\"fa fa-times o_close\" href=\"#\" title=\"Close\"></a> <div class=\"o_notification_title\"> <span role=\"img\" aria-label=\"Notification undefined\" class=\"o_icon fa fa-3x fa-question-circle-o\" title=\"Notification undefined\"></span> a0 </div> <div class=\"o_notification_content\">b0</div> <div class=\"o_buttons\"> <button class=\"btn btn-primary\" type=\"button\"> <span>accept0</span> </button><button class=\"btn btn-secondary\" type=\"button\"> <span>refuse0</span> </button> </div>",
"should display notification");
@@ -198,17 +187,14 @@ QUnit.module('Services', {
testUtils.dom.click($notification.find('.o_buttons button:contains(refuse1)'));
testUtils.dom.click($notification.eq(2).find('.o_close'));
- setTimeout(function () {
- assert.strictEqual($notification.is(':hidden'), true, "should hide the notification");
- assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notification");
- assert.verifySteps(['accept0', 'refuse1', 'close2']);
- view.destroy();
- done();
- });
+ assert.strictEqual($notification.is(':hidden'), true, "should hide the notification");
+ assert.strictEqual($('body .o_notification_manager .o_notification').length,
+ 0, "should destroy the notification");
+ assert.verifySteps(['accept0', 'refuse1', 'close2']);
+ view.destroy();
});
- QUnit.test('call close notification service', function (assert) {
- var done = assert.async();
+ QUnit.test('call close notification service', async function (assert) {
assert.expect(2);
testUtils.mock.unpatch(Notification);
@@ -216,7 +202,7 @@ QUnit.module('Services', {
_autoCloseDelay: 2500,
_animationDelay: 0,
});
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
var close = 0;
var notificationId0 = view.call('notification', 'notify', {
@@ -234,20 +220,18 @@ QUnit.module('Services', {
close++;
}
});
+ await testUtils.nextTick();
view.call('notification', 'close', notificationId0);
view.call('notification', 'close', notificationId1);
+ await testUtils.nextTick();
- setTimeout(function () {
- assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notifications");
- assert.strictEqual(close, 2, "should call onClose method twice");
- view.destroy();
- done();
- });
+ assert.strictEqual($('body .o_notification_manager .o_notification').length, 0, "should destroy the notifications");
+ assert.strictEqual(close, 2, "should call onClose method twice");
+ view.destroy();
});
- QUnit.test('Display a custom notification', function (assert) {
- var done = assert.async();
+ QUnit.test('Display a custom notification', async function (assert) {
assert.expect(3);
var Custom = Notification.extend({
@@ -263,21 +247,17 @@ QUnit.module('Services', {
},
});
- var view = createView(this.viewParams);
+ var view = await createView(this.viewParams);
view.call('notification', 'notify', {
Notification: Custom,
customParams: true,
});
- assert.strictEqual(
- $('body .o_notification_manager .o_notification:contains(Custom)').length, 1,
+ await testUtils.nextMicrotaskTick();
+ assert.containsOnce($('body'), '.o_notification_manager .o_notification:contains(Custom)',
"should display the notification");
view.destroy();
- setTimeout(function () {
- assert.strictEqual(
- $('body .o_notification_manager .o_notification').length, 0,
- "should destroy the notification");
- done();
- });
+ assert.containsNone($('body'), '.o_notification_manager .o_notification',
+ "should destroy the notification");
});
});});
diff --git a/addons/web/static/tests/tools/debug_manager_tests.js b/addons/web/static/tests/tools/debug_manager_tests.js
index fb454aae0d1..0de3d5857e0 100644
--- a/addons/web/static/tests/tools/debug_manager_tests.js
+++ b/addons/web/static/tests/tools/debug_manager_tests.js
@@ -8,7 +8,7 @@ var createDebugManager = testUtils.createDebugManager;
QUnit.module('DebugManager', {}, function () {
- QUnit.test("list: edit view menu item", function (assert) {
+ QUnit.test("list: edit view menu item", async function (assert) {
assert.expect(3);
var debugManager = createDebugManager();
@@ -28,7 +28,8 @@ QUnit.module('DebugManager', {}, function () {
var view = {
viewType: "list",
};
- debugManager.update('action', action, view);
+ await testUtils.nextTick();
+ await debugManager.update('action', action, view);
var $editView = debugManager.$('a[data-action=edit][data-model="ir.ui.view"]');
assert.strictEqual($editView.length, 1, "should have edit view menu item");
@@ -39,7 +40,7 @@ QUnit.module('DebugManager', {}, function () {
debugManager.destroy();
});
- QUnit.test("form: Manage Attachments option", function (assert) {
+ QUnit.test("form: Manage Attachments option", async function (assert) {
assert.expect(3);
var debugManager = createDebugManager({
@@ -59,8 +60,7 @@ QUnit.module('DebugManager', {}, function () {
},
},
});
-
- debugManager.appendTo($('#qunit-fixture'));
+ await debugManager.appendTo($('#qunit-fixture'));
// Simulate update debug manager from web client
var action = {
@@ -79,19 +79,19 @@ QUnit.module('DebugManager', {}, function () {
return [5];
},
};
- debugManager.update('action', action, view);
+ await debugManager.update('action', action, view);
var $attachmentMenu = debugManager.$('a[data-action=get_attachments]');
assert.strictEqual($attachmentMenu.length, 1, "should have Manage Attachments menu item");
assert.strictEqual($attachmentMenu.text().trim(), "Manage Attachments",
"should have correct menu item text");
- testUtils.dom.click(debugManager.$('> a')); // open dropdown
- testUtils.dom.click($attachmentMenu);
+ await testUtils.dom.click(debugManager.$('> a')); // open dropdown
+ await testUtils.dom.click($attachmentMenu);
debugManager.destroy();
});
- QUnit.test("Debug: Set defaults with right model", function (assert) {
+ QUnit.test("Debug: Set defaults with right model", async function (assert) {
assert.expect(2);
/* Click on debug > set default,
@@ -115,7 +115,7 @@ QUnit.module('DebugManager', {}, function () {
},
};
- var form = testUtils.createView({
+ var form = await testUtils.createView({
View: FormView,
model: 'partner',
data: data,
@@ -132,13 +132,13 @@ QUnit.module('DebugManager', {}, function () {
if (route == "/web/dataset/call_kw/ir.default/set") {
assert.deepEqual(args.args, ["partner", "foo", "yop", true, true, false],
'Model, field, value and booleans for current user/company should have been passed');
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
}
});
- debugManager.appendTo($('#qunit-fixture'));
+ await debugManager.appendTo($('#qunit-fixture'));
// Simulate update debug manager from web client
var action = {
@@ -155,18 +155,18 @@ QUnit.module('DebugManager', {}, function () {
};
// We are all set
- debugManager.update('action', action, form);
+ await debugManager.update('action', action, form);
// click on set_defaults dropdown
- testUtils.dom.click(debugManager.$('> a')); // open dropdown
- testUtils.dom.click(debugManager.$('a[data-action="set_defaults"]'));
+ await testUtils.dom.click(debugManager.$('> a')); // open dropdown
+ await testUtils.dom.click(debugManager.$('a[data-action="set_defaults"]'));
var $modal = $('.modal-content');
assert.strictEqual($modal.length, 1, 'One modal present');
$modal.find('select[id=formview_default_fields] option[value=foo]').prop('selected', true);
// Save
- testUtils.dom.click($modal.find('.modal-footer button').eq(1));
+ await testUtils.dom.click($modal.find('.modal-footer button').eq(1));
form.destroy();
debugManager.destroy();
diff --git a/addons/web/static/tests/views/abstract_controller_tests.js b/addons/web/static/tests/views/abstract_controller_tests.js
index f9045645bc6..e0fa433b13c 100644
--- a/addons/web/static/tests/views/abstract_controller_tests.js
+++ b/addons/web/static/tests/views/abstract_controller_tests.js
@@ -1,89 +1,82 @@
-odoo.define("base.abstract_controller_tests", function(require) {
- "use strict";
+odoo.define("base.abstract_controller_tests", function (require) {
+"use strict";
- var testUtils = require("web.test_utils");
- var createView = testUtils.createView;
- var BasicView = require("web.BasicView");
- var BasicRenderer = require("web.BasicRenderer");
+var testUtils = require("web.test_utils");
+var createView = testUtils.createView;
+var BasicView = require("web.BasicView");
+var BasicRenderer = require("web.BasicRenderer");
- function getHtmlRenderer(html) {
- return BasicRenderer.extend({
- start: function() {
- this.$el.html(html);
- return this._super.apply(this, arguments);
- }
- });
- }
- function getHtmlView(html, viewType) {
- viewType = viewType || "test";
- return BasicView.extend({
- viewType: viewType,
- config: _.extend({}, BasicView.prototype.config, {
- Renderer: getHtmlRenderer(html)
- })
- });
- }
+function getHtmlRenderer(html) {
+ return BasicRenderer.extend({
+ start: function () {
+ this.$el.html(html);
+ return this._super.apply(this, arguments);
+ }
+ });
+}
+function getHtmlView(html, viewType) {
+ viewType = viewType || "test";
+ return BasicView.extend({
+ viewType: viewType,
+ config: _.extend({}, BasicView.prototype.config, {
+ Renderer: getHtmlRenderer(html)
+ })
+ });
+}
- QUnit.module(
- "Views",
- {
- beforeEach: function() {
- this.data = {
- test_model: {
- fields: {},
- records: []
- }
- };
+QUnit.module("Views", {
+ beforeEach: function () {
+ this.data = {
+ test_model: {
+ fields: {},
+ records: []
}
- },
- function() {
-
- QUnit.module('AbstractController');
-
- QUnit.test(
- 'click on a a[type="action"] child triggers the correct action',
- function(assert) {
- assert.expect(7);
+ };
+ }
+}, function () {
+ QUnit.module('AbstractController');
- var html =
- "<div>" +
- '<a name="a1" type="action" class="simple">simple</a>' +
- '<a name="a2" type="action" class="with-child">' +
- "<span>child</input>" +
- "</a>" +
- '<a type="action" data-model="foo" data-method="bar" class="method">method</a>' +
- '<a type="action" data-model="foo" data-res-id="42" class="descr">descr</a>' +
- '<a type="action" data-model="foo" class="descr2">descr2</a>' +
- "</div>";
+ QUnit.test('click on a a[type="action"] child triggers the correct action', async function (assert) {
+ assert.expect(7);
- var view = createView({
- View: getHtmlView(html, "test"),
- data: this.data,
- model: "test_model",
- arch: "<test/>",
- intercepts: {
- do_action: function (event) {
- assert.step(event.data.action.name || event.data.action);
- }
- },
- mockRPC: function (route, args) {
- if (args.model === 'foo' && args.method === 'bar') {
- assert.step("method");
- return $.when({name: 'method'});
- }
- return this._super.apply(this, arguments);
- }
- });
- testUtils.dom.click(view.$(".simple"));
- testUtils.dom.click(view.$(".with-child span"));
- testUtils.dom.click(view.$(".method"));
- testUtils.dom.click(view.$(".descr"));
- testUtils.dom.click(view.$(".descr2"));
- assert.verifySteps(["a1", "a2", "method", "method", "descr", "descr2"]);
+ var html =
+ "<div>" +
+ '<a name="a1" type="action" class="simple">simple</a>' +
+ '<a name="a2" type="action" class="with-child">' +
+ "<span>child</input>" +
+ "</a>" +
+ '<a type="action" data-model="foo" data-method="bar" class="method">method</a>' +
+ '<a type="action" data-model="foo" data-res-id="42" class="descr">descr</a>' +
+ '<a type="action" data-model="foo" class="descr2">descr2</a>' +
+ "</div>";
- view.destroy();
+ var view = await createView({
+ View: getHtmlView(html, "test"),
+ data: this.data,
+ model: "test_model",
+ arch: "<test/>",
+ intercepts: {
+ do_action: function (event) {
+ assert.step(event.data.action.name || event.data.action);
}
- );
- }
+ },
+ mockRPC: function (route, args) {
+ if (args.model === 'foo' && args.method === 'bar') {
+ assert.step("method");
+ return Promise.resolve({name: 'method'});
+ }
+ return this._super.apply(this, arguments);
+ }
+ });
+ await testUtils.dom.click(view.$(".simple"));
+ await testUtils.dom.click(view.$(".with-child span"));
+ await testUtils.dom.click(view.$(".method"));
+ await testUtils.dom.click(view.$(".descr"));
+ await testUtils.dom.click(view.$(".descr2"));
+ assert.verifySteps(["a1", "a2", "method", "method", "descr", "descr2"]);
+
+ view.destroy();
+ }
);
});
+});
diff --git a/addons/web/static/tests/views/abstract_view_banner_tests.js b/addons/web/static/tests/views/abstract_view_banner_tests.js
index 21532ed60d9..ab668dd8c0d 100644
--- a/addons/web/static/tests/views/abstract_view_banner_tests.js
+++ b/addons/web/static/tests/views/abstract_view_banner_tests.js
@@ -5,7 +5,7 @@ var AbstractRenderer = require('web.AbstractRenderer');
var AbstractView = require('web.AbstractView');
var testUtils = require('web.test_utils');
-var createAsyncView = testUtils.createAsyncView;
+var createView = testUtils.createView;
var TestRenderer = AbstractRenderer.extend({
_renderView: function () {
@@ -48,7 +48,7 @@ QUnit.module('Views', {
'<div class="hello_banner"/>' +
'</div>';
- createAsyncView({
+ createView({
View: TestView,
model: 'test_model',
data: this.data,
@@ -56,7 +56,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
if (route === '/module/hello_banner') {
assert.step(route);
- return $.when({html: banner_html});
+ return Promise.resolve({html: banner_html});
}
return this._super(route, args);
},
diff --git a/addons/web/static/tests/views/abstract_view_tests.js b/addons/web/static/tests/views/abstract_view_tests.js
index 3d4cc423ddd..ba819379279 100644
--- a/addons/web/static/tests/views/abstract_view_tests.js
+++ b/addons/web/static/tests/views/abstract_view_tests.js
@@ -6,7 +6,7 @@ var ajax = require('web.ajax');
var testUtils = require('web.test_utils');
var createActionManager = testUtils.createActionManager;
-var createAsyncView = testUtils.createAsyncView;
+var createView = testUtils.createView;
QUnit.module('Views', {
beforeEach: function () {
@@ -31,15 +31,15 @@ QUnit.module('Views', {
QUnit.module('AbstractView');
- QUnit.test('lazy loading of js libs (in parallel)', function (assert) {
+ QUnit.test('lazy loading of js libs (in parallel)', async function (assert) {
var done = assert.async();
assert.expect(6);
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
var loadJS = ajax.loadJS;
ajax.loadJS = function (url) {
assert.step(url);
- return def.then(function () {
+ return prom.then(function () {
assert.step(url + ' loaded');
});
};
@@ -47,37 +47,37 @@ QUnit.module('Views', {
var View = AbstractView.extend({
jsLibs: [['a', 'b']],
});
- createAsyncView({
+ createView({
View: View,
arch: '<fake/>',
data: this.data,
model: 'fake_model',
}).then(function (view) {
- assert.verifySteps(['a', 'b', 'a loaded', 'b loaded'],
+ assert.verifySteps(['a loaded', 'b loaded'],
"should wait for both libs to be loaded");
ajax.loadJS = loadJS;
view.destroy();
done();
});
- assert.verifySteps(['a', 'b'],
- "both libs should be loaded in parallel");
- def.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['a', 'b'], "both libs should be loaded in parallel");
+ prom.resolve();
});
- QUnit.test('lazy loading of js libs (sequentially)', function (assert) {
+ QUnit.test('lazy loading of js libs (sequentially)', async function (assert) {
var done = assert.async();
assert.expect(10);
- var defs = {
- a: $.Deferred(),
- b: $.Deferred(),
- c: $.Deferred(),
+ var proms = {
+ a: testUtils.makeTestPromise(),
+ b: testUtils.makeTestPromise(),
+ c: testUtils.makeTestPromise(),
};
var loadJS = ajax.loadJS;
ajax.loadJS = function (url) {
assert.step(url);
- return defs[url].then(function () {
+ return proms[url].then(function () {
assert.step(url + ' loaded');
});
};
@@ -88,34 +88,32 @@ QUnit.module('Views', {
'c',
],
});
- createAsyncView({
+ createView({
View: View,
arch: '<fake/>',
data: this.data,
model: 'fake_model',
}).then(function (view) {
- assert.verifySteps(['a', 'b', 'b loaded', 'a loaded', 'c', 'c loaded'],
- "should for all libs to be loaded");
+ assert.verifySteps(['c loaded'], "should wait for all libs to be loaded");
ajax.loadJS = loadJS;
view.destroy();
done();
});
-
- assert.verifySteps(['a', 'b'],
- "libs 'a' and 'b' should be loaded in parallel");
- defs.b.resolve();
- assert.verifySteps(['a', 'b', 'b loaded'],
- "should wait for 'a' and 'b' to be loaded before loading 'c'");
- defs.a.resolve();
- assert.verifySteps(['a', 'b', 'b loaded', 'a loaded', 'c'],
- "should load 'c' when 'a' and 'b' are loaded");
- defs.c.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['a', 'b'], "libs 'a' and 'b' should be loaded in parallel");
+ await proms.b.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['b loaded'], "should wait for 'a' and 'b' to be loaded before loading 'c'");
+ await proms.a.resolve();
+ await testUtils.nextTick();
+ assert.verifySteps(['a loaded', 'c'], "should load 'c' when 'a' and 'b' are loaded");
+ await proms.c.resolve();
});
- QUnit.test('group_by from context can be a string, instead of a list of strings', function (assert) {
+ QUnit.test('group_by from context can be a string, instead of a list of strings', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: [{
id: 1,
name: 'Foo',
@@ -139,7 +137,7 @@ QUnit.module('Views', {
},
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
actionManager.destroy();
});
diff --git a/addons/web/static/tests/views/basic_model_tests.js b/addons/web/static/tests/views/basic_model_tests.js
index bf5261c5b6e..e19cadea2cf 100644
--- a/addons/web/static/tests/views/basic_model_tests.js
+++ b/addons/web/static/tests/views/basic_model_tests.js
@@ -1,92 +1,92 @@
odoo.define('web.basic_model_tests', function (require) {
-"use strict";
-
-var BasicModel = require('web.BasicModel');
-var testUtils = require('web.test_utils');
-
-var createModel = testUtils.createModel;
-
-QUnit.module('Views', {
- beforeEach: function () {
- this.data = {
- partner: {
- fields: {
- display_name: {string: "STRING", type: 'char'},
- total: {string: "Total", type: 'integer'},
- foo: {string: "Foo", type: 'char'},
- bar: {string: "Bar", type: 'integer'},
- qux: {string: "Qux", type: 'many2one', relation: 'partner'},
- product_id: {string: "Favorite product", type: 'many2one', relation: 'product'},
- product_ids: {string: "Favorite products", type: 'one2many', relation: 'product'},
- category: {string: "Category M2M", type: 'many2many', relation: 'partner_type'},
- date: {string: "Date Field", type: 'date'},
- reference: {string: "Reference Field", type: 'reference', selection: [["product", "Product"], ["partner_type", "Partner Type"], ["partner", "Partner"]]},
+ "use strict";
+
+ var BasicModel = require('web.BasicModel');
+ var testUtils = require('web.test_utils');
+
+ var createModel = testUtils.createModel;
+
+ QUnit.module('Views', {
+ beforeEach: function () {
+ this.data = {
+ partner: {
+ fields: {
+ display_name: { string: "STRING", type: 'char' },
+ total: { string: "Total", type: 'integer' },
+ foo: { string: "Foo", type: 'char' },
+ bar: { string: "Bar", type: 'integer' },
+ qux: { string: "Qux", type: 'many2one', relation: 'partner' },
+ product_id: { string: "Favorite product", type: 'many2one', relation: 'product' },
+ product_ids: { string: "Favorite products", type: 'one2many', relation: 'product' },
+ category: { string: "Category M2M", type: 'many2many', relation: 'partner_type' },
+ date: { string: "Date Field", type: 'date' },
+ reference: { string: "Reference Field", type: 'reference', selection: [["product", "Product"], ["partner_type", "Partner Type"], ["partner", "Partner"]] },
+ },
+ records: [
+ { id: 1, foo: 'blip', bar: 1, product_id: 37, category: [12], display_name: "first partner", date: "2017-01-25" },
+ { id: 2, foo: 'gnap', bar: 2, product_id: 41, display_name: "second partner" },
+ ],
+ onchanges: {},
},
- records: [
- {id: 1, foo: 'blip', bar: 1, product_id: 37, category: [12], display_name: "first partner", date: "2017-01-25"},
- {id: 2, foo: 'gnap', bar: 2, product_id: 41, display_name: "second partner"},
- ],
- onchanges: {},
- },
- product: {
- fields: {
- name: {string: "Product Name", type: "char"}
+ product: {
+ fields: {
+ name: { string: "Product Name", type: "char" }
+ },
+ records: [
+ { id: 37, display_name: "xphone" },
+ { id: 41, display_name: "xpad" }
+ ]
},
- records: [
- {id: 37, display_name: "xphone"},
- {id: 41, display_name: "xpad"}
- ]
- },
- partner_type: {
- fields: {
- display_name: {string: "Partner Type", type: "char"},
- date: {string: "Date Field", type: 'date'},
+ partner_type: {
+ fields: {
+ display_name: { string: "Partner Type", type: "char" },
+ date: { string: "Date Field", type: 'date' },
+ },
+ records: [
+ { id: 12, display_name: "gold", date: "2017-01-25" },
+ { id: 14, display_name: "silver" },
+ { id: 15, display_name: "bronze" }
+ ]
},
- records: [
- {id: 12, display_name: "gold", date: "2017-01-25"},
- {id: 14, display_name: "silver"},
- {id: 15, display_name: "bronze"}
- ]
- },
- };
-
- // add related fields to category.
- this.data.partner.fields.category.relatedFields =
- $.extend(true, {}, this.data.partner_type.fields);
- this.params = {
- res_id: 2,
- modelName: 'partner',
- fields: this.data.partner.fields,
- };
- }
-}, function () {
- QUnit.module('BasicModel');
-
- QUnit.test('can load a record', function (assert) {
- assert.expect(7);
-
- this.params.fieldNames = ['foo'];
- this.params.context = {active_field: 2};
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.deepEqual(args.kwargs.context, {
- active_field: 2,
- bin_size: true,
- someKey: 'some value',
- }, "should have sent the correct context");
- return this._super.apply(this, arguments);
- },
- session: {
- user_context: {someKey: 'some value'},
- }
- });
+ };
- assert.strictEqual(model.get(1), null, "should return null for non existing key");
+ // add related fields to category.
+ this.data.partner.fields.category.relatedFields =
+ $.extend(true, {}, this.data.partner_type.fields);
+ this.params = {
+ res_id: 2,
+ modelName: 'partner',
+ fields: this.data.partner.fields,
+ };
+ },
+ }, function () {
+ QUnit.module('BasicModel');
+
+ QUnit.test('can load a record', async function (assert) {
+ assert.expect(7);
+
+ this.params.fieldNames = ['foo'];
+ this.params.context = { active_field: 2 };
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.deepEqual(args.kwargs.context, {
+ active_field: 2,
+ bin_size: true,
+ someKey: 'some value',
+ }, "should have sent the correct context");
+ return this._super.apply(this, arguments);
+ },
+ session: {
+ user_context: { someKey: 'some value' },
+ }
+ });
- model.load(this.params).then(function (resultID) {
+ assert.strictEqual(model.get(1), null, "should return null for non existing key");
+
+ var resultID = await model.load(this.params);
// it is a string, because it is used as a key in an object
assert.strictEqual(typeof resultID, 'string', "result should be a valid id");
@@ -95,656 +95,637 @@ QUnit.module('Views', {
assert.strictEqual(record.type, 'record', "should be of type 'record'");
assert.strictEqual(record.data.foo, "gnap", "should correctly read value");
assert.strictEqual(record.data.bar, undefined, "should not fetch the field 'bar'");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('rejects loading a record with invalid id', function (assert) {
- assert.expect(1);
+ QUnit.test('rejects loading a record with invalid id', async function (assert) {
+ assert.expect(1);
- this.params.res_id = 99;
+ this.params.res_id = 99;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
+ try {
+ await model.load(this.params);
+ }
+ catch (e) {
+ assert.ok("load should return a rejected deferred for an invalid id");
+ }
- model.load(this.params).always(function (error) {
- assert.strictEqual(this.state(), 'rejected',
- "load should return a rejected deferred for an invalid id")
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('notify change with many2one', function (assert) {
- assert.expect(2);
+ QUnit.test('notify change with many2one', async function (assert) {
+ assert.expect(2);
- this.params.fieldNames = ['foo', 'qux'];
+ this.params.fieldNames = ['foo', 'qux'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.qux, false, "qux field should be false");
- model.notifyChanges(resultID, {qux: {id: 1, display_name: "hello"}});
+ await model.notifyChanges(resultID, { qux: { id: 1, display_name: "hello" } });
record = model.get(resultID);
assert.strictEqual(record.data.qux.data.id, 1, "qux field should be 1");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('notify change on many2one: unset and reset same value', function (assert) {
- assert.expect(3);
+ QUnit.test('notify change on many2one: unset and reset same value', async function (assert) {
+ assert.expect(3);
- this.data.partner.records[1].qux = 1;
+ this.data.partner.records[1].qux = 1;
- this.params.fieldNames = ['qux'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ this.params.fieldNames = ['qux'];
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.qux.data.id, 1, "qux value should be 1");
- model.notifyChanges(resultID, {qux: false});
+ await model.notifyChanges(resultID, { qux: false });
record = model.get(resultID);
assert.strictEqual(record.data.qux, false, "qux should be unset");
- model.notifyChanges(resultID, {qux: {id: 1, display_name: 'second_partner'}});
+ await model.notifyChanges(resultID, { qux: { id: 1, display_name: 'second_partner' } });
record = model.get(resultID);
assert.strictEqual(record.data.qux.data.id, 1, "qux value should be 1 again");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('write on a many2one', function (assert) {
- assert.expect(4);
- var self = this;
+ QUnit.test('write on a many2one', async function (assert) {
+ assert.expect(4);
+ var self = this;
- this.params.fieldNames = ['product_id'];
+ this.params.fieldNames = ['product_id'];
- var rpcCount = 0;
+ var rpcCount = 0;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- rpcCount++;
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ rpcCount++;
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id.data.display_name, 'xpad',
"should be initialized with correct value");
- model.notifyChanges(resultID, {product_id: {id: 37, display_name: 'xphone'}});
+ await model.notifyChanges(resultID, { product_id: { id: 37, display_name: 'xphone' } });
record = model.get(resultID);
assert.strictEqual(record.data.product_id.data.display_name, 'xphone',
"should be changed with correct value");
- model.save(resultID);
+ await model.save(resultID);
assert.strictEqual(self.data.partner.records[1].product_id, 37,
"should have really saved the data");
assert.strictEqual(rpcCount, 3, "should have done 3 rpc: 1 read, 1 write, 1 read");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('basic onchange', function (assert) {
- assert.expect(5);
-
- this.data.partner.fields.foo.onChange = true;
- this.data.partner.onchanges.foo = function (obj) {
- obj.bar = obj.foo.length;
- };
-
- this.params.fieldNames = ['foo', 'bar'];
- this.params.context = {hello: 'world'};
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'onchange') {
- var context = args.args[4];
- assert.deepEqual(context, {hello: 'world'},
- "context should be sent by the onchange");
- }
- return this._super(route, args);
- },
- });
+ QUnit.test('basic onchange', async function (assert) {
+ assert.expect(5);
+
+ this.data.partner.fields.foo.onChange = true;
+ this.data.partner.onchanges.foo = function (obj) {
+ obj.bar = obj.foo.length;
+ };
- model.load(this.params).then(function (resultID) {
+ this.params.fieldNames = ['foo', 'bar'];
+ this.params.context = { hello: 'world' };
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange') {
+ var context = args.args[4];
+ assert.deepEqual(context, { hello: 'world' },
+ "context should be sent by the onchange");
+ }
+ return this._super(route, args);
+ },
+ });
+
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.foo, 'gnap', "foo field is properly initialized");
assert.strictEqual(record.data.bar, 2, "bar field is properly initialized");
- model.notifyChanges(resultID, {foo: 'mary poppins'});
+ await model.notifyChanges(resultID, { foo: 'mary poppins' });
record = model.get(resultID);
assert.strictEqual(record.data.foo, 'mary poppins', "onchange has been applied");
assert.strictEqual(record.data.bar, 12, "onchange has been applied");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('onchange with a many2one', function (assert) {
- assert.expect(5);
+ QUnit.test('onchange with a many2one', async function (assert) {
+ assert.expect(5);
- this.data.partner.fields.product_id.onChange = true;
- this.data.partner.onchanges.product_id = function (obj) {
- if (obj.product_id === 37) {
- obj.foo = "space lollipop";
- }
- };
+ this.data.partner.fields.product_id.onChange = true;
+ this.data.partner.onchanges.product_id = function (obj) {
+ if (obj.product_id === 37) {
+ obj.foo = "space lollipop";
+ }
+ };
- this.params.fieldNames = ['foo', 'product_id'];
+ this.params.fieldNames = ['foo', 'product_id'];
- var rpcCount = 0;
+ var rpcCount = 0;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'onchange') {
- assert.strictEqual(args.args[2], "product_id",
- "should send the only changed field as a string, not a list");
- }
- rpcCount++;
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange') {
+ assert.strictEqual(args.args[2], "product_id",
+ "should send the only changed field as a string, not a list");
+ }
+ rpcCount++;
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.foo, 'gnap', "foo field is properly initialized");
assert.strictEqual(record.data.product_id.data.id, 41, "product_id field is properly initialized");
- model.notifyChanges(resultID, {product_id: {id: 37, display_name: 'xphone'}});
+ await model.notifyChanges(resultID, { product_id: { id: 37, display_name: 'xphone' } });
record = model.get(resultID);
assert.strictEqual(record.data.foo, 'space lollipop', "onchange has been applied");
assert.strictEqual(rpcCount, 2, "should have done 2 rpc: 1 read and 1 onchange");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('onchange on a one2many not in view (fieldNames)', function (assert) {
- assert.expect(6);
+ QUnit.test('onchange on a one2many not in view (fieldNames)', async function (assert) {
+ assert.expect(6);
- this.data.partner.fields.foo.onChange = true;
- this.data.partner.onchanges.foo = function (obj) {
- obj.bar = obj.foo.length;
- obj.product_ids = [];
- };
+ this.data.partner.fields.foo.onChange = true;
+ this.data.partner.onchanges.foo = function (obj) {
+ obj.bar = obj.foo.length;
+ obj.product_ids = [];
+ };
- this.params.fieldNames = ['foo'];
+ this.params.fieldNames = ['foo'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.foo, 'gnap', "foo field is properly initialized");
assert.strictEqual(record.data.bar, undefined, "bar field is not loaded");
assert.strictEqual(record.data.product_ids, undefined, "product_ids field is not loaded");
- model.notifyChanges(resultID, {foo: 'mary poppins'});
+ await model.notifyChanges(resultID, { foo: 'mary poppins' });
record = model.get(resultID);
assert.strictEqual(record.data.foo, 'mary poppins', "onchange has been applied");
assert.strictEqual(record.data.bar, 12, "onchange has been applied");
assert.strictEqual(record.data.product_ids, undefined,
"onchange on product_ids (one2many) has not been applied");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('notifyChange on a one2many', function (assert) {
- assert.expect(9);
+ QUnit.test('notifyChange on a one2many', async function (assert) {
+ assert.expect(9);
- this.data.partner.records[1].product_ids = [37];
- this.params.fieldNames = ['product_ids'];
+ this.data.partner.records[1].product_ids = [37];
+ this.params.fieldNames = ['product_ids'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'name_get') {
- assert.strictEqual(args.model, 'product');
- }
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'name_get') {
+ assert.strictEqual(args.model, 'product');
+ }
+ return this._super(route, args);
+ },
+ });
- var o2mParams = {
- modelName: 'product',
- fields: this.data.product.fields,
- fieldNames: ['display_name'],
- };
- model.load(this.params).then(function (resultID) {
- model.load(o2mParams).then(function (newRecordID) {
- var record = model.get(resultID);
- var x2mListID = record.data.product_ids.id;
+ var o2mParams = {
+ modelName: 'product',
+ fields: this.data.product.fields,
+ fieldNames: ['display_name'],
+ };
+ var resultID = await model.load(this.params);
+ var newRecordID = await model.load(o2mParams);
+ var record = model.get(resultID);
+ var x2mListID = record.data.product_ids.id;
- assert.strictEqual(record.data.product_ids.count, 1,
- "there should be one record in the relation");
+ assert.strictEqual(record.data.product_ids.count, 1,
+ "there should be one record in the relation");
- // trigger a 'ADD' command
- model.notifyChanges(resultID, {product_ids: {operation: 'ADD', id: newRecordID}});
+ // trigger a 'ADD' command
+ await model.notifyChanges(resultID, { product_ids: { operation: 'ADD', id: newRecordID } });
- assert.deepEqual(model.localData[x2mListID]._changes, [{
- operation: 'ADD', id: newRecordID,
- }], "_changes should be correct");
- record = model.get(resultID);
- assert.strictEqual(record.data.product_ids.count, 2,
- "there should be two records in the relation");
+ assert.deepEqual(model.localData[x2mListID]._changes, [{
+ operation: 'ADD', id: newRecordID,
+ }], "_changes should be correct");
+ record = model.get(resultID);
+ assert.strictEqual(record.data.product_ids.count, 2,
+ "there should be two records in the relation");
- // trigger a 'UPDATE' command
- model.notifyChanges(resultID, {product_ids: {operation: 'UPDATE', id: newRecordID}});
+ // trigger a 'UPDATE' command
+ await model.notifyChanges(resultID, { product_ids: { operation: 'UPDATE', id: newRecordID } });
- assert.deepEqual(model.localData[x2mListID]._changes, [{
- operation: 'ADD', id: newRecordID,
- }, {
- operation: 'UPDATE', id: newRecordID,
- }], "_changes should be correct");
- record = model.get(resultID);
- assert.strictEqual(record.data.product_ids.count, 2,
- "there should be two records in the relation");
-
- // trigger a 'DELETE' command on the existing record
- var existingRecordID = record.data.product_ids.data[0].id;
- model.notifyChanges(resultID, {product_ids: {operation: 'DELETE', ids: [existingRecordID]}});
-
- assert.deepEqual(model.localData[x2mListID]._changes, [{
- operation: 'ADD', id: newRecordID,
- }, {
- operation: 'UPDATE', id: newRecordID,
- }, {
- operation: 'DELETE', id: existingRecordID,
- }],
- "_changes should be correct");
- record = model.get(resultID);
- assert.strictEqual(record.data.product_ids.count, 1,
- "there should be one record in the relation");
+ assert.deepEqual(model.localData[x2mListID]._changes, [{
+ operation: 'ADD', id: newRecordID,
+ }, {
+ operation: 'UPDATE', id: newRecordID,
+ }], "_changes should be correct");
+ record = model.get(resultID);
+ assert.strictEqual(record.data.product_ids.count, 2,
+ "there should be two records in the relation");
- // trigger a 'DELETE' command on the new record
- model.notifyChanges(resultID, {product_ids: {operation: 'DELETE', ids: [newRecordID]}});
+ // trigger a 'DELETE' command on the existing record
+ var existingRecordID = record.data.product_ids.data[0].id;
+ await model.notifyChanges(resultID, { product_ids: { operation: 'DELETE', ids: [existingRecordID] } });
- assert.deepEqual(model.localData[x2mListID]._changes, [{
- operation: 'DELETE', id: existingRecordID,
- }], "_changes should be correct");
- record = model.get(resultID);
- assert.strictEqual(record.data.product_ids.count, 0,
- "there should be no record in the relation");
- });
+ assert.deepEqual(model.localData[x2mListID]._changes, [{
+ operation: 'ADD', id: newRecordID,
+ }, {
+ operation: 'UPDATE', id: newRecordID,
+ }, {
+ operation: 'DELETE', id: existingRecordID,
+ }],
+ "_changes should be correct");
+ record = model.get(resultID);
+ assert.strictEqual(record.data.product_ids.count, 1,
+ "there should be one record in the relation");
+
+ // trigger a 'DELETE' command on the new record
+ await model.notifyChanges(resultID, { product_ids: { operation: 'DELETE', ids: [newRecordID] } });
+
+ assert.deepEqual(model.localData[x2mListID]._changes, [{
+ operation: 'DELETE', id: existingRecordID,
+ }], "_changes should be correct");
+ record = model.get(resultID);
+ assert.strictEqual(record.data.product_ids.count, 0,
+ "there should be no record in the relation");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('notifyChange on a many2one, without display_name', function (assert) {
- assert.expect(3);
+ QUnit.test('notifyChange on a many2one, without display_name', async function (assert) {
+ assert.expect(3);
- this.params.fieldNames = ['product_id'];
+ this.params.fieldNames = ['product_id'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'name_get') {
- assert.strictEqual(args.model, 'product');
- }
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'name_get') {
+ assert.strictEqual(args.model, 'product');
+ }
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id.data.display_name, 'xpad',
"product_id field is set to xpad");
- model.notifyChanges(resultID, {product_id: {id: 37}});
+ await model.notifyChanges(resultID, { product_id: { id: 37 } });
record = model.get(resultID);
assert.strictEqual(record.data.product_id.data.display_name, 'xphone',
"display_name should have been fetched");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('onchange on a char with an unchanged many2one', function (assert) {
- assert.expect(2);
+ QUnit.test('onchange on a char with an unchanged many2one', async function (assert) {
+ assert.expect(2);
- this.data.partner.fields.foo.onChange = true;
- this.data.partner.onchanges.foo = function (obj) {
- obj.foo = obj.foo + " alligator";
- };
+ this.data.partner.fields.foo.onChange = true;
+ this.data.partner.onchanges.foo = function (obj) {
+ obj.foo = obj.foo + " alligator";
+ };
- this.params.fieldNames = ['foo', 'product_id'];
+ this.params.fieldNames = ['foo', 'product_id'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'onchange') {
- assert.strictEqual(args.args[1].product_id, 41, "should send correct value");
- }
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange') {
+ assert.strictEqual(args.args[1].product_id, 41, "should send correct value");
+ }
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
- model.notifyChanges(resultID, {foo: 'cookie'});
+ var resultID = await model.load(this.params);
+ await model.notifyChanges(resultID, { foo: 'cookie' });
var record = model.get(resultID);
assert.strictEqual(record.data.foo, 'cookie alligator', "onchange has been applied");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('onchange on a char with another many2one not set to a value', function (assert) {
- assert.expect(2);
- this.data.partner.records[0].product_id = false;
- this.data.partner.fields.foo.onChange = true;
- this.data.partner.onchanges.foo = function (obj) {
- obj.foo = obj.foo + " alligator";
- };
+ QUnit.test('onchange on a char with another many2one not set to a value', async function (assert) {
+ assert.expect(2);
+ this.data.partner.records[0].product_id = false;
+ this.data.partner.fields.foo.onChange = true;
+ this.data.partner.onchanges.foo = function (obj) {
+ obj.foo = obj.foo + " alligator";
+ };
- this.params.fieldNames = ['foo', 'product_id'];
- this.params.res_id = 1;
+ this.params.fieldNames = ['foo', 'product_id'];
+ this.params.res_id = 1;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id, false, "product_id is not set");
- model.notifyChanges(resultID, {foo: 'cookie'});
+ await model.notifyChanges(resultID, { foo: 'cookie' });
record = model.get(resultID);
assert.strictEqual(record.data.foo, 'cookie alligator', "onchange has been applied");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('can get a many2many', function (assert) {
- assert.expect(3);
+ QUnit.test('can get a many2many', async function (assert) {
+ assert.expect(3);
- this.params.res_id = 1;
- this.params.fieldsInfo = {
- default: {
- category: {
- fieldsInfo: {default: {display_name: {}}},
- relatedFields: {display_name: {type: "char"}},
- viewType: 'default',
+ this.params.res_id = 1;
+ this.params.fieldsInfo = {
+ default: {
+ category: {
+ fieldsInfo: { default: { display_name: {} } },
+ relatedFields: { display_name: { type: "char" } },
+ viewType: 'default',
+ },
},
- },
- };
+ };
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.category.data[0].res_id, 12,
"should have loaded many2many res_ids");
assert.strictEqual(record.data.category.data[0].data.display_name, "gold",
"should have loaded many2many display_name");
- record = model.get(resultID, {raw: true});
+ record = model.get(resultID, { raw: true });
assert.deepEqual(record.data.category, [12],
"with option raw, category should only return ids");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('can use command add and get many2many value with date field', function (assert) {
- assert.expect(2);
+ QUnit.test('can use command add and get many2many value with date field', async function (assert) {
+ assert.expect(2);
- this.params.fieldsInfo = {
- default: {
- category: {
- fieldsInfo: {default: {date: {}}},
- relatedFields: {date: {type: "date"}},
- viewType: 'default',
+ this.params.fieldsInfo = {
+ default: {
+ category: {
+ fieldsInfo: { default: { date: {} } },
+ relatedFields: { date: { type: "date" } },
+ viewType: 'default',
+ },
},
- },
- };
+ };
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var changes = {
- category: {operation: 'ADD_M2M', ids: [{id: 12}]}
+ category: { operation: 'ADD_M2M', ids: [{ id: 12 }] }
};
- model.notifyChanges(resultID, changes).then(function () {
- var record = model.get(resultID);
- assert.strictEqual(record.data.category.data.length, 1, "should have added one category");
- assert.strictEqual(record.data.category.data[0].data.date instanceof moment,
- true, "should have a date parsed in a moment object");
- });
+ await model.notifyChanges(resultID, changes);
+ var record = model.get(resultID);
+ assert.strictEqual(record.data.category.data.length, 1, "should have added one category");
+ assert.strictEqual(record.data.category.data[0].data.date instanceof moment,
+ true, "should have a date parsed in a moment object");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('many2many with ADD_M2M command and context with parent key', function (assert) {
- assert.expect(1);
+ QUnit.test('many2many with ADD_M2M command and context with parent key', async function (assert) {
+ assert.expect(1);
- this.data.partner_type.fields.some_char = {type: "char"};
- this.params.fieldsInfo = {
- default: {
- category: {
- fieldsInfo: {default: {some_char: { context: "{'a': parent.foo}"}}},
- relatedFields: {some_char: {type: "char"}},
- viewType: 'default',
+ this.data.partner_type.fields.some_char = { type: "char" };
+ this.params.fieldsInfo = {
+ default: {
+ category: {
+ fieldsInfo: { default: { some_char: { context: "{'a': parent.foo}" } } },
+ relatedFields: { some_char: { type: "char" } },
+ viewType: 'default',
+ },
+ foo: {},
},
- foo: {},
- },
- };
+ };
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var changes = {
- category: {operation: 'ADD_M2M', ids: [{id: 12}]}
+ category: { operation: 'ADD_M2M', ids: [{ id: 12 }] }
};
- model.notifyChanges(resultID, changes).then(function () {
- var record = model.get(resultID);
- var categoryRecord = record.data.category.data[0];
- assert.deepEqual(categoryRecord.getContext({fieldName: 'some_char'}), {a:'gnap'},
- "should properly evaluate context");
+ await model.notifyChanges(resultID, changes);
+ var record = model.get(resultID);
+ var categoryRecord = record.data.category.data[0];
+ assert.deepEqual(categoryRecord.getContext({ fieldName: 'some_char' }), { a: 'gnap' },
+ "should properly evaluate context");
+ model.destroy();
+ });
+
+ QUnit.test('can fetch a list', async function (assert) {
+ assert.expect(4);
+
+ this.params.fieldNames = ['foo'];
+ this.params.domain = [];
+ this.params.groupedBy = [];
+ this.params.res_id = undefined;
+ this.params.context = { active_field: 2 };
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.strictEqual(args.context.active_field, 2,
+ "should have sent the correct context");
+ return this._super(route, args);
+ },
});
- });
- model.destroy();
- });
-
- QUnit.test('can fetch a list', function (assert) {
- assert.expect(4);
-
- this.params.fieldNames = ['foo'];
- this.params.domain = [];
- this.params.groupedBy = [];
- this.params.res_id = undefined;
- this.params.context = {active_field: 2};
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.strictEqual(args.context.active_field, 2,
- "should have sent the correct context");
- return this._super(route, args);
- },
- });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.type, 'list', "record fetched should be a list");
assert.strictEqual(record.data.length, 2, "should have fetched 2 records");
assert.strictEqual(record.data[0].data.foo, 'blip', "first record should have 'blip' in foo field");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('fetch x2manys in list, with not too many rpcs', function (assert) {
- assert.expect(3);
+ QUnit.test('fetch x2manys in list, with not too many rpcs', async function (assert) {
+ assert.expect(3);
- this.data.partner.records[0].category = [12, 15];
- this.data.partner.records[1].category = [12, 14];
+ this.data.partner.records[0].category = [12, 15];
+ this.data.partner.records[1].category = [12, 14];
- this.params.fieldNames = ['category'];
- this.params.domain = [];
- this.params.groupedBy = [];
- this.params.res_id = undefined;
+ this.params.fieldNames = ['category'];
+ this.params.domain = [];
+ this.params.groupedBy = [];
+ this.params.res_id = undefined;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.step(route);
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(route);
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data[0].data.category.data.length, 2,
"first record should have 2 categories loaded");
assert.verifySteps(["/web/dataset/search_read"],
"should have done 2 rpc (searchread and read category)");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('can make a default_record, no onchange', function (assert) {
- assert.expect(5);
-
- this.params.context = {};
- this.params.fieldNames = ['product_id', 'category', 'product_ids'];
- this.params.res_id = undefined;
- this.params.type = 'record';
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.step(args.method);
- return this._super(route, args);
- },
- });
+ QUnit.test('can make a default_record, no onchange', async function (assert) {
+ assert.expect(5);
- model.load(this.params).then(function (resultID) {
+ this.params.context = {};
+ this.params.fieldNames = ['product_id', 'category', 'product_ids'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method);
+ return this._super(route, args);
+ },
+ });
+
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id, false, "m2o default value should be false");
assert.deepEqual(record.data.product_ids.data, [], "o2m default should be []");
assert.deepEqual(record.data.category.data, [], "m2m default should be []");
+
+ assert.verifySteps(['default_get'],
+ "there should be default_get");
+
+ model.destroy();
});
- assert.verifySteps(['default_get'],
- "there should be default_get");
+ QUnit.test('default_get returning a non requested field', async function (assert) {
+ // 'default_get' returns a default value for the fields given in
+ // arguments. It should not return a value for fields that have not be
+ // requested. However, it happens (e.g. res.users), and the webclient
+ // should not crash when this situation occurs (the field should simply
+ // be ignored).
+ assert.expect(2);
- model.destroy();
- });
+ this.params.context = {};
+ this.params.fieldNames = ['category'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
- QUnit.test('default_get returning a non requested field', function (assert) {
- // 'default_get' returns a default value for the fields given in
- // arguments. It should not return a value for fields that have not be
- // requested. However, it happens (e.g. res.users), and the webclient
- // should not crash when this situation occurs (the field should simply
- // be ignored).
- assert.expect(2);
-
- this.params.context = {};
- this.params.fieldNames = ['category'];
- this.params.res_id = undefined;
- this.params.type = 'record';
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- var result = this._super(route, args);
- if (args.method === 'default_get') {
- result.product_ids = [[6, 0, [37, 41]]];
- }
- return result;
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ var result = this._super(route, args);
+ if (args.method === 'default_get') {
+ result.product_ids = [[6, 0, [37, 41]]];
+ }
+ return result;
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.ok('category' in record.data,
"should have processed 'category'");
assert.notOk('product_ids' in record.data,
"should have ignored 'product_ids'");
+
+ model.destroy();
});
- model.destroy();
- });
+ QUnit.test('can make a default_record with default relational values', async function (assert) {
+ assert.expect(7);
- QUnit.test('can make a default_record with default relational values', function (assert) {
- assert.expect(7);
-
- this.data.partner.fields.product_id.default = 37;
- this.data.partner.fields.product_ids.default = [
- [0, false, {name: 'xmac'}],
- [0, false, {name: 'xcloud'}]
- ];
- this.data.partner.fields.category.default = [
- [6, false, [12, 14]]
- ];
-
- this.params.fieldNames = ['product_id', 'category', 'product_ids'];
- this.params.res_id = undefined;
- this.params.type = 'record';
- this.params.fieldsInfo = {
- form: {
- category: {},
- product_id: {},
- product_ids: {
- fieldsInfo: {
- default: { name: {} },
+ this.data.partner.fields.product_id.default = 37;
+ this.data.partner.fields.product_ids.default = [
+ [0, false, { name: 'xmac' }],
+ [0, false, { name: 'xcloud' }]
+ ];
+ this.data.partner.fields.category.default = [
+ [6, false, [12, 14]]
+ ];
+
+ this.params.fieldNames = ['product_id', 'category', 'product_ids'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
+ this.params.fieldsInfo = {
+ form: {
+ category: {},
+ product_id: {},
+ product_ids: {
+ fieldsInfo: {
+ default: { name: {} },
+ },
+ relatedFields: this.data.product.fields,
+ viewType: 'default',
},
- relatedFields: this.data.product.fields,
- viewType: 'default',
},
- },
- };
- this.params.viewType = 'form';
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.step(args.method);
- return this._super(route, args);
- },
- });
+ };
+ this.params.viewType = 'form';
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method);
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.deepEqual(record.data.product_id.data.display_name, 'xphone',
"m2o default should be xphone");
@@ -754,217 +735,211 @@ QUnit.module('Views', {
'xmac', "first o2m default value should be xmac");
assert.deepEqual(record.data.category.res_ids, [12, 14],
"m2m default should be [12, 14]");
- });
- assert.verifySteps(['default_get', 'name_get'],
- "there should be default_get and name_get");
+ assert.verifySteps(['default_get', 'name_get'],
+ "there should be default_get and name_get");
- model.destroy();
- });
+ model.destroy();
+ });
- QUnit.test('default_record, with onchange on many2one', function (assert) {
- assert.expect(1);
+ QUnit.test('default_record, with onchange on many2one', async function (assert) {
+ assert.expect(1);
- // the onchange is done by the mockRPC because we want to return a value
- // of 'false', which does not work with the mockserver mockOnChange method.
- this.data.partner.onchanges.product_id = true;
+ // the onchange is done by the mockRPC because we want to return a value
+ // of 'false', which does not work with the mockserver mockOnChange method.
+ this.data.partner.onchanges.product_id = true;
- this.params.context = {};
- this.params.fieldNames = ['product_id'];
- this.params.res_id = undefined;
- this.params.type = 'record';
+ this.params.context = {};
+ this.params.fieldNames = ['product_id'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'onchange') {
- return $.when({value: { product_id: false }});
- }
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange') {
+ return Promise.resolve({ value: { product_id: false } });
+ }
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id, false, "m2o default value should be false");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('default record: batch namegets on same model and res_id', function (assert) {
- assert.expect(3);
-
- var rpcCount = 0;
- var fields = this.data.partner.fields;
- fields.other_product_id = _.extend({}, fields.product_id);
- fields.product_id.default = 37;
- fields.other_product_id.default = 41;
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- rpcCount++;
- return this._super(route, args);
- },
- });
+ QUnit.test('default record: batch namegets on same model and res_id', async function (assert) {
+ assert.expect(3);
+
+ var rpcCount = 0;
+ var fields = this.data.partner.fields;
+ fields.other_product_id = _.extend({}, fields.product_id);
+ fields.product_id.default = 37;
+ fields.other_product_id.default = 41;
- var params = {
- context: {},
- fieldNames: ['other_product_id', 'product_id'],
- fields: fields,
- modelName: 'partner',
- type: 'record',
- };
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ rpcCount++;
+ return this._super(route, args);
+ },
+ });
+
+ var params = {
+ context: {},
+ fieldNames: ['other_product_id', 'product_id'],
+ fields: fields,
+ modelName: 'partner',
+ type: 'record',
+ };
- model.load(params).then(function (resultID) {
+ var resultID = await model.load(params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id.data.display_name, "xphone",
"should have fetched correct name");
assert.strictEqual(record.data.other_product_id.data.display_name, "xpad",
"should have fetched correct name");
assert.strictEqual(rpcCount, 2, "should have done 2 rpcs: default_get and 1 name_get");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('undoing a change makes the record not dirty', function (assert) {
- assert.expect(4);
+ QUnit.test('undoing a change makes the record not dirty', async function (assert) {
+ assert.expect(4);
- this.params.fieldNames = ['foo'];
+ this.params.fieldNames = ['foo'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.foo, "gnap", "foo field should properly be set");
assert.ok(!model.isDirty(resultID), "record should not be dirty");
- model.notifyChanges(resultID, {foo: "hello"});
+ await model.notifyChanges(resultID, { foo: "hello" });
assert.ok(model.isDirty(resultID), "record should be dirty");
- model.notifyChanges(resultID, {foo: "gnap"});
+ await model.notifyChanges(resultID, { foo: "gnap" });
assert.ok(!model.isDirty(resultID), "record should not be dirty");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('isDirty works correctly on list made empty', function (assert) {
- assert.expect(3);
+ QUnit.test('isDirty works correctly on list made empty', async function (assert) {
+ assert.expect(3);
- this.params.fieldNames = ['category'];
- this.params.res_id = 1;
+ this.params.fieldNames = ['category'];
+ this.params.res_id = 1;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
var category_value = record.data.category;
assert.ok(_.isObject(category_value), "category field should have been fetched");
assert.strictEqual(category_value.data.length, 1, "category field should contain one record");
- model.notifyChanges(resultID, {category: {
- operation: 'DELETE',
- ids: [category_value.data[0].id],
- }});
+ await model.notifyChanges(resultID, {
+ category: {
+ operation: 'DELETE',
+ ids: [category_value.data[0].id],
+ }
+ });
assert.ok(model.isDirty(resultID), "record should be considered dirty");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('can duplicate a record', function (assert) {
- assert.expect(4);
+ QUnit.test('can duplicate a record', async function (assert) {
+ assert.expect(4);
- this.params.fieldNames = ['foo'];
+ this.params.fieldNames = ['foo'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.display_name, "second partner",
"record should have correct display name");
assert.strictEqual(record.data.foo, "gnap", "foo should be set to correct value");
- model.duplicateRecord(resultID).then(function (duplicateID) {
- var duplicate = model.get(duplicateID);
- assert.strictEqual(duplicate.data.display_name, "second partner (copy)",
- "record should have been duplicated");
- assert.strictEqual(duplicate.data.foo, "gnap", "foo should be set to correct value");
- });
+ var duplicateID = await model.duplicateRecord(resultID);
+ var duplicate = model.get(duplicateID);
+ assert.strictEqual(duplicate.data.display_name, "second partner (copy)",
+ "record should have been duplicated");
+ assert.strictEqual(duplicate.data.foo, "gnap", "foo should be set to correct value");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('record with many2one set to some value, then set it to none', function (assert) {
- assert.expect(3);
+ QUnit.test('record with many2one set to some value, then set it to none', async function (assert) {
+ assert.expect(3);
- this.params.fieldNames = ['product_id'];
+ this.params.fieldNames = ['product_id'];
- var self = this;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var self = this;
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_id.data.display_name, 'xpad', "product_id should be set");
- model.notifyChanges(resultID, {product_id: false});
+ await model.notifyChanges(resultID, { product_id: false });
record = model.get(resultID);
assert.strictEqual(record.data.product_id, false, "product_id should not be set");
- model.save(resultID);
+ await model.save(resultID);
assert.strictEqual(self.data.partner.records[1].product_id, false,
"should have saved the new product_id value");
- });
- model.destroy();
- });
-
- QUnit.test('internal state of groups remains when reloading', function (assert) {
- assert.expect(10);
-
- this.params.fieldNames = ['foo'];
- this.params.domain = [];
- this.params.limit = 80;
- this.params.groupedBy = ['product_id'];
- this.params.res_id = undefined;
-
- var filterEnabled = false;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'read_group' && filterEnabled) {
- // as this is not yet supported by the MockServer, simulates
- // a read_group that returns empty groups
- // this is the case for several models (e.g. project.task
- // grouped by stage_id)
- return this._super.apply(this, arguments).then(function (result) {
- // artificially filter out records of first group
- result[0].product_id_count = 0;
- return result;
- });
- }
- return this._super.apply(this, arguments);
- },
- });
+ model.destroy();
+ });
+
+ QUnit.test('internal state of groups remains when reloading', async function (assert) {
+ assert.expect(10);
+
+ this.params.fieldNames = ['foo'];
+ this.params.domain = [];
+ this.params.limit = 80;
+ this.params.groupedBy = ['product_id'];
+ this.params.res_id = undefined;
+
+ var filterEnabled = false;
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'read_group' && filterEnabled) {
+ // as this is not yet supported by the MockServer, simulates
+ // a read_group that returns empty groups
+ // this is the case for several models (e.g. project.task
+ // grouped by stage_id)
+ return this._super.apply(this, arguments).then(function (result) {
+ // artificially filter out records of first group
+ result[0].product_id_count = 0;
+ return result;
+ });
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.length, 2, "should have 2 groups");
var groupID = record.data[0].id;
assert.strictEqual(model.localData[groupID].parentID, resultID,
"parentID should be correctly set on groups");
- model.toggleGroup(groupID);
+ await model.toggleGroup(groupID);
record = model.get(resultID);
assert.ok(record.data[0].isOpen, "first group should be open");
@@ -976,7 +951,7 @@ QUnit.module('Views', {
// change the limit and offset of the first group
model.localData[record.data[0].id].limit = 10;
- model.reload(resultID);
+ await model.reload(resultID);
record = model.get(resultID);
assert.ok(record.data[0].isOpen, "first group should still be open");
assert.strictEqual(record.data[0].data.length, 1,
@@ -987,193 +962,188 @@ QUnit.module('Views', {
// filter some records out: the open group should stay open but now
// be empty
filterEnabled = true;
- model.reload(resultID);
+ await model.reload(resultID);
record = model.get(resultID);
assert.strictEqual(record.data[0].count, 0,
"first group's count should be 0");
assert.strictEqual(record.data[0].data.length, 0,
"first group's data should be empty'");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('group on date field with magic grouping method', function (assert) {
- assert.expect(1);
+ QUnit.test('group on date field with magic grouping method', async function (assert) {
+ assert.expect(1);
- this.params.fieldNames = ['foo'];
- this.params.groupedBy = ['date:month'];
- this.params.res_id = undefined;
+ this.params.fieldNames = ['foo'];
+ this.params.groupedBy = ['date:month'];
+ this.params.res_id = undefined;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'read_group') {
- assert.deepEqual(args.kwargs.fields, ['foo', 'date'],
- "should have correctly trimmed the magic grouping info from the field name");
- }
- return this._super.apply(this, arguments);
- },
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'read_group') {
+ assert.deepEqual(args.kwargs.fields, ['foo', 'date'],
+ "should have correctly trimmed the magic grouping info from the field name");
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ await model.load(this.params);
+ model.destroy();
});
- model.load(this.params);
- model.destroy();
- });
+ QUnit.test('read group when grouped by a selection field', async function (assert) {
+ assert.expect(5);
- QUnit.test('read group when grouped by a selection field', function (assert) {
- assert.expect(5);
+ this.data.partner.fields.selection = {
+ type: 'selection',
+ selection: [['a', 'A'], ['b', 'B']],
+ };
+ this.data.partner.records[0].selection = 'a';
- this.data.partner.fields.selection = {
- type: 'selection',
- selection: [['a', 'A'], ['b', 'B']],
- };
- this.data.partner.records[0].selection = 'a';
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
+ var params = {
+ modelName: 'partner',
+ fields: this.data.partner.fields,
+ fieldNames: ['foo'],
+ groupedBy: ['selection'],
+ };
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
- var params = {
- modelName: 'partner',
- fields: this.data.partner.fields,
- fieldNames: ['foo'],
- groupedBy: ['selection'],
- };
-
- model.load(params).then(function (resultID) {
+ var resultID = await model.load(params);
var dataPoint = model.get(resultID);
assert.strictEqual(dataPoint.data.length, 2, "should have two groups");
- var groupFalse = _.findWhere(dataPoint.data, {value: false});
+ var groupFalse = _.findWhere(dataPoint.data, { value: false });
assert.ok(groupFalse, "should have a group for value false");
assert.deepEqual(groupFalse.domain, [['selection', '=', false]],
"group's domain should be correct");
- var groupA = _.findWhere(dataPoint.data, {value: 'A'});
+ var groupA = _.findWhere(dataPoint.data, { value: 'A' });
assert.ok(groupA, "should have a group for value 'a'");
assert.deepEqual(groupA.domain, [['selection', '=', 'a']],
"group's domain should be correct");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('create record, then save', function (assert) {
- assert.expect(5);
-
- this.params.fieldNames = ['product_ids'];
- this.params.res_id = undefined;
- this.params.type = 'record';
- this.params.context = {active_field: 2};
-
- var id;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'create') {
- // has to be done before the call to _super
- assert.notOk('product_ids' in args.args[0], "should not have any value");
- assert.notOk('category' in args.args[0], "should not have other fields");
-
- assert.strictEqual(args.kwargs.context.active_field, 2,
- "record's context should be correctly passed");
- }
- var result = this._super(route, args);
- if (args.method === 'create') {
- result.then(function (res) {
- id = res;
- });
- }
- return result;
- },
- });
+ QUnit.test('create record, then save', async function (assert) {
+ assert.expect(5);
+
+ this.params.fieldNames = ['product_ids'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
+ this.params.context = { active_field: 2 };
- model.load(this.params).then(function (resultID) {
+ var id;
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'create') {
+ // has to be done before the call to _super
+ assert.notOk('product_ids' in args.args[0], "should not have any value");
+ assert.notOk('category' in args.args[0], "should not have other fields");
+
+ assert.strictEqual(args.kwargs.context.active_field, 2,
+ "record's context should be correctly passed");
+ }
+ var result = this._super(route, args);
+ if (args.method === 'create') {
+ result.then(function (res) {
+ id = res;
+ });
+ }
+ return result;
+ },
+ });
+
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
- model.save(record.id, {reload: false});
+ await model.save(record.id, { reload: false });
record = model.get(resultID);
assert.strictEqual(record.res_id, id, "should have correct id from server");
assert.strictEqual(record.data.id, id, "should have correct id from server");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('write commands on a one2many', function (assert) {
- assert.expect(4);
+ QUnit.test('write commands on a one2many', async function (assert) {
+ assert.expect(4);
- this.data.partner.records[1].product_ids = [37];
+ this.data.partner.records[1].product_ids = [37];
- this.params.fieldNames = ['product_ids'];
+ this.params.fieldNames = ['product_ids'];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'write') {
- assert.deepEqual(args.args[0], [2], "should write on res_id = 2");
- var commands = args.args[1].product_ids;
- assert.deepEqual(commands[0], [4, 37, false], "first command should be a 4");
- // TO DO: uncomment next line
- // assert.strictEqual(commands[1], [0, false, {name: "toy"}], "second command should be a 0");
- assert.strictEqual(commands[1][0], 0, "second command should be a 0");
- }
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'write') {
+ assert.deepEqual(args.args[0], [2], "should write on res_id = 2");
+ var commands = args.args[1].product_ids;
+ assert.deepEqual(commands[0], [4, 37, false], "first command should be a 4");
+ // TO DO: uncomment next line
+ // assert.strictEqual(commands[1], [0, false, {name: "toy"}], "second command should be a 0");
+ assert.strictEqual(commands[1][0], 0, "second command should be a 0");
+ }
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
- var record = model.get(resultID, {raw: true});
+ var resultID = await model.load(this.params);
+ var record = model.get(resultID, { raw: true });
assert.deepEqual(record.data.product_ids, [37], "should have correct initial value");
- model.makeRecord('product', [{
- name: 'name',
- string: "Product Name",
- type: "char",
- value: "xpod"
- }
- ]).then(function (relatedRecordID) {
- model.notifyChanges(record.id, {
- product_ids: {operation: "ADD", id: relatedRecordID}
- });
- model.save(record.id);
+ var relatedRecordID = await model.makeRecord('product', [{
+ name: 'name',
+ string: "Product Name",
+ type: "char",
+ value: "xpod"
+ }
+ ]);
+ await model.notifyChanges(record.id, {
+ product_ids: { operation: "ADD", id: relatedRecordID }
});
+ await model.save(record.id);
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('create commands on a one2many', function (assert) {
- assert.expect(3);
+ QUnit.test('create commands on a one2many', async function (assert) {
+ assert.expect(3);
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- return this._super(route, args);
- },
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ return this._super(route, args);
+ },
+ });
- this.params.fieldsInfo = {
- default: {
- product_ids: {
- fieldsInfo: {
- default: {
- display_name: {type: 'string'},
- }
- },
- viewType: 'default',
+ this.params.fieldsInfo = {
+ default: {
+ product_ids: {
+ fieldsInfo: {
+ default: {
+ display_name: { type: 'string' },
+ }
+ },
+ viewType: 'default',
+ }
}
- }
- };
- this.params.res_id = undefined;
- this.params.type = 'record';
+ };
+ this.params.res_id = undefined;
+ this.params.type = 'record';
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_ids.data.length, 0,
"one2many should start with a list of length 0");
- model.notifyChanges(record.id, {
+ await model.notifyChanges(record.id, {
product_ids: {
operation: "CREATE",
data: {
@@ -1186,279 +1156,275 @@ QUnit.module('Views', {
"one2many should be a list of length 1");
assert.strictEqual(record.data.product_ids.data[0].data.display_name, "coucou",
"one2many should have correct data");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('onchange with a one2many on a new record', function (assert) {
- assert.expect(4);
+ QUnit.test('onchange with a one2many on a new record', async function (assert) {
+ assert.expect(4);
- this.data.partner.fields.total.default = 50;
- this.data.partner.fields.product_ids.onChange = true;
- this.data.partner.onchanges.product_ids = function (obj) {
- obj.total += 100;
- };
+ this.data.partner.fields.total.default = 50;
+ this.data.partner.fields.product_ids.onChange = true;
+ this.data.partner.onchanges.product_ids = function (obj) {
+ obj.total += 100;
+ };
- this.params.fieldNames = ['total', 'product_ids'];
- this.params.res_id = undefined;
- this.params.type = 'record';
- this.params.fieldsInfo = {
- form: {
- product_ids: {
- fieldsInfo: {
- default: { name: {} },
+ this.params.fieldNames = ['total', 'product_ids'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
+ this.params.fieldsInfo = {
+ form: {
+ product_ids: {
+ fieldsInfo: {
+ default: { name: {} },
+ },
+ relatedFields: this.data.product.fields,
+ viewType: 'default',
},
- relatedFields: this.data.product.fields,
- viewType: 'default',
+ total: {},
},
- total: {},
- },
- };
- this.params.viewType = 'form';
-
- var o2mRecordParams = {
- fields: this.data.product.fields,
- fieldNames: ['name'],
- modelName: 'product',
- type: 'record',
- };
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'onchange' && args.args[1].total === 150) {
- assert.deepEqual(args.args[1].product_ids, [[0, args.args[1].product_ids[0][1], {name: "xpod"}]],
- "Should have sent the create command in the onchange");
- }
- return this._super(route, args);
- },
- });
+ };
+ this.params.viewType = 'form';
+
+ var o2mRecordParams = {
+ fields: this.data.product.fields,
+ fieldNames: ['name'],
+ modelName: 'product',
+ type: 'record',
+ };
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'onchange' && args.args[1].total === 150) {
+ assert.deepEqual(args.args[1].product_ids, [[0, args.args[1].product_ids[0][1], { name: "xpod" }]],
+ "Should have sent the create command in the onchange");
+ }
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.product_ids.data.length, 0,
"one2many should start with a list of length 0");
// make a default record for the related model
- model.load(o2mRecordParams).then(function (relatedRecordID) {
- // update the subrecord
- model.notifyChanges(relatedRecordID, {name: 'xpod'});
- // add the subrecord to the o2m of the main record
- model.notifyChanges(resultID, {
- product_ids: {operation: "ADD", id: relatedRecordID}
- });
-
- record = model.get(resultID);
- assert.strictEqual(record.data.product_ids.data.length, 1,
- "one2many should be a list of length 1");
- assert.strictEqual(record.data.product_ids.data[0].data.name, "xpod",
- "one2many should have correct data");
+ var relatedRecordID = await model.load(o2mRecordParams);
+ // update the subrecord
+ await model.notifyChanges(relatedRecordID, { name: 'xpod' });
+ // add the subrecord to the o2m of the main record
+ await model.notifyChanges(resultID, {
+ product_ids: { operation: "ADD", id: relatedRecordID }
});
+
+ record = model.get(resultID);
+ assert.strictEqual(record.data.product_ids.data.length, 1,
+ "one2many should be a list of length 1");
+ assert.strictEqual(record.data.product_ids.data[0].data.name, "xpod",
+ "one2many should have correct data");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('dates are properly loaded and parsed (record)', function (assert) {
- assert.expect(2);
+ QUnit.test('dates are properly loaded and parsed (record)', async function (assert) {
+ assert.expect(2);
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- var params = {
- fieldNames: ['date'],
- fields: this.data.partner.fields,
- modelName: 'partner',
- res_id: 1,
- };
+ var params = {
+ fieldNames: ['date'],
+ fields: this.data.partner.fields,
+ modelName: 'partner',
+ res_id: 1,
+ };
- model.load(params).then(function (resultID) {
- var record = model.get(resultID);
- assert.ok(record.data.date instanceof moment,
- "fetched date field should have been formatted");
- });
+ model.load(params).then(function (resultID) {
+ var record = model.get(resultID);
+ assert.ok(record.data.date instanceof moment,
+ "fetched date field should have been formatted");
+ });
- params.res_id = 2;
+ params.res_id = 2;
- model.load(params).then(function (resultID) {
- var record = model.get(resultID);
- assert.strictEqual(record.data.date, false,
- "unset date field should be false");
+ model.load(params).then(function (resultID) {
+ var record = model.get(resultID);
+ assert.strictEqual(record.data.date, false,
+ "unset date field should be false");
+ });
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('dates are properly loaded and parsed (list)', function (assert) {
- assert.expect(2);
+ QUnit.test('dates are properly loaded and parsed (list)', async function (assert) {
+ assert.expect(2);
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- var params = {
- fieldNames: ['date'],
- fields: this.data.partner.fields,
- modelName: 'partner',
- type: 'list',
- };
+ var params = {
+ fieldNames: ['date'],
+ fields: this.data.partner.fields,
+ modelName: 'partner',
+ type: 'list',
+ };
- model.load(params).then(function (resultID) {
- var record = model.get(resultID);
- var firstRecord = record.data[0];
- var secondRecord = record.data[1];
- assert.ok(firstRecord.data.date instanceof moment,
- "fetched date field should have been formatted");
- assert.strictEqual(secondRecord.data.date, false,
- "if date is not set, it should be false");
+ model.load(params).then(function (resultID) {
+ var record = model.get(resultID);
+ var firstRecord = record.data[0];
+ var secondRecord = record.data[1];
+ assert.ok(firstRecord.data.date instanceof moment,
+ "fetched date field should have been formatted");
+ assert.strictEqual(secondRecord.data.date, false,
+ "if date is not set, it should be false");
+ });
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('dates are properly loaded and parsed (default_get)', function (assert) {
- assert.expect(1);
+ QUnit.test('dates are properly loaded and parsed (default_get)', async function (assert) {
+ assert.expect(1);
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- var params = {
- fieldNames: ['date'],
- fields: this.data.partner.fields,
- modelName: 'partner',
- type: 'record',
- };
+ var params = {
+ fieldNames: ['date'],
+ fields: this.data.partner.fields,
+ modelName: 'partner',
+ type: 'record',
+ };
- model.load(params).then(function (resultID) {
- var record = model.get(resultID);
- assert.strictEqual(record.data.date, false, "date default value should be false");
+ model.load(params).then(function (resultID) {
+ var record = model.get(resultID);
+ assert.strictEqual(record.data.date, false, "date default value should be false");
+ });
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('default_get on x2many may return a list of ids', function (assert) {
- assert.expect(1);
+ QUnit.test('default_get on x2many may return a list of ids', async function (assert) {
+ assert.expect(1);
- this.data.partner.fields.category.default = [12, 14];
+ this.data.partner.fields.category.default = [12, 14];
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- var params = {
- fieldNames: ['category'],
- fields: this.data.partner.fields,
- modelName: 'partner',
- type: 'record',
- };
+ var params = {
+ fieldNames: ['category'],
+ fields: this.data.partner.fields,
+ modelName: 'partner',
+ type: 'record',
+ };
- model.load(params).then(function (resultID) {
- var record = model.get(resultID);
- assert.ok(_.isEqual(record.data.category.res_ids, [12, 14]),
- "category field should have correct default value");
- });
+ model.load(params).then(function (resultID) {
+ var record = model.get(resultID);
+ assert.ok(_.isEqual(record.data.category.res_ids, [12, 14]),
+ "category field should have correct default value");
+ });
- model.destroy();
- });
+ model.destroy();
+ });
- QUnit.test('default_get: fetch many2one with default (empty & not) inside x2manys', function (assert) {
- assert.expect(4);
+ QUnit.test('default_get: fetch many2one with default (empty & not) inside x2manys', async 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);
- },
- });
+ 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: {} },
+ 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',
},
- viewType: 'list',
},
},
- },
- modelName: 'partner',
- type: 'record',
- viewType: 'form',
- };
+ modelName: 'partner',
+ type: 'record',
+ viewType: 'form',
+ };
- model.load(params).then(function (resultID) {
+ var resultID = await model.load(params);
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();
- });
+ model.destroy();
+ });
- QUnit.test('default_get: fetch x2manys inside x2manys', function (assert) {
- assert.expect(3);
+ QUnit.test('default_get: fetch x2manys inside x2manys', async function (assert) {
+ assert.expect(3);
- this.data.partner.fields.o2m = {
- string: "O2M", type: 'one2many', relation: 'partner', default: [[6, 0, [1]]],
- };
+ this.data.partner.fields.o2m = {
+ string: "O2M", type: 'one2many', relation: 'partner', default: [[6, 0, [1]]],
+ };
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- var params = {
- fieldNames: ['o2m'],
- fields: this.data.partner.fields,
- fieldsInfo: {
- form: {
- o2m: {
- relatedFields: this.data.partner.fields,
- fieldsInfo: {
- list: {
- category: {
- relatedFields: { display_name: {} },
+ 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',
},
- viewType: 'list',
},
},
- },
- modelName: 'partner',
- type: 'record',
- viewType: 'form',
- };
+ modelName: 'partner',
+ type: 'record',
+ viewType: 'form',
+ };
- model.load(params).then(function (resultID) {
+ var resultID = await model.load(params);
var record = model.get(resultID);
assert.strictEqual(record.data.o2m.count, 1, "o2m field should contain 1 record");
var categoryList = record.data.o2m.data[0].data.category;
@@ -1466,25 +1432,24 @@ QUnit.module('Views', {
"category field should contain 1 record");
assert.strictEqual(categoryList.data[0].data.display_name,
'gold', "category records should have been fetched");
- });
- model.destroy();
- });
+ model.destroy();
+ });
- QUnit.test('contexts and domains can be properly fetched', function (assert) {
- assert.expect(8);
+ QUnit.test('contexts and domains can be properly fetched', async function (assert) {
+ assert.expect(8);
- this.data.partner.fields.product_id.context = "{'hello': 'world', 'test': foo}";
- this.data.partner.fields.product_id.domain = "[['hello', 'like', 'world'], ['test', 'like', foo]]";
+ this.data.partner.fields.product_id.context = "{'hello': 'world', 'test': foo}";
+ this.data.partner.fields.product_id.domain = "[['hello', 'like', 'world'], ['test', 'like', foo]]";
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- this.params.fieldNames = ['product_id', 'foo'];
+ this.params.fieldNames = ['product_id', 'foo'];
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var recordPartner = model.get(resultID);
assert.strictEqual(typeof recordPartner.getContext, "function",
"partner record should have a getContext function");
@@ -1495,280 +1460,273 @@ QUnit.module('Views', {
assert.deepEqual(recordPartner.getDomain(), [],
"asking for a domain without a field name should fetch the session/user/view domain");
assert.deepEqual(
- recordPartner.getContext({fieldName: "product_id"}),
- {hello: "world", test: "gnap"},
+ recordPartner.getContext({ fieldName: "product_id" }),
+ { hello: "world", test: "gnap" },
"asking for a context with a field name should fetch the field context (evaluated)");
assert.deepEqual(
- recordPartner.getDomain({fieldName: "product_id"}),
+ recordPartner.getDomain({ fieldName: "product_id" }),
[["hello", "like", "world"], ["test", "like", "gnap"]],
"asking for a domain with a field name should fetch the field domain (evaluated)");
- });
- model.destroy();
+ model.destroy();
- // Try again with xml override of field domain and context
- model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ // Try again with xml override of field domain and context
+ model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- this.params.fieldsInfo = {
- default: {
- foo: {},
- product_id: {
- context: "{'hello2': 'world', 'test2': foo}",
- domain: "[['hello2', 'like', 'world'], ['test2', 'like', foo]]",
- },
- }
- };
+ this.params.fieldsInfo = {
+ default: {
+ foo: {},
+ product_id: {
+ context: "{'hello2': 'world', 'test2': foo}",
+ domain: "[['hello2', 'like', 'world'], ['test2', 'like', foo]]",
+ },
+ }
+ };
- model.load(this.params).then(function (resultID) {
- var recordPartner = model.get(resultID);
+ resultID = await model.load(this.params);
+ recordPartner = model.get(resultID);
assert.deepEqual(
- recordPartner.getContext({fieldName: "product_id"}),
- {hello2: "world", test2: "gnap"},
+ recordPartner.getContext({ fieldName: "product_id" }),
+ { hello2: "world", test2: "gnap" },
"field context should have been overriden by xml attribute");
assert.deepEqual(
- recordPartner.getDomain({fieldName: "product_id"}),
+ recordPartner.getDomain({ fieldName: "product_id" }),
[["hello2", "like", "world"], ["test2", "like", "gnap"]],
"field domain should have been overriden by xml attribute");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('dont write on readonly fields (write and create)', function (assert) {
- assert.expect(6);
-
- this.params.fieldNames = ['foo', 'bar'];
- this.data.partner.fields.foo.onChange = true;
- this.data.partner.onchanges.foo = function (obj) {
- obj.bar = obj.foo.length;
- };
- this.params.fieldsInfo = {
- default: {
- foo: {},
- bar: {
- modifiers: {
- readonly: true,
+ QUnit.test('dont write on readonly fields (write and create)', async function (assert) {
+ assert.expect(6);
+
+ this.params.fieldNames = ['foo', 'bar'];
+ this.data.partner.fields.foo.onChange = true;
+ this.data.partner.onchanges.foo = function (obj) {
+ obj.bar = obj.foo.length;
+ };
+ this.params.fieldsInfo = {
+ default: {
+ foo: {},
+ bar: {
+ modifiers: {
+ readonly: true,
+ },
},
- },
- }
- };
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'write') {
- assert.deepEqual(args.args[1], {foo: "verylongstring"},
- "should only save foo field");
}
- if (args.method === 'create') {
- assert.deepEqual(args.args[0], {foo: "anotherverylongstring"},
- "should only save foo field");
- }
- return this._super(route, args);
- },
- });
- model.load(this.params).then(function (resultID) {
+ };
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'write') {
+ assert.deepEqual(args.args[1], { foo: "verylongstring" },
+ "should only save foo field");
+ }
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], { foo: "anotherverylongstring" },
+ "should only save foo field");
+ }
+ return this._super(route, args);
+ },
+ });
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.bar, 2,
"should be initialized with correct value");
- model.notifyChanges(resultID, {foo: "verylongstring"});
+ await model.notifyChanges(resultID, { foo: "verylongstring" });
record = model.get(resultID);
assert.strictEqual(record.data.bar, 14,
"should be changed with correct value");
- model.save(resultID);
- });
+ await model.save(resultID);
- // start again, but with a new record
- delete this.params.res_id;
- model.load(this.params).then(function (resultID) {
- var record = model.get(resultID);
+ // start again, but with a new record
+ delete this.params.res_id;
+ resultID = await model.load(this.params);
+ record = model.get(resultID);
assert.strictEqual(record.data.bar, 0,
"should be initialized with correct value (0 as integer)");
- model.notifyChanges(resultID, {foo: "anotherverylongstring"});
+ await model.notifyChanges(resultID, { foo: "anotherverylongstring" });
record = model.get(resultID);
assert.strictEqual(record.data.bar, 21,
"should be changed with correct value");
- model.save(resultID);
+ await model.save(resultID);
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('dont write on readonly fields unless save attribute is set', function (assert) {
- assert.expect(6);
-
- this.params.fieldNames = ['foo', 'bar'];
- this.data.partner.fields.foo.onChange = true;
- this.data.partner.onchanges.foo = function (obj) {
- obj.bar = obj.foo.length;
- };
- this.params.fieldsInfo = {
- default: {
- foo: {},
- bar: {
- modifiers: {
- readonly: true,
+ QUnit.test('dont write on readonly fields unless save attribute is set', async function (assert) {
+ assert.expect(6);
+
+ this.params.fieldNames = ['foo', 'bar'];
+ this.data.partner.fields.foo.onChange = true;
+ this.data.partner.onchanges.foo = function (obj) {
+ obj.bar = obj.foo.length;
+ };
+ this.params.fieldsInfo = {
+ default: {
+ foo: {},
+ bar: {
+ modifiers: {
+ readonly: true,
+ },
+ force_save: true,
},
- force_save: true,
- },
- }
- };
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'write') {
- assert.deepEqual(args.args[1], {bar: 14, foo: "verylongstring"},
- "should only save foo field");
- }
- if (args.method === 'create') {
- assert.deepEqual(args.args[0], {bar: 21, foo: "anotherverylongstring"},
- "should only save foo field");
}
- return this._super(route, args);
- },
- });
+ };
- model.load(this.params).then(function (resultID) {
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'write') {
+ assert.deepEqual(args.args[1], { bar: 14, foo: "verylongstring" },
+ "should only save foo field");
+ }
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0], { bar: 21, foo: "anotherverylongstring" },
+ "should only save foo field");
+ }
+ return this._super(route, args);
+ },
+ });
+
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data.bar, 2,
"should be initialized with correct value");
- model.notifyChanges(resultID, {foo: "verylongstring"});
+ await model.notifyChanges(resultID, { foo: "verylongstring" });
record = model.get(resultID);
assert.strictEqual(record.data.bar, 14,
"should be changed with correct value");
- model.save(resultID);
- });
+ await model.save(resultID);
- // start again, but with a new record
- delete this.params.res_id;
- model.load(this.params).then(function (resultID) {
- var record = model.get(resultID);
+ // start again, but with a new record
+ delete this.params.res_id;
+ resultID = await model.load(this.params);
+ record = model.get(resultID);
assert.strictEqual(record.data.bar, 0,
"should be initialized with correct value (0 as integer)");
- model.notifyChanges(resultID, {foo: "anotherverylongstring"});
+ await model.notifyChanges(resultID, { foo: "anotherverylongstring" });
record = model.get(resultID);
assert.strictEqual(record.data.bar, 21,
"should be changed with correct value");
- model.save(resultID);
+ await model.save(resultID);
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('default_get with one2many values', function (assert) {
- assert.expect(1);
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- if (args.method === 'default_get') {
- return $.when({
- product_ids: [[0, 0, {"name": "xdroid"}]]
- });
- }
- return this._super(route, args);
- },
- });
- var params = {
- fieldNames: ['product_ids'],
- fields: this.data.partner.fields,
- modelName: 'partner',
- type: 'record',
- fieldsInfo: {
- form: {
- product_ids: {
- fieldsInfo: {
- default: { name: {} },
+ QUnit.test('default_get with one2many values', async function (assert) {
+ assert.expect(1);
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ if (args.method === 'default_get') {
+ return Promise.resolve({
+ product_ids: [[0, 0, { "name": "xdroid" }]]
+ });
+ }
+ return this._super(route, args);
+ },
+ });
+ var params = {
+ fieldNames: ['product_ids'],
+ fields: this.data.partner.fields,
+ modelName: 'partner',
+ type: 'record',
+ fieldsInfo: {
+ form: {
+ product_ids: {
+ fieldsInfo: {
+ default: { name: {} },
+ },
+ relatedFields: this.data.product.fields,
+ viewType: 'default',
},
- relatedFields: this.data.product.fields,
- viewType: 'default',
},
},
- },
- viewType: 'form',
- };
- model.load(params).then(function (resultID) {
+ viewType: 'form',
+ };
+ var resultID = await model.load(params);
assert.strictEqual(typeof resultID, 'string', "result should be a valid id");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('call makeRecord with a pre-fetched many2one field', function (assert) {
- assert.expect(3);
- var rpcCount = 0;
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- rpcCount++;
- return this._super(route, args);
- },
- });
+ QUnit.test('call makeRecord with a pre-fetched many2one field', async function (assert) {
+ assert.expect(3);
+ var rpcCount = 0;
- model.makeRecord('coucou', [{
- name: 'partner_id',
- relation: 'partner',
- type: 'many2one',
- value: [1, 'first partner'],
- }], {
- partner_id: {
- options: {
- no_open: true,
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ rpcCount++;
+ return this._super(route, args);
},
- },
- }).then(function (recordID) {
- var record = model.get(recordID);
- assert.deepEqual(record.fieldsInfo.default.partner_id, {options: {no_open: true}},
- "makeRecord should have generated the fieldsInfo");
- assert.deepEqual(record.data.partner_id.data, {id: 1, display_name: 'first partner'},
- "many2one should contain the partner with id 1");
- assert.strictEqual(rpcCount, 0, "makeRecord should not have done any rpc");
- });
- model.destroy();
- });
+ });
- QUnit.test('call makeRecord with a many2many field', function (assert) {
- assert.expect(5);
- var rpcCount = 0;
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- rpcCount++;
- return this._super(route, args);
- },
+ model.makeRecord('coucou', [{
+ name: 'partner_id',
+ relation: 'partner',
+ type: 'many2one',
+ value: [1, 'first partner'],
+ }], {
+ partner_id: {
+ options: {
+ no_open: true,
+ },
+ },
+ }).then(function (recordID) {
+ var record = model.get(recordID);
+ assert.deepEqual(record.fieldsInfo.default.partner_id, { options: { no_open: true } },
+ "makeRecord should have generated the fieldsInfo");
+ assert.deepEqual(record.data.partner_id.data, { id: 1, display_name: 'first partner' },
+ "many2one should contain the partner with id 1");
+ assert.strictEqual(rpcCount, 0, "makeRecord should not have done any rpc");
+ });
+ model.destroy();
});
- model.makeRecord('coucou', [{
- name: 'partner_ids',
- fields: [{
- name: 'id',
- type: 'integer',
- }, {
- name: 'display_name',
- type: 'char',
- }],
- relation: 'partner',
- type: 'many2many',
- value: [1, 2],
- }]).then(function (recordID) {
+ QUnit.test('call makeRecord with a many2many field', async function (assert) {
+ assert.expect(5);
+ var rpcCount = 0;
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ rpcCount++;
+ return this._super(route, args);
+ },
+ });
+
+ var recordID = await model.makeRecord('coucou', [{
+ name: 'partner_ids',
+ fields: [{
+ name: 'id',
+ type: 'integer',
+ }, {
+ name: 'display_name',
+ type: 'char',
+ }],
+ relation: 'partner',
+ type: 'many2many',
+ value: [1, 2],
+ }]);
var record = model.get(recordID);
assert.deepEqual(record.fieldsInfo.default.partner_ids, {},
"makeRecord should have generated the fieldsInfo");
@@ -1776,45 +1734,44 @@ QUnit.module('Views', {
"there should be 2 elements in the many2many");
assert.strictEqual(record.data.partner_ids.data.length, 2,
"many2many should be a list of length 2");
- assert.deepEqual(record.data.partner_ids.data[0].data, {id: 1, display_name: 'first partner'},
+ assert.deepEqual(record.data.partner_ids.data[0].data, { id: 1, display_name: 'first partner' },
"many2many should contain the partner with id 1");
assert.strictEqual(rpcCount, 1, "makeRecord should have done 1 rpc");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('call makeRecord with a pre-fetched many2many field', function (assert) {
- assert.expect(5);
- var rpcCount = 0;
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- rpcCount++;
- return this._super(route, args);
- },
- });
+ QUnit.test('call makeRecord with a pre-fetched many2many field', async function (assert) {
+ assert.expect(5);
+ var rpcCount = 0;
- model.makeRecord('coucou', [{
- name: 'partner_ids',
- fields: [{
- name: 'id',
- type: 'integer',
- }, {
- name: 'display_name',
- type: 'char',
- }],
- relation: 'partner',
- type: 'many2many',
- value: [{
- id: 1,
- display_name: "first partner",
- }, {
- id: 2,
- display_name: "second partner",
- }],
- }]).then(function (recordID) {
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ rpcCount++;
+ return this._super(route, args);
+ },
+ });
+
+ var recordID = await model.makeRecord('coucou', [{
+ name: 'partner_ids',
+ fields: [{
+ name: 'id',
+ type: 'integer',
+ }, {
+ name: 'display_name',
+ type: 'char',
+ }],
+ relation: 'partner',
+ type: 'many2many',
+ value: [{
+ id: 1,
+ display_name: "first partner",
+ }, {
+ id: 2,
+ display_name: "second partner",
+ }],
+ }]);
var record = model.get(recordID);
assert.deepEqual(record.fieldsInfo.default.partner_ids, {},
"makeRecord should have generated the fieldsInfo");
@@ -1822,154 +1779,149 @@ QUnit.module('Views', {
"there should be 2 elements in the many2many");
assert.strictEqual(record.data.partner_ids.data.length, 2,
"many2many should be a list of length 2");
- assert.deepEqual(record.data.partner_ids.data[0].data, {id: 1, display_name: 'first partner'},
+ assert.deepEqual(record.data.partner_ids.data[0].data, { id: 1, display_name: 'first partner' },
"many2many should contain the partner with id 1");
assert.strictEqual(rpcCount, 0, "makeRecord should not have done any rpc");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('check id, active_id, active_ids, active_model values in record\'s context', function (assert) {
- assert.expect(2);
+ QUnit.test('check id, active_id, active_ids, active_model values in record\'s context', async function (assert) {
+ assert.expect(2);
- this.data.partner.fields.product_id.context = "{'id': id, 'active_id': active_id, 'active_ids': active_ids, 'active_model': active_model}";
+ this.data.partner.fields.product_id.context = "{'id': id, 'active_id': active_id, 'active_ids': active_ids, 'active_model': active_model}";
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- this.params.fieldNames = ['product_id'];
+ this.params.fieldNames = ['product_id'];
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var recordPartner = model.get(resultID);
assert.deepEqual(
- recordPartner.getContext({fieldName: "product_id"}),
- {id: 2, active_id: 2, active_ids: [2], active_model: "partner"},
+ recordPartner.getContext({ fieldName: "product_id" }),
+ { id: 2, active_id: 2, active_ids: [2], active_model: "partner" },
"wrong values for id, active_id, active_ids or active_model");
- });
- // Try again without record
- this.params.res_id = undefined;
+ // Try again without record
+ this.params.res_id = undefined;
- model.load(this.params).then(function (resultID) {
- var recordPartner = model.get(resultID);
+ resultID = await model.load(this.params);
+ recordPartner = model.get(resultID);
assert.deepEqual(
- recordPartner.getContext({fieldName: "product_id"}),
- {id: false, active_id: false, active_ids: [], active_model: "partner"},
+ recordPartner.getContext({ fieldName: "product_id" }),
+ { id: false, active_id: false, active_ids: [], active_model: "partner" },
"wrong values for id, active_id, active_ids or active_model. Have to be defined even if there is no record.");
+
+ model.destroy();
});
- model.destroy();
- });
+ QUnit.test('load model with many2many field properly fetched', async function (assert) {
+ assert.expect(2);
- QUnit.test('load model with many2many field properly fetched', function (assert) {
- assert.expect(2);
+ this.params.fieldNames = ['category'];
+ this.params.res_id = 1;
- this.params.fieldNames = ['category'];
- this.params.res_id = 1;
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method);
+ return this._super(route, args);
+ },
+ });
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.step(args.method);
- return this._super(route, args);
- },
+ model.load(this.params);
+ assert.verifySteps(['read'],
+ "there should be only one read");
+ model.destroy();
});
- model.load(this.params);
- assert.verifySteps(['read'],
- "there should be only one read");
- model.destroy();
- });
+ QUnit.test('data should contain all fields in view, default being false', async function (assert) {
+ assert.expect(1);
- QUnit.test('data should contain all fields in view, default being false', function (assert) {
- assert.expect(1);
+ this.data.partner.fields.product_ids.default = [
+ [6, 0, []],
+ [0, 0, { name: 'new' }],
+ ];
+ this.data.product.fields.date = { string: "Date", type: "date" };
+
+ var params = {
+ fieldNames: ['product_ids'],
+ modelName: 'partner',
+ fields: this.data.partner.fields,
+ fieldsInfo: {
+ form: {
+ product_ids: {
+ relatedFields: this.data.product.fields,
+ fieldsInfo: { list: { name: {}, date: {} } },
+ viewType: 'list',
+ }
+ },
+ },
+ res_id: undefined,
+ type: 'record',
+ viewType: 'form',
+ };
- this.data.partner.fields.product_ids.default = [
- [6, 0, []],
- [0, 0, {name: 'new'}],
- ];
- this.data.product.fields.date = { string: "Date", type: "date" };
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- var params = {
- fieldNames: ['product_ids'],
- modelName: 'partner',
- fields: this.data.partner.fields,
- fieldsInfo: {
- form: {
- product_ids: {
- relatedFields: this.data.product.fields,
- fieldsInfo: { list: { name: {}, date: {} } },
- viewType: 'list',
- }
- },
- },
- res_id: undefined,
- type: 'record',
- viewType: 'form',
- };
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ model.load(params).then(function (resultID) {
+ var record = model.get(resultID);
+ assert.strictEqual(record.data.product_ids.data[0].data.date, false,
+ "date value should be in data, and should be false");
+ });
- model.load(params).then(function (resultID) {
- var record = model.get(resultID);
- assert.strictEqual(record.data.product_ids.data[0].data.date, false,
- "date value should be in data, and should be false");
+ model.destroy();
});
- model.destroy();
- });
-
- QUnit.test('changes are discarded when reloading from a new record', function (assert) {
- // practical use case: click on 'Create' to open a form view in edit
- // mode (new record), click on 'Discard', then open an existing record
- assert.expect(2);
+ QUnit.test('changes are discarded when reloading from a new record', async function (assert) {
+ // practical use case: click on 'Create' to open a form view in edit
+ // mode (new record), click on 'Discard', then open an existing record
+ assert.expect(2);
- this.data.partner.fields.foo.default = 'default';
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ this.data.partner.fields.foo.default = 'default';
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- // load a new record (default_get)
- var params = _.extend(this.params, {
- res_id: undefined,
- type: 'record',
- fieldNames: ['foo'],
- });
- model.load(params).then(function (resultID) {
+ // load a new record (default_get)
+ var params = _.extend(this.params, {
+ res_id: undefined,
+ type: 'record',
+ fieldNames: ['foo'],
+ });
+ var resultID = await model.load(params);
var record = model.get(resultID);
assert.strictEqual(record.data.foo, 'default',
"should be the default value");
// reload with id 2
- model.reload(record.id, {currentId: 2}).then(function (resultID) {
- var record = model.get(resultID);
- assert.strictEqual(record.data.foo, 'gnap',
- "should be the value of record 2");
- });
- });
+ resultID = await model.reload(record.id, { currentId: 2 });
+ record = model.get(resultID);
+ assert.strictEqual(record.data.foo, 'gnap',
+ "should be the value of record 2");
- model.destroy();
- });
+ model.destroy();
+ });
- QUnit.test('has a proper evaluation context', function (assert) {
- assert.expect(1);
+ QUnit.test('has a proper evaluation context', async function (assert) {
+ assert.expect(1);
- this.params.fieldNames = Object.keys(this.data.partner.fields);
- this.params.res_id = 1;
+ this.params.fieldNames = Object.keys(this.data.partner.fields);
+ this.params.res_id = 1;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.deepEqual(record.evalContext, {
active_id: 1,
@@ -1988,42 +1940,41 @@ QUnit.module('Views', {
reference: false,
total: 0
}, "should use the proper eval context");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('x2manys in contexts and domains are correctly evaluated', function (assert) {
- assert.expect(4);
-
- this.data.partner.records[0].product_ids = [37, 41];
- this.params.fieldNames = Object.keys(this.data.partner.fields);
- this.params.fieldsInfo = {
- form: {
- qux: {
- context: "{'category': category, 'product_ids': product_ids}",
- domain: "[['id', 'in', category], ['id', 'in', product_ids]]",
- relatedFields: this.data.partner.fields,
- },
- category: {
- relatedFields: this.data.partner_type.fields,
- },
- product_ids: {
- relatedFields: this.data.product.fields,
+ QUnit.test('x2manys in contexts and domains are correctly evaluated', async function (assert) {
+ assert.expect(4);
+
+ this.data.partner.records[0].product_ids = [37, 41];
+ this.params.fieldNames = Object.keys(this.data.partner.fields);
+ this.params.fieldsInfo = {
+ form: {
+ qux: {
+ context: "{'category': category, 'product_ids': product_ids}",
+ domain: "[['id', 'in', category], ['id', 'in', product_ids]]",
+ relatedFields: this.data.partner.fields,
+ },
+ category: {
+ relatedFields: this.data.partner_type.fields,
+ },
+ product_ids: {
+ relatedFields: this.data.product.fields,
+ },
},
- },
- };
- this.params.viewType = 'form';
- this.params.res_id = 1;
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ };
+ this.params.viewType = 'form';
+ this.params.res_id = 1;
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
- var context = record.getContext({fieldName: 'qux'});
- var domain = record.getDomain({fieldName: 'qux'});
+ var context = record.getContext({ fieldName: 'qux' });
+ var domain = record.getDomain({ fieldName: 'qux' });
assert.deepEqual(context, {
category: [12],
@@ -2038,177 +1989,171 @@ QUnit.module('Views', {
], "x2many values in domains should be lists of ids");
assert.strictEqual(JSON.stringify(domain),
"[[\"id\",\"in\",[12]],[\"id\",\"in\",[37,41]]]",
- "x2many values in domains should be lists of ids");
+ "x2many values in domains should be lists of ids");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('fetch references in list, with not too many rpcs', function (assert) {
- assert.expect(5);
-
- this.data.partner.records[0].reference = 'product,37';
- this.data.partner.records[1].reference = 'product,41';
-
- this.params.fieldNames = ['reference'];
- this.params.domain = [];
- this.params.groupedBy = [];
- this.params.res_id = undefined;
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.step(route);
- if (route === "/web/dataset/call_kw/product/name_get") {
- assert.deepEqual(args.args, [[37, 41]],
- "the name_get should contain the product ids");
- }
- return this._super(route, args);
- },
- });
+ QUnit.test('fetch references in list, with not too many rpcs', async function (assert) {
+ assert.expect(5);
+
+ this.data.partner.records[0].reference = 'product,37';
+ this.data.partner.records[1].reference = 'product,41';
+
+ this.params.fieldNames = ['reference'];
+ this.params.domain = [];
+ this.params.groupedBy = [];
+ this.params.res_id = undefined;
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(route);
+ if (route === "/web/dataset/call_kw/product/name_get") {
+ assert.deepEqual(args.args, [[37, 41]],
+ "the name_get should contain the product ids");
+ }
+ return this._super(route, args);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.strictEqual(record.data[0].data.reference.data.display_name, "xphone",
"name_get should have been correctly fetched");
- assert.verifySteps(["/web/dataset/search_read", "/web/dataset/call_kw/product/name_get"],
+ assert.verifySteps(["/web/dataset/search_read", "/web/dataset/call_kw/product/name_get"],
"should have done 2 rpc (searchread and name_get for product)");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('reload a new record', function (assert) {
- assert.expect(6);
-
- this.params.context = {};
- this.params.fieldNames = ['product_id', 'category', 'product_ids'];
- this.params.res_id = undefined;
- this.params.type = 'record';
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route, args) {
- assert.step(args.method);
- return this._super(route, args);
- },
- });
+ QUnit.test('reload a new record', async function (assert) {
+ assert.expect(6);
- model.load(this.params).then(function (recordID) {
- model.reload(recordID).then(function (recordID) {
- assert.verifySteps(['default_get', 'default_get'],
- "two default_get RPCs should have been done");
- var record = model.get(recordID);
- assert.strictEqual(record.data.product_id, false,
- "m2o default value should be false");
- assert.deepEqual(record.data.product_ids.data, [],
- "o2m default should be []");
- assert.deepEqual(record.data.category.data, [],
- "m2m default should be []");
+ this.params.context = {};
+ this.params.fieldNames = ['product_id', 'category', 'product_ids'];
+ this.params.res_id = undefined;
+ this.params.type = 'record';
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route, args) {
+ assert.step(args.method);
+ return this._super(route, args);
+ },
});
- });
- model.destroy();
- });
+ var recordID = await model.load(this.params);
+ recordID = await model.reload(recordID);
+ assert.verifySteps(['default_get', 'default_get'],
+ "two default_get RPCs should have been done");
+ var record = model.get(recordID);
+ assert.strictEqual(record.data.product_id, false,
+ "m2o default value should be false");
+ assert.deepEqual(record.data.product_ids.data, [],
+ "o2m default should be []");
+ assert.deepEqual(record.data.category.data, [],
+ "m2m default should be []");
+
+ model.destroy();
+ });
- QUnit.test('default_get with value false for a one2many', function (assert) {
- assert.expect(1);
+ QUnit.test('default_get with value false for a one2many', async 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';
+ 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,
- });
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
assert.deepEqual(record.data.product_ids.data, [], "o2m default should be []");
- });
-
- model.destroy();
- });
- QUnit.test('only x2many lists (static) should be sorted client-side', function (assert) {
- assert.expect(1);
-
- this.params.modelName = 'partner_type';
- this.params.res_id = undefined;
- this.params.orderedBy = [{name: 'display_name', asc: true}];
-
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- mockRPC: function (route) {
- if (route === '/web/dataset/search_read') {
- // simulate randomn sort form the server
- return $.when({
- length: 3,
- records: [
- {id: 12, display_name: "gold", date: "2017-01-25"},
- {id: 15, display_name: "bronze"},
- {id: 14, display_name: "silver"},
- ],
- });
- }
- return this._super.apply(this, arguments);
- },
- });
+ model.destroy();
+ });
+
+ QUnit.test('only x2many lists (static) should be sorted client-side', async function (assert) {
+ assert.expect(1);
+
+ this.params.modelName = 'partner_type';
+ this.params.res_id = undefined;
+ this.params.orderedBy = [{ name: 'display_name', asc: true }];
+
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ mockRPC: function (route) {
+ if (route === '/web/dataset/search_read') {
+ // simulate randomn sort form the server
+ return Promise.resolve({
+ length: 3,
+ records: [
+ { id: 12, display_name: "gold", date: "2017-01-25" },
+ { id: 15, display_name: "bronze" },
+ { id: 14, display_name: "silver" },
+ ],
+ });
+ }
+ return this._super.apply(this, arguments);
+ },
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var list = model.get(resultID);
assert.deepEqual(_.map(list.data, 'res_id'), [12, 15, 14],
"should have kept the order from the server");
+ model.destroy();
});
- model.destroy();
- });
- QUnit.test('onchange on a boolean field', function (assert) {
- assert.expect(2);
-
- var newFields = {
- foobool: {
- type: 'boolean',
- string: 'foobool',
- },
- foobool2: {
- type: 'boolean',
- string: 'foobool2',
- },
- };
- _.extend(this.data.partner.fields, newFields);
-
- this.data.partner.fields.foobool.onChange = true;
- this.data.partner.onchanges.foobool = function (obj) {
- if (obj.foobool) {
- obj.foobool2 = true;
- }
- };
+ QUnit.test('onchange on a boolean field', async function (assert) {
+ assert.expect(2);
+
+ var newFields = {
+ foobool: {
+ type: 'boolean',
+ string: 'foobool',
+ },
+ foobool2: {
+ type: 'boolean',
+ string: 'foobool2',
+ },
+ };
+ _.extend(this.data.partner.fields, newFields);
+
+ this.data.partner.fields.foobool.onChange = true;
+ this.data.partner.onchanges.foobool = function (obj) {
+ if (obj.foobool) {
+ obj.foobool2 = true;
+ }
+ };
- this.data.partner.records[0].foobool = false;
- this.data.partner.records[0].foobool2 = true;
+ this.data.partner.records[0].foobool = false;
+ this.data.partner.records[0].foobool2 = true;
- this.params.res_id = 1;
- this.params.fieldNames = ['foobool', 'foobool2'];
- this.params.fields = this.data.partner.fields;
- var model = createModel({
- Model: BasicModel,
- data: this.data,
- });
+ this.params.res_id = 1;
+ this.params.fieldNames = ['foobool', 'foobool2'];
+ this.params.fields = this.data.partner.fields;
+ var model = createModel({
+ Model: BasicModel,
+ data: this.data,
+ });
- model.load(this.params).then(function (resultID) {
+ var resultID = await model.load(this.params);
var record = model.get(resultID);
- model.notifyChanges(resultID, {foobool2: false});
+ await model.notifyChanges(resultID, { foobool2: false });
record = model.get(resultID);
assert.strictEqual(record.data.foobool2, false, "foobool2 field should be false");
- model.notifyChanges(resultID, {foobool: true});
+ await model.notifyChanges(resultID, { foobool: true });
record = model.get(resultID);
assert.strictEqual(record.data.foobool2, true, "foobool2 field should be true");
+ model.destroy();
});
- model.destroy();
});
-});});
+});
diff --git a/addons/web/static/tests/views/calendar_mobile_tests.js b/addons/web/static/tests/views/calendar_mobile_tests.js
index 969476b0081..60b5ed5f85f 100644
--- a/addons/web/static/tests/views/calendar_mobile_tests.js
+++ b/addons/web/static/tests/views/calendar_mobile_tests.js
@@ -4,7 +4,7 @@ odoo.define('web.calendar_mobile_tests', function (require) {
var CalendarView = require('web.CalendarView');
var testUtils = require('web.test_utils');
-var createAsyncView = testUtils.createAsyncView;
+var createView = testUtils.createView;
var initialDate = new Date(2016, 11, 12, 8, 0, 0);
initialDate = new Date(initialDate.getTime() - initialDate.getTimezoneOffset()*60*1000);
@@ -24,7 +24,7 @@ QUnit.module('Views', {
{id: 1, name: "event 1", start: "2016-12-11 00:00:00", stop: "2016-12-11 00:00:00"},
],
check_access_rights: function () {
- return $.when(true);
+ return Promise.resolve(true);
}
},
};
@@ -37,7 +37,7 @@ QUnit.module('Views', {
assert.expect(3);
var done = assert.async();
- createAsyncView({
+ createView({
View: CalendarView,
model: 'event',
data: this.data,
diff --git a/addons/web/static/tests/views/calendar_tests.js b/addons/web/static/tests/views/calendar_tests.js
index 9e0e7dc1e84..8061df08af4 100644
--- a/addons/web/static/tests/views/calendar_tests.js
+++ b/addons/web/static/tests/views/calendar_tests.js
@@ -7,7 +7,6 @@ var Dialog = require('web.Dialog');
var fieldUtils = require('web.field_utils');
var mixins = require('web.mixins');
var testUtils = require('web.test_utils');
-var time = require('web.time');
var session = require('web.session');
var createActionManager = testUtils.createActionManager;
@@ -23,8 +22,7 @@ CalendarRenderer.include({
});
-var createView = testUtils.createView;
-var createAsyncView = testUtils.createAsyncView;
+var createCalendarView = testUtils.createCalendarView;
var initialDate = new Date(2016, 11, 12, 8, 0, 0);
initialDate = new Date(initialDate.getTime() - initialDate.getTimezoneOffset()*60*1000);
@@ -57,7 +55,7 @@ QUnit.module('Views', {
{id: 6, user_id: session.uid, partner_id: 1, name: "event 6", start: "2016-12-18 08:00:00", stop: "2016-12-18 09:00:00", allday: false, partner_ids: [3], type: 3}
],
check_access_rights: function () {
- return $.when(true);
+ return Promise.resolve(true);
}
},
user: {
@@ -98,7 +96,7 @@ QUnit.module('Views', {
]
},
};
- }
+ },
}, function () {
QUnit.module('CalendarView');
@@ -125,9 +123,8 @@ QUnit.module('Views', {
'</form>',
};
- QUnit.test('simple calendar rendering', function (assert) {
- assert.expect(25);
- var done = assert.async();
+ QUnit.test('simple calendar rendering', async function (assert) {
+ assert.expect(24);
this.data.event.records.push({
id: 7,
@@ -141,7 +138,7 @@ QUnit.module('Views', {
type: 1
});
- createAsyncView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -159,73 +156,72 @@ QUnit.module('Views', {
'<field name="partner_ids" write_model="filter_partner" write_field="partner_id"/>'+
'</calendar>',
archs: archs,
-
viewOptions: {
initialDate: initialDate,
},
- }).then(function (calendar) {
-
- assert.ok(calendar.$('.o_calendar_view').find('.fc-view-container').length, "should instance of fullcalendar");
-
- var $sidebar = calendar.$('.o_calendar_sidebar');
-
- assert.strictEqual($sidebar.find('.ui-state-active').text(), "12", "should highlight the target day");
-
- // test view scales
-
- assert.containsN(calendar, '.fc-event', 9, "should display 9 events on the week (4 event + 5 days event)");
- assert.strictEqual($sidebar.find('.o_selected_range').length, 7, "week scale should highlight 7 days in mini calendar");
-
- calendar.$buttons.find('.o_calendar_button_day').trigger('click'); // display only one day
- assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day");
- assert.strictEqual($sidebar.find('.o_selected_range').length, 1, "should highlight the target day in mini calendar");
-
- calendar.$buttons.find('.o_calendar_button_month').trigger('click'); // display all the month
- assert.containsN(calendar, '.fc-event', 7, "should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')");
- assert.strictEqual($sidebar.find('.o_selected_range').length, 31, "month scale should highlight all days in mini calendar");
-
- // test filters
-
- assert.strictEqual($sidebar.find('.o_calendar_filter').length, 2, "should display 3 filters");
-
- var $typeFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(user))');
- assert.ok($typeFilter.length, "should display 'user' filter");
- assert.strictEqual($typeFilter.find('.o_calendar_filter_item').length, 3, "should display 3 filter items for 'user'");
+ });
- // filters which has no value should show with string "Undefined", should not have any user image and should show at the last
- assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last').data('value'), false, "filters having false value should be displayed at last in filter items");
- assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last span').text(), "Undefined", "filters having false value should display 'Undefined' string");
- assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last label img').length, 0, "filters having false value should not have any user image");
+ assert.ok(calendar.$('.o_calendar_view').find('.fc-view-container').length,
+ "should instance of fullcalendar");
- var $attendeesFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(attendees))');
- assert.ok($attendeesFilter.length, "should display 'attendees' filter");
- assert.strictEqual($attendeesFilter.find('.o_calendar_filter_item').length, 3, "should display 3 filter items for 'attendees' who use write_model (2 saved + Everything)");
- assert.ok($attendeesFilter.find('.o_field_many2one').length, "should display one2many search bar for 'attendees' filter");
+ var $sidebar = calendar.$('.o_calendar_sidebar');
- assert.containsN(calendar, '.fc-event', 7,
- "should display 7 events ('event 5' counts for 2 because it spans two weeks and thus generate two fc-event elements)");
- testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').first());
- assert.containsN(calendar, '.fc-event', 4, "should now only display 4 event");
- testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').eq(1));
- assert.containsNone(calendar, '.fc-event', "should not display any event anymore");
+ // test view scales
+ assert.containsN(calendar, '.fc-event', 9,
+ "should display 9 events on the week (4 event + 5 days event)");
+ assert.containsN($sidebar, '.o_selected_range', 7,
+ "week scale should highlight 7 days in mini calendar");
- // test search bar in filter
- $sidebar.find('input[type="text"]').trigger('click');
- assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').length, 2, "should display 2 choices in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
- $('ul.ui-autocomplete li:first').trigger('click');
- assert.strictEqual($sidebar.find('.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item').length, 4, "should display 4 filter items for 'attendees'");
- $sidebar.find('input[type="text"]').trigger('click');
- assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').text(), "partner 4", "should display the last choice in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
- $sidebar.find('.o_calendar_filter_item .o_remove').first().trigger('click');
- assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
- $('.modal-footer button.btn:contains(Ok)').trigger('click');
- assert.strictEqual($sidebar.find('.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item').length, 3, "click on remove then should display 3 filter items for 'attendees'");
- calendar.destroy();
- done();
- });
+ await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_day')); // display only one day
+ assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day");
+ assert.containsOnce($sidebar, '.o_selected_range',
+ "should highlight the target day in mini calendar");
+
+ await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_month')); // display all the month
+ assert.containsN(calendar, '.fc-event', 7,
+ "should display 7 events on the month (5 events + 2 week event - 1 'event 6' is filtered + 1 'Undefined event')");
+ assert.containsN($sidebar, '.o_selected_range', 31,
+ "month scale should highlight all days in mini calendar");
+
+ // test filters
+ assert.containsN($sidebar, '.o_calendar_filter', 2, "should display 2 filters");
+
+ var $typeFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(user))');
+ assert.ok($typeFilter.length, "should display 'user' filter");
+ assert.containsN($typeFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'user'");
+
+ // filters which has no value should show with string "Undefined", should not have any user image and should show at the last
+ assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last').data('value'), false, "filters having false value should be displayed at last in filter items");
+ assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last span').text(), "Undefined", "filters having false value should display 'Undefined' string");
+ assert.strictEqual($typeFilter.find('.o_calendar_filter_item:last label img').length, 0, "filters having false value should not have any user image");
+
+ var $attendeesFilter = $sidebar.find('.o_calendar_filter:has(h3:contains(attendees))');
+ assert.ok($attendeesFilter.length, "should display 'attendees' filter");
+ assert.containsN($attendeesFilter, '.o_calendar_filter_item', 3, "should display 3 filter items for 'attendees' who use write_model (2 saved + Everything)");
+ assert.ok($attendeesFilter.find('.o_field_many2one').length, "should display one2many search bar for 'attendees' filter");
+
+ assert.containsN(calendar, '.fc-event', 7,
+ "should display 7 events ('event 5' counts for 2 because it spans two weeks and thus generate two fc-event elements)");
+ await testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').first());
+ assert.containsN(calendar, '.fc-event', 4, "should now only display 4 event");
+ await testUtils.dom.click(calendar.$('.o_calendar_filter .custom-checkbox input').eq(1));
+ assert.containsNone(calendar, '.fc-event', "should not display any event anymore");
+
+ // test search bar in filter
+ await testUtils.dom.click($sidebar.find('input[type="text"]'));
+ assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').length, 2,"should display 2 choices in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
+ await testUtils.dom.click($('ul.ui-autocomplete li:first'));
+ assert.containsN($sidebar, '.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item', 4, "should display 4 filter items for 'attendees'");
+ await testUtils.dom.click($sidebar.find('input[type="text"]'));
+ assert.strictEqual($('ul.ui-autocomplete li:not(.o_m2o_dropdown_option)').text(), "partner 4", "should display the last choice in one2many autocomplete"); // TODO: remove :not(.o_m2o_dropdown_option) because can't have "create & edit" choice
+ await testUtils.dom.click($sidebar.find('.o_calendar_filter_item .o_remove').first(), {allowInvisible: true});
+ assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Ok)'));
+ assert.containsN($sidebar, '.o_calendar_filter:has(h3:contains(attendees)) .o_calendar_filter_item', 3, "click on remove then should display 3 filter items for 'attendees'");
+ calendar.destroy();
});
- QUnit.test('breadcrumbs are updated with the displayed period', function (assert) {
+ QUnit.test('breadcrumbs are updated with the displayed period', async function (assert) {
assert.expect(3);
var archs = {
@@ -246,35 +242,34 @@ QUnit.module('Views', {
views: [[1, 'calendar']],
}];
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: actions,
archs: archs,
data: this.data,
});
- actionManager.doAction(1);
-
+ await actionManager.doAction(1);
// displays month mode by default
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(),
'Meetings Test (Dec 11 – 17, 2016)', "should display the current week");
// switch to day mode
- testUtils.dom.click($('.o_control_panel .o_calendar_button_day'));
+ await testUtils.dom.click($('.o_control_panel .o_calendar_button_day'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(),
'Meetings Test (December 12, 2016)', "should display the current day");
// switch to month mode
- testUtils.dom.click($('.o_control_panel .o_calendar_button_month'));
+ await testUtils.dom.click($('.o_control_panel .o_calendar_button_month'));
assert.strictEqual($('.o_control_panel .breadcrumb-item').text(),
'Meetings Test (December 2016)', "should display the current month");
actionManager.destroy();
});
- QUnit.test('create and change events', function (assert) {
+ QUnit.test('create and change events', async function (assert) {
assert.expect(26);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -299,19 +294,19 @@ QUnit.module('Views', {
// click on an existing event to open the formViewDialog
- calendar.$('.fc-event:contains(event 4) .fc-content').trigger('click');
+ await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
assert.ok($('.modal-body').length, "should open the form view in dialog when click on event");
assert.ok($('.modal-footer button.btn:contains(Edit)').length, "formViewDialog should be in readonly mode");
assert.ok($('.modal-footer button.btn:contains(Delete)').length, "formViewDialog should have a delete button");
- $('.modal-footer button.btn:contains(Edit)').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Edit)'));
assert.ok($('.modal-body').length, "should switch the modal in edit mode");
assert.notOk($('.modal-footer button.btn:contains(Delete)').length, "formViewDialog should not have a delete button in edit mode");
- testUtils.fields.editInput($('.modal-body input:first'), 'event 4 modified');
- $('.modal-footer button.btn:contains(Save)').trigger('click');
+ await testUtils.fields.editInput($('.modal-body input:first'), 'event 4 modified');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Save)'));
assert.notOk($('.modal-body').length, "save button should close the modal");
assert.ok(calendar.$('.fc-event:contains(event 4 modified)').length, "should display the updated records");
@@ -322,11 +317,12 @@ QUnit.module('Views', {
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
assert.ok($('.modal-sm').length, "should open the quick create dialog");
- testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create');
- $('.modal-footer button.btn:contains(Create)').trigger('click').trigger('click');
+ await testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Create)'));
assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1, "should display the new record after quick create");
assert.containsN(calendar, 'td.fc-event-container[colspan]', 2, "should the new record have only one day");
@@ -335,15 +331,19 @@ QUnit.module('Views', {
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
assert.ok($('.modal-sm').length, "should open the quick create dialog");
+ await testUtils.fields.editInput($('.modal-body input:first'),
+ 'new event in quick create validated by pressing enter key.');
$('.modal-body input:first')
.val('new event in quick create validated by pressing enter key.')
.trigger($.Event('keyup', {keyCode: $.ui.keyCode.ENTER}))
.trigger($.Event('keyup', {keyCode: $.ui.keyCode.ENTER}));
-
- assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create validated by pressing enter key.)').length, 1, "should display the new record by pressing enter key");
+ await testUtils.nextTick();
+ assert.containsOnce(calendar, '.fc-event:contains(new event in quick create validated by pressing enter key.)',
+ "should display the new record by pressing enter key");
// create a new event and edit it
@@ -352,11 +352,12 @@ QUnit.module('Views', {
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
assert.strictEqual($('.modal-sm').length, 1, "should open the quick create dialog");
testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
- $('.modal-footer button.btn:contains(Edit)').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Edit)'));
assert.strictEqual($('.modal-lg .o_form_view').length, 1, "should open the slow create dialog");
assert.strictEqual($('.modal-lg .modal-title').text(), "Create: Events",
@@ -364,9 +365,10 @@ QUnit.module('Views', {
assert.strictEqual($('.modal-lg .o_form_view input[name="name"]').val(), "coucou",
"should have set the name from the quick create dialog");
- $('.modal-lg button.btn:contains(Save)').trigger('click');
+ await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
- assert.strictEqual(calendar.$('.fc-event:contains(coucou)').length, 1, "should display the new record with string attribute");
+ assert.strictEqual(calendar.$('.fc-event:contains(coucou)').length, 1,
+ "should display the new record with string attribute");
// create a new event with 2 days
@@ -375,41 +377,44 @@ QUnit.module('Views', {
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell.next(), "mousemove");
testUtils.dom.triggerMouseEvent($cell.next(), "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal-dialog input:first'), 'new event in quick create 2');
- $('.modal-footer button.btn:contains(Edit)').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Edit)'));
- assert.strictEqual($('.modal-lg input:first').val(), 'new event in quick create 2', "should open the formViewDialog with default values");
+ assert.strictEqual($('.modal-lg input:first').val(),'new event in quick create 2',
+ "should open the formViewDialog with default values");
- $('.modal-lg button.btn:contains(Save)').trigger('click');
+ await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
assert.notOk($('.modal').length, "should close dialogs");
var $newevent2 = calendar.$('.fc-event:contains(new event in quick create 2)');
assert.ok($newevent2.length, "should display the 2 days new record");
- assert.hasAttrValue($newevent2.closest('.fc-event-container'), 'colspan', "2", "the new record should have 2 days");
+ assert.hasAttrValue($newevent2.closest('.fc-event-container'),
+ 'colspan', "2","the new record should have 2 days");
// delete the a record
- calendar.$('.fc-event:contains(event 4) .fc-content').trigger('click');
- $('.modal-footer button.btn:contains(Delete)').trigger('click');
+ await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Delete)'));
assert.ok($('.modal-footer button.btn:contains(Ok)').length, "should display the confirm message");
- $('.modal-footer button.btn:contains(Ok)').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Ok)'));
assert.notOk(calendar.$('.fc-event:contains(event 4) .fc-content').length, "the record should be deleted");
assert.containsN(calendar, '.fc-event-container .fc-event', 10, "should display 10 events");
// move to next month
- testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_next'));
+ await testUtils.dom.click(calendar.$buttons.find('.o_calendar_button_next'));
assert.containsNone(calendar, '.fc-event-container .fc-event', "should display 0 events");
calendar.destroy();
});
- QUnit.test('quickcreate switching to actual create for required fields', function (assert) {
+ QUnit.test('quickcreate switching to actual create for required fields', async function (assert) {
assert.expect(4);
var event = $.Event();
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -430,11 +435,14 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === "create") {
- return $.Deferred().reject({
- code: 200,
- data: {},
- message: "Odoo server error",
- }, event);
+ return Promise.reject({
+ message: {
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ },
+ event: event
+ });
}
return this._super(route, args);
},
@@ -444,12 +452,14 @@ QUnit.module('Views', {
var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
assert.strictEqual($('.modal-sm .modal-title').text(), 'Create: Events',
"should open the quick create dialog");
- testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create');
- $('.modal-footer button.btn:contains(Create)').trigger('click').trigger('click');
+ await testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Create)'));
+ await testUtils.nextTick();
// If the event is not default-prevented, a traceback will be raised, which we do not want
assert.ok(event.isDefaultPrevented(), "fail deferred event should have been default-prevented");
@@ -462,12 +472,12 @@ QUnit.module('Views', {
calendar.destroy();
});
- QUnit.test('create event with timezone in week mode European locale', function (assert) {
+ QUnit.test('create event with timezone in week mode European locale', async function (assert) {
assert.expect(5);
this.data.event.records = [];
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -507,11 +517,7 @@ QUnit.module('Views', {
}
return this._super(route, args);
},
- });
-
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
+ }, {positionalClicks: true});
var top = calendar.$('.fc-axis:contains(8:00)').offset().top + 5;
var left = calendar.$('.fc-day:eq(2)').offset().left + 5;
@@ -520,7 +526,6 @@ QUnit.module('Views', {
testUtils.dom.triggerPositionalMouseEvent(left, top, "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.');
}
@@ -529,9 +534,10 @@ QUnit.module('Views', {
assert.strictEqual(calendar.$('.fc-content .fc-time').text(), "08:00 - 10:00",
"should display the time in the calendar sticker");
- testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
- testUtils.fields.editInput($('.modal input:first'), 'new event');
- $('.modal button.btn:contains(Create)').trigger('click');
+ await testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
+ await testUtils.nextTick();
+ await testUtils.fields.editInput($('.modal input:first'), 'new event');
+ await testUtils.dom.click($('.modal button.btn:contains(Create)'));
var $newevent = calendar.$('.fc-event:contains(new event)');
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "08:00-10:00newevent12/13/201608:00:00False",
@@ -550,13 +556,12 @@ QUnit.module('Views', {
// delete record
- $newevent.trigger('click');
- $('.modal button.btn-secondary:contains(Delete)').trigger('click');
- $('.modal button.btn-primary:contains(Ok)').trigger('click');
+ await testUtils.dom.click($newevent);
+ await testUtils.dom.click($('.modal button.btn-secondary:contains(Delete)'));
+ await testUtils.dom.click($('.modal button.btn-primary:contains(Ok)'));
assert.containsNone(calendar, '.fc-content', "should delete the record");
calendar.destroy();
- $view.remove();
});
QUnit.test('default week start (US)', function (assert) {
@@ -564,7 +569,7 @@ QUnit.module('Views', {
assert.expect(1);
var done = assert.async();
- createAsyncView({
+ createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -592,7 +597,7 @@ QUnit.module('Views', {
assert.expect(1);
var done = assert.async();
- createAsyncView({
+ createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -625,7 +630,7 @@ QUnit.module('Views', {
assert.expect(1);
var done = assert.async();
- createAsyncView({
+ createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -651,7 +656,7 @@ QUnit.module('Views', {
});
});
- QUnit.test('create event with timezone in week mode with formViewDialog European locale', function (assert) {
+ QUnit.test('create event with timezone in week mode with formViewDialog European locale', async function (assert) {
assert.expect(8);
this.data.event.records = [];
@@ -667,7 +672,7 @@ QUnit.module('Views', {
}
};
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -709,10 +714,7 @@ QUnit.module('Views', {
}
return this._super(route, args);
},
- });
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
+ }, {positionalClicks: true});
var top = calendar.$('.fc-axis:contains(8:00)').offset().top + 5;
var left = calendar.$('.fc-day:eq(2)').offset().left + 5;
@@ -721,42 +723,42 @@ QUnit.module('Views', {
testUtils.dom.triggerPositionalMouseEvent(left, top, "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.');
}
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
- testUtils.fields.editInput($('.modal input:first'), 'new event');
- $('.modal button.btn:contains(Edit)').trigger('click');
-
- assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 08:00:00",
- "should display the datetime");
+ await testUtils.nextTick();
+ await testUtils.fields.editInput($('.modal input:first'), 'new event');
+ await testUtils.dom.click($('.modal button.btn:contains(Edit)'));
- $('.modal-lg .o_field_boolean[name="allday"] input').trigger('click');
+ assert.strictEqual($('.o_field_widget[name="start"] input').val(),
+ "12/13/2016 08:00:00", "should display the datetime");
- assert.strictEqual($('.o_field_widget[name="start_date"] input').val(), "12/13/2016",
- "should display the date");
+ await testUtils.dom.click($('.modal-lg .o_field_boolean[name="allday"] input'));
+ await testUtils.nextTick();
+ assert.strictEqual($('input[name="start_date"]').val(),
+ "12/13/2016", "should display the date");
- $('.modal-lg .o_field_boolean[name="allday"] input').trigger('click');
+ await testUtils.dom.click($('.modal-lg .o_field_boolean[name="allday"] input'));
- assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 02:00:00",
- "should display the datetime from the date with the timezone");
+ assert.strictEqual($('.o_field_widget[name="start"] input').val(),
+ "12/13/2016 02:00:00", "should display the datetime from the date with the timezone");
// use datepicker to enter a date: 12/13/2016 08:00:00
testUtils.dom.openDatepicker($('.o_field_widget[name="start"].o_datepicker'));
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)').trigger('click');
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click');
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]'));
// use datepicker to enter a date: 12/13/2016 10:00:00
testUtils.dom.openDatepicker($('.o_field_widget[name="stop"].o_datepicker'));
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)').trigger('click');
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click');
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]'));
- $('.modal-lg button.btn:contains(Save)').trigger('click');
+ await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
var $newevent = calendar.$('.fc-event:contains(new event)');
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "08:00-10:00newevent",
@@ -787,6 +789,7 @@ QUnit.module('Views', {
left = calendar.$('.fc-day:eq(1)').offset().left + 5;
testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup");
+ await testUtils.nextTick();
// Move to "All day"
expectedEvent = {
@@ -798,17 +801,17 @@ QUnit.module('Views', {
top = calendar.$('.fc-day:eq(1)').offset().top + 5;
testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup");
+ await testUtils.nextTick();
calendar.destroy();
- $view.remove();
});
- QUnit.test('create event with timezone in week mode American locale', function (assert) {
+ QUnit.test('create event with timezone in week mode American locale', async function (assert) {
assert.expect(5);
this.data.event.records = [];
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -848,11 +851,7 @@ QUnit.module('Views', {
}
return this._super(route, args);
},
- });
-
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
+ }, {positionalClicks: true});
var top = calendar.$('.fc-axis:contains(8am)').offset().top + 5;
var left = calendar.$('.fc-day:eq(2)').offset().left + 5;
@@ -861,7 +860,6 @@ QUnit.module('Views', {
testUtils.dom.triggerPositionalMouseEvent(left, top, "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.');
}
@@ -871,8 +869,9 @@ QUnit.module('Views', {
"should display the time in the calendar sticker");
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal input:first'), 'new event');
- $('.modal button.btn:contains(Create)').trigger('click');
+ await testUtils.dom.click($('.modal button.btn:contains(Create)'));
var $newevent = calendar.$('.fc-event:contains(new event)');
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "8:00am-10:00amnewevent12/13/201608:00:00False",
@@ -891,16 +890,15 @@ QUnit.module('Views', {
// delete record
- $newevent.trigger('click');
- $('.modal button.btn-secondary:contains(Delete)').trigger('click');
- $('.modal button.btn-primary:contains(Ok)').trigger('click');
+ await testUtils.dom.click($newevent);
+ await testUtils.dom.click($('.modal button.btn-secondary:contains(Delete)'));
+ await testUtils.dom.click($('.modal button.btn-primary:contains(Ok)'));
assert.containsNone(calendar, '.fc-content', "should delete the record");
calendar.destroy();
- $view.remove();
});
- QUnit.test('create event with timezone in week mode with formViewDialog American locale', function (assert) {
+ QUnit.test('create event with timezone in week mode with formViewDialog American locale', async function (assert) {
assert.expect(8);
this.data.event.records = [];
@@ -916,7 +914,7 @@ QUnit.module('Views', {
}
};
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -958,10 +956,7 @@ QUnit.module('Views', {
}
return this._super(route, args);
},
- });
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
+ }, {positionalClicks: true});
var top = calendar.$('.fc-axis:contains(8am)').offset().top + 5;
var left = calendar.$('.fc-day:eq(2)').offset().left + 5;
@@ -970,42 +965,42 @@ QUnit.module('Views', {
testUtils.dom.triggerPositionalMouseEvent(left, top, "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.');
}
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top + 60, "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal input:first'), 'new event');
- $('.modal button.btn:contains(Edit)').trigger('click');
+ await testUtils.dom.click($('.modal button.btn:contains(Edit)'));
assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 08:00:00",
"should display the datetime");
- $('.modal-lg .o_field_boolean[name="allday"] input').trigger('click');
+ await testUtils.dom.click($('.modal-lg .o_field_boolean[name="allday"] input'));
assert.strictEqual($('.o_field_widget[name="start_date"] input').val(), "12/13/2016",
"should display the date");
- $('.modal-lg .o_field_boolean[name="allday"] input').trigger('click');
+ await testUtils.dom.click($('.modal-lg .o_field_boolean[name="allday"] input'));
assert.strictEqual($('.o_field_widget[name="start"] input').val(), "12/13/2016 02:00:00",
"should display the datetime from the date with the timezone");
// use datepicker to enter a date: 12/13/2016 08:00:00
testUtils.dom.openDatepicker($('.o_field_widget[name="start"].o_datepicker'));
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)').trigger('click');
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click');
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(08)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]'));
// use datepicker to enter a date: 12/13/2016 10:00:00
testUtils.dom.openDatepicker($('.o_field_widget[name="stop"].o_datepicker'));
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour').trigger('click');
- $('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)').trigger('click');
- $('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]').trigger('click');
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="togglePicker"]'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker .timepicker-hour'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .timepicker-hours td.hour:contains(10)'));
+ await testUtils.dom.click($('.bootstrap-datetimepicker-widget .picker-switch a[data-action="close"]'));
- $('.modal-lg button.btn:contains(Save)').trigger('click');
+ await testUtils.dom.click($('.modal-lg button.btn:contains(Save)'));
var $newevent = calendar.$('.fc-event:contains(new event)');
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "8:00am-10:00amnewevent",
@@ -1036,6 +1031,7 @@ QUnit.module('Views', {
left = calendar.$('.fc-day:eq(1)').offset().left + 5;
testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup");
+ await testUtils.nextTick();
// Move to "All day"
expectedEvent = {
@@ -1047,15 +1043,15 @@ QUnit.module('Views', {
top = calendar.$('.fc-day:eq(1)').offset().top + 5;
testUtils.dom.triggerPositionalMouseEvent(left, top, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup");
+ await testUtils.nextTick();
calendar.destroy();
- $view.remove();
});
- QUnit.test('check calendar week column timeformat and event content timeformat', function (assert) {
+ QUnit.test('check calendar week column timeformat and event content timeformat', async function (assert) {
assert.expect(2);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1079,12 +1075,12 @@ QUnit.module('Views', {
calendar.destroy();
});
- QUnit.test('create all day event in week mode', function (assert) {
+ QUnit.test('create all day event in week mode', async function (assert) {
assert.expect(3);
this.data.event.records = [];
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1107,26 +1103,22 @@ QUnit.module('Views', {
return 120;
},
},
- });
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
-
+ }, {positionalClicks: true});
var pos = calendar.$('.fc-bg td:eq(4)').offset();
try {
testUtils.dom.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.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal input:first'), 'new event');
- $('.modal button.btn:contains(Create)').trigger('click');
+ await testUtils.dom.click($('.modal button.btn:contains(Create)'));
var $newevent = calendar.$('.fc-event:contains(new event)');
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "newevent",
@@ -1146,15 +1138,14 @@ QUnit.module('Views', {
"the new record should have the utc datetime (quickCreate)");
calendar.destroy();
- $view.remove();
});
- QUnit.test('create all day event in week mode (no quickCreate)', function (assert) {
+ QUnit.test('create all day event in week mode (no quickCreate)', async function (assert) {
assert.expect(1);
this.data.event.records = [];
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1186,18 +1177,13 @@ QUnit.module('Views', {
"should send the correct data to create events");
},
},
- });
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
-
+ }, {positionalClicks: true});
var pos = calendar.$('.fc-bg td:eq(4)').offset();
try {
testUtils.dom.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();
@@ -1205,15 +1191,14 @@ QUnit.module('Views', {
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup");
calendar.destroy();
- $view.remove();
});
- QUnit.test('create event in month mode', function (assert) {
+ QUnit.test('create event in month mode', async function (assert) {
assert.expect(4);
this.data.event.records = [];
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1246,25 +1231,22 @@ QUnit.module('Views', {
}
return this._super(route, args);
},
- });
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
+ }, {positionalClicks: true});
var pos = calendar.$('.fc-bg td:eq(20)').offset();
try {
testUtils.dom.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.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(pos.left+15, pos.top+15, "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal input:first'), 'new event');
- $('.modal button.btn:contains(Create)').trigger('click');
+ await testUtils.dom.click($('.modal button.btn:contains(Create)'));
var $newevent = calendar.$('.fc-event:contains(new event)');
assert.strictEqual($newevent.text().replace(/[\s\n\r]+/g, ''), "newevent",
@@ -1281,13 +1263,12 @@ QUnit.module('Views', {
}, "the new record should have the utc datetime (quickCreate)");
calendar.destroy();
- $view.remove();
});
- QUnit.test('use mini calendar', function (assert) {
+ QUnit.test('use mini calendar', async function (assert) {
assert.expect(12);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1314,36 +1295,36 @@ QUnit.module('Views', {
assert.containsOnce(calendar, '.fc-agendaWeek-view', "should be in week mode");
assert.containsN(calendar, '.fc-event', 9, "should display 9 events on the week (4 event + 5 days event)");
- testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(19)'));
+ await testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(19)'));
// Clicking on a day in another week should switch to the other week view
assert.containsOnce(calendar, '.fc-agendaWeek-view', "should be in week mode");
assert.containsN(calendar, '.fc-event', 4, "should display 4 events on the week (1 event + 3 days event)");
// Clicking on a day in the same week should switch to that particular day view
- testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
+ await testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
assert.containsOnce(calendar, '.fc-agendaDay-view', "should be in day mode");
assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day");
// Clicking on the same day should toggle between day, month and week views
- testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
+ await testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
assert.containsOnce(calendar, '.fc-month-view', "should be in month mode");
assert.containsN(calendar, '.fc-event', 7, "should display 7 events on the month (event 5 is on multiple weeks and generates to .fc-event)");
- testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
+ await testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
assert.containsOnce(calendar, '.fc-agendaWeek-view', "should be in week mode");
assert.containsN(calendar, '.fc-event', 4, "should display 4 events on the week (1 event + 3 days event)");
- testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
+ await testUtils.dom.click(calendar.$('.o_calendar_mini a:contains(18)'));
assert.containsOnce(calendar, '.fc-agendaDay-view', "should be in day mode");
assert.containsN(calendar, '.fc-event', 2, "should display 2 events on the day");
calendar.destroy();
});
- QUnit.test('rendering, with many2many', function (assert) {
+ QUnit.test('rendering, with many2many', async function (assert) {
assert.expect(5);
this.data.event.fields.partner_ids.type = 'many2many';
this.data.event.records[0].partner_ids = [1,2,3,4,5];
this.data.partner.records.push({id: 5, display_name: "partner 5", image: 'EEE'});
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1365,21 +1346,21 @@ QUnit.module('Views', {
"should have 3 avatars in the side bar");
var $event1Avatars = calendar.$('.fc-event .o_calendar_avatars').first();
- assert.strictEqual($event1Avatars.find('img').length, 1, "should have 1 avatar");
- assert.strictEqual($event1Avatars.find('span').length, 0,
+ assert.containsOnce($event1Avatars, 'img', "should have 1 avatar");
+ assert.containsNone($event1Avatars, 'span',
"should not have a span for more attendees since there is only one");
var $event2Avatars = calendar.$('.fc-event:contains(All day) .o_calendar_avatars');
- assert.strictEqual($event2Avatars.find('img').length, 3, "should have 3 avatars");
+ assert.containsN($event2Avatars, 'img', 3, "should have 3 avatars");
assert.strictEqual($event2Avatars.find('span').text(), '+2',
"should indicate there are 2 more attendees that we don't show");
calendar.destroy();
});
- QUnit.test('open form view', function (assert) {
+ QUnit.test('open form view', async function (assert) {
assert.expect(3);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1399,7 +1380,7 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === "get_formview_id") {
- return $.Deferred().resolve('A view');
+ return Promise.resolve('A view');
}
return this._super(route, args);
},
@@ -1419,13 +1400,14 @@ QUnit.module('Views', {
},
"should open the form view");
});
- calendar.$('.fc-event:contains(event 4) .fc-content').trigger('click');
+ await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
// create a new event and edit it
var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
testUtils.mock.intercept(calendar, 'do_action', function (event) {
@@ -1445,17 +1427,17 @@ QUnit.module('Views', {
"should open the form view with the context default values");
});
- $('.modal button.btn:contains(Edit)').trigger('click');
+ testUtils.dom.click($('.modal button.btn:contains(Edit)'));
calendar.destroy();
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) {
+ QUnit.test('create and edit event in month mode (all_day: false)', async function (assert) {
assert.expect(2);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1483,7 +1465,8 @@ QUnit.module('Views', {
var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
- testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
+ await testUtils.nextTick();
+ await testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
testUtils.mock.intercept(calendar, 'do_action', function (event) {
assert.deepEqual(event.data.action,
@@ -1501,18 +1484,18 @@ QUnit.module('Views', {
"should open the form view with the context default values");
});
- $('.modal button.btn:contains(Edit)').trigger('click');
+ await testUtils.dom.click($('.modal button.btn:contains(Edit)'));
calendar.destroy();
assert.strictEqual($('#ui-datepicker-div:empty').length, 0, "should have a clean body");
});
- QUnit.test('readonly date_start field', function (assert) {
+ QUnit.test('readonly date_start field', async function (assert) {
assert.expect(4);
this.data.event.fields.start.readonly = true;
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1532,7 +1515,7 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === "get_formview_id") {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
@@ -1554,14 +1537,15 @@ QUnit.module('Views', {
},
"should open the form view");
});
- calendar.$('.fc-event:contains(event 4) .fc-content').trigger('click');
+ await testUtils.dom.click(calendar.$('.fc-event:contains(event 4) .fc-content'));
// create a new event and edit it
var $cell = calendar.$('.fc-day-grid .fc-row:eq(4) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
- testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
+ await testUtils.nextTick();
+ await testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
testUtils.mock.intercept(calendar, 'do_action', function (event) {
assert.deepEqual(event.data.action,
@@ -1580,14 +1564,14 @@ QUnit.module('Views', {
"should open the form view with the context default values");
});
- $('.modal button.btn:contains(Edit)').trigger('click');
+ await testUtils.dom.click($('.modal button.btn:contains(Edit)'));
calendar.destroy();
assert.strictEqual($('#ui-datepicker-div:empty').length, 0, "should have a clean body");
});
- QUnit.test('"all" filter', function (assert) {
+ QUnit.test('"all" filter', async function (assert) {
assert.expect(6);
var interval = [
@@ -1603,7 +1587,7 @@ QUnit.module('Views', {
var i = 0;
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1636,26 +1620,26 @@ QUnit.module('Views', {
"should display 9 events on the week");
// Select the events only associated with partner 2
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-id=2] input'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-id=2] input'));
assert.containsN(calendar, '.fc-event', 4,
"should display 4 events on the week");
// Click on the 'all' filter to reload all events
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=all] input'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=all] input'));
assert.containsN(calendar, '.fc-event', 9,
"should display 9 events on the week");
calendar.destroy();
});
- QUnit.test('create event with filters', function (assert) {
+ QUnit.test('create event with filters', async function (assert) {
assert.expect(7);
this.data.event.fields.user_id.default = 5;
this.data.event.fields.partner_id.default = 3;
this.data.user.records.push({id: 5, display_name: "user 5", partner_id: 3});
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1675,34 +1659,32 @@ QUnit.module('Views', {
viewOptions: {
initialDate: initialDate,
},
- });
-
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
+ }, {positionalClicks: true});
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
assert.containsN(calendar, '.o_calendar_filter_item', 5, "should display 5 filter items");
assert.containsN(calendar, '.fc-event', 3, "should display 3 events");
// quick create a record
var left = calendar.$('.fc-bg td:eq(4)').offset().left+15;
- var top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15;
+ var top = calendar.$('.fc-slats tr:eq(12) td:first').offset().top+15;
try {
testUtils.dom.triggerPositionalMouseEvent(left, top, "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.');
}
testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mouseup");
+ await testUtils.nextTick();
- testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
- $('.modal-footer button.btn:contains(Create)').trigger('click');
+ await testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Create)'));
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should add the missing filter (active)");
assert.containsN(calendar, '.fc-event', 4, "should display the created item");
+ await testUtils.nextTick();
// change default value for quick create an hide record
this.data.event.fields.user_id.default = 4;
@@ -1710,26 +1692,26 @@ QUnit.module('Views', {
// quick create and other record
left = calendar.$('.fc-bg td:eq(3)').offset().left+15;
- top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15;
+ top = calendar.$('.fc-slats tr:eq(12) td:first').offset().top+15;
testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown");
testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mouseup");
+ await testUtils.nextTick();
testUtils.fields.editInput($('.modal-body input:first'), 'coucou 2');
- $('.modal-footer button.btn:contains(Create)').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Create)'));
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should have the same filters");
assert.containsN(calendar, '.fc-event', 4, "should not display the created item");
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
assert.containsN(calendar, '.fc-event', 11, "should display all records");
calendar.destroy();
- $view.remove();
});
- QUnit.test('create event with filters (no quickCreate)', function (assert) {
+ QUnit.test('create event with filters (no quickCreate)', async function (assert) {
assert.expect(4);
this.data.event.fields.user_id.default = 5;
@@ -1740,7 +1722,7 @@ QUnit.module('Views', {
partner_id: 3
});
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1772,42 +1754,39 @@ QUnit.module('Views', {
viewOptions: {
initialDate: initialDate,
},
- });
+ }, {positionalClicks: true});
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body'); // => select with click position
-
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
assert.containsN(calendar, '.o_calendar_filter_item', 5, "should display 5 filter items");
assert.containsN(calendar, '.fc-event', 3, "should display 3 events");
+ await testUtils.nextTick();
// quick create a record
var left = calendar.$('.fc-bg td:eq(4)').offset().left+15;
- var top = calendar.$('.fc-slats tr:eq(4) td:first').offset().top+15;
+ var top = calendar.$('.fc-slats tr:eq(12) td:first').offset().top+15;
try {
testUtils.dom.triggerPositionalMouseEvent(left, top, "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.');
}
testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mousemove");
testUtils.dom.triggerPositionalMouseEvent(left, top + 200, "mouseup");
+ await testUtils.nextTick();
- testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
+ await testUtils.fields.editInput($('.modal-body input:first'), 'coucou');
- $('.modal-footer button.btn:contains(Edit)').trigger('click');
- $('.modal-footer button.btn:contains(Save)').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Edit)'));
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Save)'));
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should add the missing filter (active)");
assert.containsN(calendar, '.fc-event', 4, "should display the created item");
calendar.destroy();
- $view.remove();
});
- QUnit.test('Update event with filters', function (assert) {
+ QUnit.test('Update event with filters', async function (assert) {
assert.expect(4);
var records = this.data.user.records;
@@ -1823,7 +1802,7 @@ QUnit.module('Views', {
}
};
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1857,16 +1836,16 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
assert.containsN(calendar, '.o_calendar_filter_item', 5, "should display 5 filter items");
assert.containsN(calendar, '.fc-event', 3, "should display 3 events");
- calendar.$('.fc-event:contains(event 2) .fc-content').trigger('click');
- $('.modal button.btn:contains(Edit)').trigger('click');
- $('.modal .o_field_widget[name="user_id"] input').trigger('click');
- $('.ui-menu-item a:contains(user 5)').trigger('mouseenter').trigger('click');
- $('.modal button.btn:contains(Save)').trigger('click');
+ await testUtils.dom.click(calendar.$('.fc-event:contains(event 2) .fc-content'));
+ await testUtils.dom.click($('.modal button.btn:contains(Edit)'));
+ await testUtils.dom.click($('.modal .o_field_widget[name="user_id"] input'));
+ await testUtils.dom.click($('.ui-menu-item a:contains(user 5)').trigger('mouseenter'));
+ await testUtils.dom.click($('.modal button.btn:contains(Save)'));
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should add the missing filter (active)");
assert.containsN(calendar, '.fc-event', 3, "should display the updated item");
@@ -1874,7 +1853,7 @@ QUnit.module('Views', {
calendar.destroy();
});
- QUnit.test('change pager with filters', function (assert) {
+ QUnit.test('change pager with filters', async function (assert) {
assert.expect(3);
this.data.user.records.push({
@@ -1914,7 +1893,7 @@ QUnit.module('Views', {
type: 1
});
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1936,8 +1915,8 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
- testUtils.dom.click($('.o_calendar_button_prev'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=4] input'));
+ await testUtils.dom.click($('.o_calendar_button_prev'));
assert.containsN(calendar, '.o_calendar_filter_item', 6, "should display 6 filter items");
assert.containsN(calendar, '.fc-event', 2, "should display 2 events");
@@ -1947,10 +1926,10 @@ QUnit.module('Views', {
calendar.destroy();
});
- QUnit.test('ensure events are still shown if filters give an empty domain', function (assert) {
+ QUnit.test('ensure events are still shown if filters give an empty domain', async function (assert) {
assert.expect(2);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1964,16 +1943,16 @@ QUnit.module('Views', {
assert.containsN(calendar, '.fc-event', 5,
"should display 5 events");
- testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=all] input[type=checkbox]'));
+ await testUtils.dom.click(calendar.$('.o_calendar_filter_item[data-value=all] input[type=checkbox]'));
assert.containsN(calendar, '.fc-event', 5,
"should display 5 events");
calendar.destroy();
});
- QUnit.test('events starting at midnight', function (assert) {
- assert.expect(2);
+ QUnit.test('events starting at midnight', async function (assert) {
+ assert.expect(3);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -1984,19 +1963,22 @@ QUnit.module('Views', {
translateParameters: { // Avoid issues due to localization formats
time_format: "%H:%M:%S",
},
- });
+ }, {positionalClicks: true});
+
+ // Reset the scroll to 0 as we want to create an event from midnight
+ assert.ok(calendar.$('.fc-scroller')[0].scrollTop > 0,
+ "should scroll to 6:00 by default (this is true at least for resolutions up to 1900x1600)");
+ calendar.$('.fc-scroller')[0].scrollTop = 0;
// Click on Tuesday 12am
- var $view = $('#qunit-fixture').contents();
- $view.prependTo('body');
var top = calendar.$('.fc-axis:contains(0:00)').offset().top + 5;
var left = calendar.$('.fc-day:eq(2)').offset().left + 5;
try {
testUtils.dom.triggerPositionalMouseEvent(left, top, "mousedown");
testUtils.dom.triggerPositionalMouseEvent(left, top, "mouseup");
+ await testUtils.nextTick();
} catch (e) {
calendar.destroy();
- $view.remove();
throw new Error('The test failed to simulate a click on the screen.' +
'Your screen is probably too small or your dev tools are open.');
}
@@ -2005,20 +1987,19 @@ QUnit.module('Views', {
// Creating the event
testUtils.fields.editInput($('.modal-body input:first'), 'new event in quick create');
- $('.modal-footer button.btn:contains(Create)').trigger('click').trigger('click');
+ await testUtils.dom.click($('.modal-footer button.btn:contains(Create)'));
assert.strictEqual(calendar.$('.fc-event:contains(new event in quick create)').length, 1,
"should display the new record after quick create dialog");
calendar.destroy();
- $view.remove();
});
- QUnit.test('set event as all day when field is date', function (assert) {
+ QUnit.test('set event as all day when field is date', async function (assert) {
assert.expect(2);
this.data.event.records[0].start_date = "2016-12-14";
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -2051,11 +2032,11 @@ QUnit.module('Views', {
calendar.destroy();
});
- QUnit.test('quickcreate avoid double event creation', function (assert) {
+ QUnit.test('quickcreate avoid double event creation', async function (assert) {
assert.expect(1);
var createCount = 0;
- var def = $.Deferred();
- var calendar = createView({
+ var prom = testUtils.makeTestPromise();
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -2077,7 +2058,7 @@ QUnit.module('Views', {
var result = this._super(route, args);
if (args.method === "create") {
createCount++;
- return def.then(_.constant(result));
+ return prom.then(_.constant(result));
}
return result;
},
@@ -2087,22 +2068,26 @@ QUnit.module('Views', {
var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
+
var $input = $('.modal input:first');
- testUtils.fields.editInput($input, 'new event in quick create');
+ await testUtils.fields.editInput($input, 'new event in quick create');
// Simulate ENTER pressed on Create button (after a TAB)
$input.trigger($.Event('keyup', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
- testUtils.dom.click($('.modal-footer button:first'));
- def.resolve();
+ await testUtils.nextTick();
+ await testUtils.dom.click($('.modal-footer button:first'));
+ prom.resolve();
+ await testUtils.nextTick();
assert.strictEqual(createCount, 1,
"should create only one event");
calendar.destroy();
});
- QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
assert.expect(1);
var instanceNumber = 0;
@@ -2141,13 +2126,13 @@ QUnit.module('Views', {
},
};
- var calendar = createView(params);
+ var calendar = await createCalendarView(params);
calendar.destroy();
var initialInstanceNumber = instanceNumber;
instanceNumber = 0;
- calendar = createView(params);
+ calendar = await createCalendarView(params);
// call destroy function of controller to ensure that it correctly destroys everything
calendar.__destroy();
@@ -2161,18 +2146,18 @@ QUnit.module('Views', {
testUtils.mock.unpatch(mixins.ParentedMixin);
});
- QUnit.test('create an event (async dialog) [REQUIRE FOCUS]', function (assert) {
+ QUnit.test('create an event (async dialog) [REQUIRE FOCUS]', async function (assert) {
assert.expect(3);
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
testUtils.mock.patch(Dialog, {
open: function () {
var _super = this._super.bind(this);
- def.then(_super);
+ prom.then(_super);
return this;
},
});
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -2197,11 +2182,13 @@ QUnit.module('Views', {
var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 0,
"should not have opened the dialog yet");
- def.resolve();
+ prom.resolve();
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 1,
"should have opened the dialog");
@@ -2212,7 +2199,7 @@ QUnit.module('Views', {
testUtils.mock.unpatch(Dialog);
});
- QUnit.test('calendar is configured to have no groupBy menu', function (assert) {
+ QUnit.test('calendar is configured to have no groupBy menu', async function (assert) {
assert.expect(1);
var archs = {
@@ -2233,22 +2220,22 @@ QUnit.module('Views', {
views: [[1, 'calendar']]
}];
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: actions,
archs: archs,
data: this.data,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.containsNone(actionManager.$('.o_control_panel .o_search_options span.fa.fa-bars'),
"the control panel has no groupBy menu");
actionManager.destroy();
});
- QUnit.test('timezone does not affect current day', function (assert) {
+ QUnit.test('timezone does not affect current day', async function (assert) {
assert.expect(2);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -2273,17 +2260,17 @@ QUnit.module('Views', {
assert.strictEqual($sidebar.find('.ui-datepicker-current-day').text(), "12", "should highlight the target day");
// go to previous day
- testUtils.dom.click($sidebar.find('.ui-datepicker-current-day').prev());
+ await testUtils.dom.click($sidebar.find('.ui-datepicker-current-day').prev());
assert.strictEqual($sidebar.find('.ui-datepicker-current-day').text(), "11", "should highlight the selected day");
calendar.destroy();
});
- QUnit.test('form_view_id attribute works (for creating events)', function (assert) {
+ QUnit.test('form_view_id attribute works (for creating events)', async function (assert) {
assert.expect(1);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -2305,7 +2292,7 @@ QUnit.module('Views', {
// reject the create rpc (quick create), then the web client
// fall back to a form view. This happens typically when a
// model has required fields
- return $.Deferred().reject('None shall pass!');
+ return Promise.reject('None shall pass!');
}
return this._super(route, args);
},
@@ -2320,17 +2307,19 @@ QUnit.module('Views', {
var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
- var $input = $('.modal-body input:first');
- testUtils.fields.editInput($input, "It's just a fleshwound");
- $('.modal button.btn:contains(Create)').trigger('click');
+ await testUtils.nextTick();
+ var $input = $('.modal-body input:first');
+ await testUtils.fields.editInput($input, "It's just a fleshwound");
+ await testUtils.dom.click($('.modal button.btn:contains(Create)'));
+ await testUtils.nextTick(); // wait a little before to finish the test
calendar.destroy();
});
- QUnit.test('calendar fallback to form view id in action if necessary', function (assert) {
+ QUnit.test('calendar fallback to form view id in action if necessary', async function (assert) {
assert.expect(1);
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
@@ -2352,7 +2341,7 @@ QUnit.module('Views', {
// reject the create rpc (quick create), then the web client
// fall back to a form view. This happens typically when a
// model has required fields
- return $.Deferred().reject('None shall pass!');
+ return Promise.reject('None shall pass!');
}
return this._super(route, args);
},
@@ -2367,14 +2356,15 @@ QUnit.module('Views', {
var $cell = calendar.$('.fc-day-grid .fc-row:eq(2) .fc-day:eq(2)');
testUtils.dom.triggerMouseEvent($cell, "mousedown");
testUtils.dom.triggerMouseEvent($cell, "mouseup");
- var $input = $('.modal-body input:first');
- testUtils.fields.editInput($input, "It's just a fleshwound");
- $('.modal button.btn:contains(Create)').trigger('click');
+ await testUtils.nextTick();
+ var $input = $('.modal-body input:first');
+ await testUtils.fields.editInput($input, "It's just a fleshwound");
+ await testUtils.dom.click($('.modal button.btn:contains(Create)'));
calendar.destroy();
});
- QUnit.test('fullcalendar initializes with right locale', function (assert) {
+ QUnit.test('fullcalendar initializes with right locale', async function (assert) {
assert.expect(1);
var initialLocale = moment.locale();
@@ -2386,7 +2376,7 @@ QUnit.module('Views', {
weekdaysShort: ["zz1.", "zz2.", "zz3.", "zz4.", "zz5.", "zz6.", "zz7."],
});
- var calendar = createView({
+ var calendar = await createCalendarView({
View: CalendarView,
model: 'event',
data: this.data,
diff --git a/addons/web/static/tests/views/control_panel_tests.js b/addons/web/static/tests/views/control_panel_tests.js
index f2654e55e1b..2e0a369ab4a 100644
--- a/addons/web/static/tests/views/control_panel_tests.js
+++ b/addons/web/static/tests/views/control_panel_tests.js
@@ -353,7 +353,7 @@ QUnit.module('Views', {
search_disable_custom_filters: true,
},
});
- testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
+ await testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
assert.containsOnce(controlPanel, '.o_menu_item a:contains("A")');
assert.containsNone(controlPanel, '.o_menu_item a:contains("B")');
@@ -371,8 +371,8 @@ QUnit.module('Views', {
data: this.data,
searchMenuTypes: ['filter'],
});
- testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
- testUtils.dom.click($('.o_menu_item a'));
+ await testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
+ await testUtils.dom.click($('.o_menu_item a'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'A',
'should have a facet with A');
@@ -381,14 +381,16 @@ QUnit.module('Views', {
which: $.ui.keyCode.BACKSPACE,
keyCode: $.ui.keyCode.BACKSPACE,
}));
+ await testUtils.nextTick();
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0,
- 'there should be no facet');
+ 'there should be no facet');
// delete nothing (should not crash)
controlPanel.$('input.o_searchview_input').trigger($.Event('keydown', {
which: $.ui.keyCode.BACKSPACE,
keyCode: $.ui.keyCode.BACKSPACE,
}));
+ await testUtils.nextTick();
controlPanel.destroy();
});
@@ -409,7 +411,7 @@ QUnit.module('Views', {
search_disable_custom_filters: true,
},
});
- testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
+ await testUtils.dom.click(controlPanel.$('.o_filters_menu_button'));
assert.containsOnce(controlPanel, '.o_menu_item a:contains("A")');
assert.containsNone(controlPanel, '.o_menu_item a:contains("B")');
diff --git a/addons/web/static/tests/views/form_tests.js b/addons/web/static/tests/views/form_tests.js
index b1df6260359..96d36d8eec9 100644
--- a/addons/web/static/tests/views/form_tests.js
+++ b/addons/web/static/tests/views/form_tests.js
@@ -16,7 +16,6 @@ var Widget = require('web.Widget');
var _t = core._t;
var createView = testUtils.createView;
-var createAsyncView = testUtils.createAsyncView;
var createActionManager = testUtils.createActionManager;
QUnit.module('Views', {
@@ -105,7 +104,6 @@ QUnit.module('Views', {
]
},
};
-
this.actions = [{
id: 1,
name: 'Partners Action 1',
@@ -113,15 +111,15 @@ QUnit.module('Views', {
type: 'ir.actions.act_window',
views: [[false, 'kanban'], [false, 'form']],
}];
- }
+ },
}, function () {
QUnit.module('FormView');
- QUnit.test('simple form rendering', function (assert) {
+ QUnit.test('simple form rendering', async function (assert) {
assert.expect(12);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -174,10 +172,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('attributes are transferred on async widgets', function (assert) {
+ QUnit.test('attributes are transferred on async widgets', async function (assert) {
assert.expect(1);
+ var done = assert.async();
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
var FieldChar = fieldRegistry.get('char');
fieldRegistry.add('asyncwidget', FieldChar.extend({
@@ -186,7 +185,7 @@ QUnit.module('Views', {
},
}));
- createAsyncView({
+ createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -201,14 +200,16 @@ QUnit.module('Views', {
"should apply style attribute on fields");
form.destroy();
delete fieldRegistry.map.asyncwidget;
+ done();
});
def.resolve();
+ await testUtils.nextTick();
});
- QUnit.test('decoration works on widgets', function (assert) {
+ QUnit.test('decoration works on widgets', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -224,10 +225,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('decoration on widgets are reevaluated if necessary', function (assert) {
+ QUnit.test('decoration on widgets are reevaluated if necessary', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -239,15 +240,15 @@ QUnit.module('Views', {
viewOptions: {mode: 'edit'},
});
assert.doesNotHaveClass(form.$('input[name="display_name"]'), 'text-danger');
- testUtils.fields.editInput(form.$('input[name=int_field]'), 3);
+ await testUtils.fields.editInput(form.$('input[name=int_field]'), 3);
assert.hasClass(form.$('input[name="display_name"]'), 'text-danger');
form.destroy();
});
- QUnit.test('decoration on widgets works on same widget', function (assert) {
+ QUnit.test('decoration on widgets works on same widget', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -258,15 +259,15 @@ QUnit.module('Views', {
viewOptions: {mode: 'edit'},
});
assert.doesNotHaveClass(form.$('input[name="int_field"]'), 'text-danger');
- testUtils.fields.editInput(form.$('input[name=int_field]'), 3);
+ await testUtils.fields.editInput(form.$('input[name=int_field]'), 3);
assert.hasClass(form.$('input[name="int_field"]'), 'text-danger');
form.destroy();
});
- QUnit.test('only necessary fields are fetched with correct context', function (assert) {
+ QUnit.test('only necessary fields are fetched with correct context', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -287,10 +288,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('group rendering', function (assert) {
+ QUnit.test('group rendering', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -308,14 +309,14 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('Form and subview with _view_ref contexts', function (assert) {
+ QUnit.test('Form and subview with _view_ref contexts', async function (assert) {
assert.expect(2);
this.data.product.fields.partner_type_ids = {string: "one2many field", type: "one2many", relation: "partner_type"},
this.data.product.records = [{id: 1, name: 'Tromblon', partner_type_ids: [12,14]}];
this.data.partner.records[0].product_id = 1;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
data: this.data,
archs: {
'product,false,form': '<form>'+
@@ -344,7 +345,7 @@ QUnit.module('Views', {
},
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -356,7 +357,7 @@ QUnit.module('Views', {
mockRPC: function(route, args) {
if (args.method === 'get_formview_action') {
- return $.when({
+ return Promise.resolve({
res_id: 1,
type: 'ir.actions.act_window',
target: 'current',
@@ -376,14 +377,14 @@ QUnit.module('Views', {
},
},
});
- form.$('.o_field_widget[name="product_id"]').click();
+ await testUtils.dom.click(form.$('.o_field_widget[name="product_id"]'));
form.destroy();
actionManager.destroy();
});
- QUnit.test('invisible fields are properly hidden', function (assert) {
+ QUnit.test('invisible fields are properly hidden', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -410,10 +411,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('invisible elements are properly hidden', function (assert) {
+ QUnit.test('invisible elements are properly hidden', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -446,7 +447,8 @@ QUnit.module('Views', {
// we set the value bar to simulate a falsy boolean value.
this.data.partner.records[0].bar = false;
- var form = createView({
+
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -459,9 +461,11 @@ QUnit.module('Views', {
'</group></sheet>' +
'</form>',
res_id: 1,
+ viewOptions: {
+ mode:'edit'
+ },
});
- testUtils.form.clickEdit(form);
assert.hasClass(form.$('.foo_field'), 'o_invisible_modifier');
assert.hasClass(form.$('.bar_field'), 'o_invisible_modifier');
@@ -472,10 +476,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('asynchronous fields can be set invisible', function (assert) {
+ QUnit.test('asynchronous fields can be set invisible', async function (assert) {
assert.expect(1);
+ var done = assert.async();
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
// we choose this widget because it is a quite simple widget with a non
// empty qweb template
@@ -486,7 +491,7 @@ QUnit.module('Views', {
},
}));
- createAsyncView({
+ createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -501,15 +506,15 @@ QUnit.module('Views', {
assert.hasClass(form.$('.o_field_widget[name="int_field"]'), 'o_invisible_modifier');
form.destroy();
delete fieldRegistry.map.asyncwidget;
+ done();
});
def.resolve();
});
-
- QUnit.test('properly handle modifiers and attributes on notebook tags', function (assert) {
+ QUnit.test('properly handle modifiers and attributes on notebook tags', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -531,10 +536,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('invisible attrs on first notebook page', function (assert) {
+ QUnit.test('invisible attrs on first notebook page', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -554,12 +559,12 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasClass(form.$('.o_notebook .nav .nav-link:first()'), 'active');
assert.doesNotHaveClass(form.$('.o_notebook .nav .nav-item:first()'), 'o_invisible_modifier');
// set a value on the m2o
- testUtils.fields.many2one.searchAndClickItem('product_id');
+ await testUtils.fields.many2one.searchAndClickItem('product_id');
assert.doesNotHaveClass(form.$('.o_notebook .nav .nav-link:first()'), 'active');
assert.hasClass(form.$('.o_notebook .nav .nav-item:first()'), 'o_invisible_modifier');
assert.hasClass(form.$('.o_notebook .nav .nav-link:nth(1)'), 'active');
@@ -567,10 +572,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('first notebook page invisible', function (assert) {
+ QUnit.test('first notebook page invisible', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -597,10 +602,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('autofocus on second notebook page', function (assert) {
+ QUnit.test('autofocus on second notebook page', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -626,10 +631,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('invisible attrs on group are re-evaluated on field change', function (assert) {
+ QUnit.test('invisible attrs on group are re-evaluated on field change', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -643,22 +648,24 @@ QUnit.module('Views', {
'</group>' +
'</sheet>' +
'</form>',
- res_id: 1
+ res_id: 1,
+ viewOptions: {
+ mode: 'edit'
+ },
});
assert.containsOnce(form, 'div.o_group:visible');
- testUtils.form.clickEdit(form);
- testUtils.dom.click('.o_field_boolean input', form);
+ await testUtils.dom.click('.o_field_boolean input', form);
assert.containsOnce(form, 'div.o_group:hidden');
form.destroy();
});
- QUnit.test('invisible attrs with zero value in domain and unset value in data', function (assert) {
+ QUnit.test('invisible attrs with zero value in domain and unset value in data', async function (assert) {
assert.expect(1);
this.data.partner.fields.int_field.type = 'monetary';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -677,10 +684,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('rendering stat buttons', function (assert) {
+ QUnit.test('rendering stat buttons', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -706,18 +713,18 @@ QUnit.module('Views', {
assert.containsOnce(form, 'button.oe_stat_button.o_invisible_modifier');
var count = 0;
- testUtils.mock.intercept(form, "execute_action", function () {
+ await testUtils.mock.intercept(form, "execute_action", function () {
count++;
});
- testUtils.dom.click('.oe_stat_button');
+ await testUtils.dom.click('.oe_stat_button');
assert.strictEqual(count, 1, "should have triggered a execute action");
form.destroy();
});
- QUnit.test('label uses the string attribute', function (assert) {
+ QUnit.test('label uses the string attribute', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -736,10 +743,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('readonly attrs on fields are re-evaluated on field change', function (assert) {
+ QUnit.test('readonly attrs on fields are re-evaluated on field change', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -753,24 +760,24 @@ QUnit.module('Views', {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'span[name="foo"]',
"the foo field widget should be readonly");
- testUtils.dom.click(form.$('.o_field_boolean input'));
+ await testUtils.dom.click(form.$('.o_field_boolean input'));
assert.containsOnce(form, 'input[name="foo"]',
"the foo field widget should have been rerendered to now be editable");
- testUtils.dom.click(form.$('.o_field_boolean input'));
+ await testUtils.dom.click(form.$('.o_field_boolean input'));
assert.containsOnce(form, 'span[name="foo"]',
"the foo field widget should have been rerendered to now be readonly again");
- testUtils.dom.click(form.$('.o_field_boolean input'));
+ await testUtils.dom.click(form.$('.o_field_boolean input'));
assert.containsOnce(form, 'input[name="foo"]',
"the foo field widget should have been rerendered to now be editable again");
form.destroy();
});
- QUnit.test('empty fields have o_form_empty class in readonly mode', function (assert) {
+ QUnit.test('empty fields have o_form_empty class in readonly mode', async function (assert) {
assert.expect(8);
this.data.partner.fields.foo.default = false; // no default value for this test
@@ -783,7 +790,7 @@ QUnit.module('Views', {
}
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -804,21 +811,21 @@ QUnit.module('Views', {
assert.containsN(form, '.o_form_label_empty', 2,
"should have 2 muted labels (for the empty fieds) in readonly");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.o_field_empty',
"in edit mode, only empty readonly fields should have the o_field_empty class");
assert.containsOnce(form, '.o_form_label_empty',
"in edit mode, only labels associated to empty readonly fields should have the o_form_label_empty class");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'test');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'test');
assert.containsNone(form, '.o_field_empty',
"after readonly modifier change, the o_field_empty class should have been removed");
assert.containsNone(form, '.o_form_label_empty',
"after readonly modifier change, the o_form_label_empty class should have been removed");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'hello');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'hello');
assert.containsOnce(form, '.o_field_empty',
"after value changed to false for a readonly field, the o_field_empty class should have been added");
@@ -828,14 +835,14 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('empty fields\' labels still get the empty class after widget rerender', function (assert) {
+ QUnit.test('empty fields\' labels still get the empty class after widget rerender', async function (assert) {
assert.expect(6);
this.data.partner.fields.foo.default = false; // no default value for this test
this.data.partner.records[1].foo = false; // 1 is record with id=2
this.data.partner.records[1].display_name = false; // 1 is record with id=2
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -848,21 +855,21 @@ QUnit.module('Views', {
res_id: 2,
});
- assert.containsN(form, '.o_field_widget.o_field_empty', 2)
+ assert.containsN(form, '.o_field_widget.o_field_empty', 2);
assert.containsN(form, '.o_form_label_empty', 2,
"should have 1 muted label (for the empty fied) in readonly");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsNone(form, '.o_field_empty',
"in edit mode, only empty readonly fields should have the o_field_empty class");
assert.containsNone(form, '.o_form_label_empty',
"in edit mode, only labels associated to empty readonly fields should have the o_form_label_empty class");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'readonly');
- testUtils.fields.editInput(form.$('input[name=foo]'), 'edit');
- testUtils.fields.editInput(form.$('input[name=display_name]'), 'some name');
- testUtils.fields.editInput(form.$('input[name=foo]'), 'readonly');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'readonly');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'edit');
+ await testUtils.fields.editInput(form.$('input[name=display_name]'), 'some name');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'readonly');
assert.containsNone(form, '.o_field_empty',
"there still should not be any empty class on fields as the readonly one is now set");
@@ -872,11 +879,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('empty inner readonly fields don\'t have o_form_empty class in "create" mode', function (assert) {
+ QUnit.test('empty inner readonly fields don\'t have o_form_empty class in "create" mode', async function (assert) {
assert.expect(2);
this.data.partner.fields.product_id.readonly = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -897,10 +904,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('form view can switch to edit mode', function (assert) {
+ QUnit.test('form view can switch to edit mode', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -915,7 +922,7 @@ QUnit.module('Views', {
assert.isVisible(form.$buttons.find('.o_form_buttons_view'));
assert.isNotVisible(form.$buttons.find('.o_form_buttons_edit'));
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.mode, 'edit', 'form view should be in edit mode');
assert.hasClass(form.$('.o_form_view'), 'o_form_editable');
@@ -925,10 +932,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('required attrs on fields are re-evaluated on field change', function (assert) {
+ QUnit.test('required attrs on fields are re-evaluated on field change', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -942,25 +949,25 @@ QUnit.module('Views', {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[name="foo"].o_required_modifier',
"the foo field widget should be required");
- testUtils.dom.click('.o_field_boolean input');
+ await testUtils.dom.click('.o_field_boolean input');
assert.containsOnce(form, 'input[name="foo"]:not(.o_required_modifier)',
"the foo field widget should now have been marked as non-required");
- testUtils.dom.click('.o_field_boolean input');
+ await testUtils.dom.click('.o_field_boolean input');
assert.containsOnce(form, 'input[name="foo"].o_required_modifier',
"the foo field widget should now have been marked as required again");
form.destroy();
});
- QUnit.test('required fields should have o_required_modifier in readonly mode', function (assert) {
+ QUnit.test('required fields should have o_required_modifier in readonly mode', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.required = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -976,17 +983,17 @@ QUnit.module('Views', {
assert.containsOnce(form, 'span.o_required_modifier', form);
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input.o_required_modifier',
"in edit mode, should have 1 input with o_required_modifier");
form.destroy();
});
- QUnit.test('required float fields works as expected', function (assert) {
+ QUnit.test('required float fields works as expected', async function (assert) {
assert.expect(10);
this.data.partner.fields.qux.required = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1007,29 +1014,29 @@ QUnit.module('Views', {
assert.strictEqual(form.$('input[name="qux"]').val(), "0.0",
"qux input is 0 by default (float field)");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.containsNone(form.$('input[name="qux"]'), "should have switched to readonly");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=qux]'), '1');
+ await testUtils.fields.editInput(form.$('input[name=qux]'), '1');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- assert.strictEqual(form.$('input[name="qux"]').val(), "1.0",
+ assert.strictEqual(form.$('input[name="qux"]').val(), "1.0",
"qux input is properly formatted");
assert.verifySteps(['default_get', 'create', 'read', 'write', 'read']);
form.destroy();
});
- QUnit.test('separators', function (assert) {
+ QUnit.test('separators', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1048,10 +1055,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('invisible attrs on separators', function (assert) {
+ QUnit.test('invisible attrs on separators', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1071,12 +1078,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('buttons in form view', function (assert) {
+ QUnit.test('buttons in form view', async function (assert) {
assert.expect(8);
var rpcCount = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1104,7 +1111,7 @@ QUnit.module('Views', {
assert.containsOnce(form, 'button.p[name="post"]:contains(Confirm)');
assert.containsN(form, '.o_form_statusbar button:visible', 2);
- testUtils.mock.intercept(form, 'execute_action', function (ev) {
+ await testUtils.mock.intercept(form, 'execute_action', function (ev) {
assert.strictEqual(ev.data.action_data.name, 'post',
"should trigger execute_action with correct method name");
assert.deepEqual(ev.data.env.currentID, 2, "should have correct id in ev data");
@@ -1112,14 +1119,14 @@ QUnit.module('Views', {
ev.data.on_closed();
});
rpcCount = 0;
- testUtils.dom.click('.o_form_statusbar button.p', form);
+ await testUtils.dom.click('.o_form_statusbar button.p', form);
assert.strictEqual(rpcCount, 1, "should have done 1 rpcs to reload");
- testUtils.mock.intercept(form, 'execute_action', function (ev) {
+ await testUtils.mock.intercept(form, 'execute_action', function (ev) {
ev.data.on_fail();
});
- testUtils.dom.click('.o_form_statusbar button.s', form);
+ await testUtils.dom.click('.o_form_statusbar button.s', form);
assert.strictEqual(rpcCount, 1,
"should have done 1 rpc, because we do not reload anymore if the server action fails");
@@ -1127,10 +1134,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('buttons classes in form view', function (assert) {
+ QUnit.test('buttons classes in form view', async function (assert) {
assert.expect(16);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1180,13 +1187,13 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('buttons in form view, new record', function (assert) {
+ QUnit.test('buttons in form view, new record', async function (assert) {
// this simulates a situation similar to the settings forms.
assert.expect(7);
var resID;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1213,20 +1220,20 @@ QUnit.module('Views', {
},
});
- testUtils.mock.intercept(form, 'execute_action', function (event) {
+ await testUtils.mock.intercept(form, 'execute_action', function (event) {
assert.step('execute_action');
assert.deepEqual(event.data.env.currentID, resID,
"execute action should be done on correct record id");
event.data.on_success();
event.data.on_closed();
});
- testUtils.dom.click('.o_form_statusbar button.p', form);
+ await testUtils.dom.click('.o_form_statusbar button.p', form);
assert.verifySteps(['default_get', 'create', 'read', 'execute_action', 'read']);
form.destroy();
});
- QUnit.test('buttons in form view, new record, with field id in view', function (assert) {
+ QUnit.test('buttons in form view, new record, with field id in view', async function (assert) {
assert.expect(7);
// buttons in form view are one of the rare example of situation when we
// save a record without reloading it immediately, because we only care
@@ -1236,7 +1243,7 @@ QUnit.module('Views', {
var resID;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1263,22 +1270,22 @@ QUnit.module('Views', {
},
});
- testUtils.mock.intercept(form, 'execute_action', function (event) {
+ await testUtils.mock.intercept(form, 'execute_action', function (event) {
assert.step('execute_action');
assert.deepEqual(event.data.env.currentID, resID,
"execute action should be done on correct record id");
event.data.on_success();
event.data.on_closed();
});
- testUtils.dom.click('.o_form_statusbar button.p', form);
+ await testUtils.dom.click('.o_form_statusbar button.p', form);
assert.verifySteps(['default_get', 'create', 'read', 'execute_action', 'read']);
form.destroy();
});
- QUnit.test('change and save char', function (assert) {
+ QUnit.test('change and save char', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1298,11 +1305,11 @@ QUnit.module('Views', {
assert.containsOnce(form, 'span:contains(blip)',
"should contain span with field value");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.mode, 'edit', 'form view should be in edit mode');
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode');
assert.containsOnce(form, 'span:contains(tralala)',
@@ -1310,10 +1317,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('properly reload data from server', function (assert) {
+ QUnit.test('properly reload data from server', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1329,18 +1336,18 @@ QUnit.module('Views', {
res_id: 2,
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, 'span:contains(apple)',
"should contain span with field value");
form.destroy();
});
- QUnit.test('disable buttons until reload data from server', function (assert) {
+ QUnit.test('disable buttons until reload data from server', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1353,22 +1360,23 @@ QUnit.module('Views', {
} else if (args.method === 'read') {
// Block the 'read' call
var result = this._super.apply(this, arguments);
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(result);
}
return this._super(route, args);
},
res_id: 2,
});
- var def = $.Deferred();
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.form.clickSave(form);
+ var def = testUtils.makeTestPromise();
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.form.clickSave(form);
// Save button should be disabled
assert.hasAttrValue(form.$buttons.find('.o_form_button_save'), 'disabled', 'disabled');
// Release the 'read' call
- def.resolve();
+ await def.resolve();
+ await testUtils.nextTick();
// Edit button should be enabled after the reload
assert.hasAttrValue(form.$buttons.find('.o_form_button_edit'), 'disabled', undefined);
@@ -1376,7 +1384,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('properly apply onchange in simple case', function (assert) {
+ QUnit.test('properly apply onchange in simple case', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = {
@@ -1384,7 +1392,7 @@ QUnit.module('Views', {
obj.int_field = obj.foo.length + 1000;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1394,19 +1402,19 @@ QUnit.module('Views', {
res_id: 2,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=int_field]').val(), "9",
"should contain input with initial value");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
assert.strictEqual(form.$('input[name=int_field]').val(), "1007",
"should contain input with onchange applied");
form.destroy();
});
- QUnit.test('properly apply onchange when changed field is active field', function (assert) {
+ QUnit.test('properly apply onchange when changed field is active field', async function (assert) {
assert.expect(3);
this.data.partner.onchanges = {
@@ -1414,7 +1422,7 @@ QUnit.module('Views', {
obj.int_field = 14;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1429,27 +1437,27 @@ QUnit.module('Views', {
assert.strictEqual(form.$('input[name=int_field]').val(), "9",
"should contain input with initial value");
- testUtils.fields.editInput(form.$('input[name=int_field]'), '666');
+ await testUtils.fields.editInput(form.$('input[name=int_field]'), '666');
assert.strictEqual(form.$('input[name=int_field]').val(), "14",
"value should have been set to 14 by onchange");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
- assert.strictEqual(form.$('.o_field_widget[name=int_field]').text(), "14",
+ assert.strictEqual(form.$('.o_field_widget[name=int_field]').text(), "14",
"value should still be 14");
form.destroy();
});
- QUnit.test('onchange send only the present fields to the server', function (assert) {
+ QUnit.test('onchange send only the present fields to the server', async function (assert) {
assert.expect(1);
this.data.partner.records[0].product_id = false;
this.data.partner.onchanges.foo = function (obj) {
obj.foo = obj.foo + " alligator";
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1477,17 +1485,17 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
form.destroy();
});
- QUnit.test('onchange only send present fields value', function (assert) {
+ QUnit.test('onchange only send present fields value', async function (assert) {
assert.expect(1);
this.data.partner.onchanges.foo = function (obj) {};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1515,22 +1523,24 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// add a o2m row
- testUtils.dom.click('.o_field_x2many_list_row_add a');
+ await testUtils.dom.click('.o_field_x2many_list_row_add a');
form.$('.o_field_one2many input:first').focus();
- testUtils.fields.editInput(form.$('.o_field_one2many input[name=display_name]'), 'valid line');
+ await testUtils.nextTick();
+ await testUtils.fields.editInput(form.$('.o_field_one2many input[name=display_name]'), 'valid line');
form.$('.o_field_one2many input:last').focus();
- testUtils.fields.editInput(form.$('.o_field_one2many input[name=qux]'), '12.4');
+ await testUtils.nextTick();
+ await testUtils.fields.editInput(form.$('.o_field_one2many input[name=qux]'), '12.4');
// trigger an onchange by modifying foo
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
form.destroy();
});
- QUnit.test('evaluate in python field options', function (assert) {
+ QUnit.test('evaluate in python field options', async function (assert) {
assert.expect(1);
var isOk = false;
@@ -1541,7 +1551,7 @@ QUnit.module('Views', {
}
return tmp.apply(tmp, arguments);
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1557,10 +1567,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('can create a record with default values', function (assert) {
+ QUnit.test('can create a record with default values', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1586,23 +1596,23 @@ QUnit.module('Views', {
});
var n = this.data.partner.records.length;
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
assert.strictEqual(form.mode, 'edit', 'form view should be in edit mode');
- assert.strictEqual(form.$('input[name=foo]').val(), "My little Foo Value",
+ assert.strictEqual(form.$('input:first').val(), "My little Foo Value",
"should have correct default_get value");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode');
assert.strictEqual(this.data.partner.records.length, n + 1, "should have created a record");
form.destroy();
});
- QUnit.test('default record with a one2many and an onchange on sub field', function (assert) {
+ QUnit.test('default record with a one2many and an onchange on sub field', async function (assert) {
assert.expect(4);
this.data.partner.onchanges.foo = function () {};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1628,10 +1638,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('sidebar is hidden when switching to edit mode', function (assert) {
+ QUnit.test('sidebar is hidden when switching to edit mode', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1645,21 +1655,21 @@ QUnit.module('Views', {
});
assert.isVisible(form.sidebar);
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.isNotVisible(form.sidebar);
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.isVisible(form.sidebar);
form.destroy();
});
- QUnit.test('basic default record', function (assert) {
+ QUnit.test('basic default record', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.default = "default foo value";
var count = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1677,7 +1687,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('make default record with non empty one2many', function (assert) {
+ QUnit.test('make default record with non empty one2many', async function (assert) {
assert.expect(4);
this.data.partner.fields.p.default = [
@@ -1688,7 +1698,7 @@ QUnit.module('Views', {
var nameGetCount = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1717,7 +1727,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('make default record with non empty many2one', function (assert) {
+ QUnit.test('make default record with non empty many2one', async function (assert) {
var done = assert.async();
assert.expect(2);
@@ -1725,7 +1735,7 @@ QUnit.module('Views', {
var nameGetCount = 0;
- createAsyncView({
+ createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1749,10 +1759,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('form view properly change its title', function (assert) {
+ QUnit.test('form view properly change its title', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1765,17 +1775,17 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'first record',
"should have the display name of the record as title");
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), _t("New"),
"should have the display name of the record as title");
form.destroy();
});
- QUnit.test('can duplicate a record', function (assert) {
+ QUnit.test('can duplicate a record', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1789,8 +1799,8 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'first record',
"should have the display name of the record as title");
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'first record (copy)',
"should have duplicated the record");
@@ -1799,10 +1809,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('duplicating a record preserve the context', function (assert) {
+ QUnit.test('duplicating a record preserve the context', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1822,16 +1832,16 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
form.destroy();
});
- QUnit.test('cannot duplicate a record', function (assert) {
+ QUnit.test('cannot duplicate a record', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1849,10 +1859,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('clicking on stat buttons in edit mode', function (assert) {
+ QUnit.test('clicking on stat buttons in edit mode', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1878,30 +1888,30 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var count = 0;
- testUtils.mock.intercept(form, "execute_action", function (event) {
+ await testUtils.mock.intercept(form, "execute_action", function (event) {
event.stopPropagation();
count++;
});
- testUtils.dom.click('.oe_stat_button');
+ await testUtils.dom.click('.oe_stat_button');
assert.strictEqual(count, 1, "should have triggered a execute action");
assert.strictEqual(form.mode, "edit", "form view should be in edit mode");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.dom.click('.oe_stat_button:first');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.dom.click('.oe_stat_button:first');
- assert.strictEqual(form.mode, "edit", "form view should be in edit mode");
+ assert.strictEqual(form.mode, "edit", "form view should be in edit mode");
assert.strictEqual(count, 2, "should have triggered a execute action");
assert.verifySteps(['read', 'write', 'read']);
form.destroy();
});
- QUnit.test('clicking on stat buttons save and reload in edit mode', function (assert) {
+ QUnit.test('clicking on stat buttons save and reload in edit mode', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1930,23 +1940,23 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'second record',
"should have correct display_name");
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=name]'), 'some other name');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=name]'), 'some other name');
- testUtils.dom.click('.oe_stat_button');
+ await testUtils.dom.click('.oe_stat_button');
assert.strictEqual(form.$('.o_control_panel .breadcrumb').text(), 'GOLDORAK',
"should have correct display_name");
form.destroy();
});
- QUnit.test('buttons with attr "special" do not trigger a save', function (assert) {
+ QUnit.test('buttons with attr "special" do not trigger a save', async function (assert) {
assert.expect(4);
var executeActionCount = 0;
var writeCount = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1961,34 +1971,35 @@ QUnit.module('Views', {
writeCount++;
}
return this._super(route, args);
- }
+ },
});
- testUtils.mock.intercept(form, "execute_action", function () {
+ await testUtils.mock.intercept(form, "execute_action", function () {
executeActionCount++;
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// make the record dirty
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.dom.click(form.$('button:contains(Do something)'));
+ await testUtils.dom.click(form.$('button:contains(Do something)'));
+ //TODO: VSC: add a next tick ?
assert.strictEqual(writeCount, 1, "should have triggered a write");
assert.strictEqual(executeActionCount, 1, "should have triggered a execute action");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'abcdef');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'abcdef');
- testUtils.dom.click(form.$('button:contains(Or discard)'));
+ await testUtils.dom.click(form.$('button:contains(Or discard)'));
assert.strictEqual(writeCount, 1, "should not have triggered a write");
assert.strictEqual(executeActionCount, 2, "should have triggered a execute action");
form.destroy();
});
- QUnit.test('buttons with attr "special=save" save', function (assert) {
+ QUnit.test('buttons with attr "special=save" save', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2011,18 +2022,18 @@ QUnit.module('Views', {
},
});
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.dom.click(form.$('.o_form_view button'));
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.dom.click(form.$('button[special="save"]'));
assert.verifySteps(['read', 'write', 'read', 'execute_action']);
form.destroy();
});
- QUnit.test('missing widgets do not crash', function (assert) {
+ QUnit.test('missing widgets do not crash', async function (assert) {
assert.expect(1);
this.data.partner.fields.foo.type = 'new field type without widget';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2035,10 +2046,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('nolabel', function (assert) {
+ QUnit.test('nolabel', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2073,13 +2084,13 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('many2one in a one2many', function (assert) {
+ QUnit.test('many2one in a one2many', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
this.data.partner.records[1].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2096,13 +2107,13 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('circular many2many\'s', function (assert) {
+ QUnit.test('circular many2many\'s', async function (assert) {
assert.expect(4);
- this.data.partner_type.fields.partner_ids = {string: "partners", type: "many2many", relation: 'partner'}
+ this.data.partner_type.fields.partner_ids = {string: "partners", type: "many2many", relation: 'partner'};
this.data.partner.records[0].timmy = [12];
this.data.partner_type.records[0].partner_ids = [1];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2128,24 +2139,24 @@ QUnit.module('Views', {
assert.containsOnce(form, 'td:contains(gold)',
"should display the name of the many2many on the original form");
- testUtils.dom.click(form.$('td:contains(gold)'));
+ await testUtils.dom.click(form.$('td:contains(gold)'));
assert.containsOnce(document.body, '.modal');
assert.containsOnce($('.modal'), 'td:contains(first record)',
"should display the name of the many2many on the modal form");
- testUtils.dom.click('.modal td:contains(first record)');
+ await testUtils.dom.click('.modal td:contains(first record)');
assert.containsN(document.body, '.modal', 2,
"there should be 2 modals (partner on top of partner_type) opened");
form.destroy();
});
- QUnit.test('discard changes on a non dirty form view', function (assert) {
+ QUnit.test('discard changes on a non dirty form view', async function (assert) {
assert.expect(4);
var nbWrite = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2160,25 +2171,24 @@ QUnit.module('Views', {
});
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=foo]').val(), 'yop',
"input should contain yop");
// click on discard
- testUtils.form.clickDiscard(form);
- assert.containsNone(document.body, '.modal', "no confirm modal should be displayed");
- assert.strictEqual(form.$('.o_field_widget').text(), 'yop',
- "field in readonly should display yop");
+ await testUtils.form.clickDiscard(form);
+ assert.containsNone(document.body, '.modal', 'no confirm modal should be displayed');
+ assert.strictEqual(form.$('.o_field_widget').text(), 'yop', 'field in readonly should display yop');
assert.strictEqual(nbWrite, 0, "no write RPC should have been done");
form.destroy();
});
- QUnit.test('discard changes on a dirty form view', function (assert) {
+ QUnit.test('discard changes on a dirty form view', async function (assert) {
assert.expect(7);
var nbWrite = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2193,31 +2203,29 @@ QUnit.module('Views', {
});
// switch to edit mode and edit the foo field
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=foo]').val(), 'yop', "input should contain yop");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
assert.strictEqual(form.$('input[name=foo]').val(), 'new value',
"input should contain new value");
// click on discard and cancel the confirm request
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed");
- testUtils.dom.click('.modal-footer .btn-secondary');
- assert.strictEqual(form.$('input[name=foo]').val(), 'new value',
- "input should still contain new value");
+ await testUtils.dom.click('.modal-footer .btn-secondary');
+ assert.strictEqual(form.$('input').val(), 'new value', 'input should still contain new value');
// click on discard and confirm
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed");
- testUtils.dom.click('.modal-footer .btn-primary');
- assert.strictEqual(form.$('.o_field_widget').text(), 'yop',
- "field in readonly should display yop");
+ await testUtils.dom.click('.modal-footer .btn-primary');
+ assert.strictEqual(form.$('.o_field_widget').text(), 'yop', 'field in readonly should display yop');
assert.strictEqual(nbWrite, 0, "no write RPC should have been done");
form.destroy();
});
- QUnit.test('discard changes on a dirty form view (for date field)', function (assert) {
+ QUnit.test('discard changes on a dirty form view (for date field)', async function (assert) {
assert.expect(1);
// this test checks that the basic model properly handles date object
@@ -2226,7 +2234,7 @@ QUnit.module('Views', {
// then parsed into string, which is wrong.
this.data.partner.fields.date.default = "2017-01-25";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2243,18 +2251,18 @@ QUnit.module('Views', {
// event to properly focusout the input, otherwise it crashes later on
// when the 'blur' event is triggered by the re-rendering)
form.$buttons.find('.o_form_button_cancel').focus();
- testUtils.dom.click('.o_form_button_cancel');
+ await testUtils.dom.click('.o_form_button_cancel');
form.$buttons.find('.o_form_button_save').focus();
- testUtils.dom.click('.o_form_button_save');
+ await testUtils.dom.click('.o_form_button_save');
assert.containsOnce(form, 'span:contains(2017)');
form.destroy();
});
- QUnit.test('discard changes on relational data on new record', function (assert) {
+ QUnit.test('discard changes on relational data on new record', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2278,28 +2286,28 @@ QUnit.module('Views', {
});
// edit the p field
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.many2one.clickOpenDropdown('product_id');
- testUtils.fields.many2one.clickHighlightedItem('product_id');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
assert.strictEqual(form.$('.o_field_widget[name=product_id] input').val(), 'xphone',
"input should contain xphone");
// click on discard and confirm
- testUtils.form.clickDiscard(form);
- testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
+ await testUtils.form.clickDiscard(form);
+ await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
assert.notOk(form.$el.prop('outerHTML').match('xphone'),
"the string xphone should not be present after discarding");
form.destroy();
});
- QUnit.test('discard changes on a new (non dirty, except for defaults) form view', function (assert) {
+ QUnit.test('discard changes on a new (non dirty, except for defaults) form view', async function (assert) {
assert.expect(3);
this.data.partner.fields.foo.default = "ABC";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2315,7 +2323,7 @@ QUnit.module('Views', {
assert.strictEqual(form.$('input[name=foo]').val(), 'ABC',
"input should contain ABC");
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.containsNone(document.body, '.modal',
"there should not be a confirm modal");
@@ -2323,12 +2331,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('discard changes on a new (dirty) form view', function (assert) {
+ QUnit.test('discard changes on a new (dirty) form view', async function (assert) {
assert.expect(8);
this.data.partner.fields.foo.default = "ABC";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2346,35 +2354,30 @@ QUnit.module('Views', {
});
// edit the foo field
- assert.strictEqual(form.$('input[name=foo]').val(), 'ABC',
- "input should contain ABC");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'DEF');
+ assert.strictEqual(form.$('input').val(), 'ABC', 'input should contain ABC');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'DEF');
// discard the changes and check it has properly been discarded
- testUtils.form.clickDiscard(form);
- assert.containsOnce(document.body, '.modal', "there should be a confirm modal");
- assert.strictEqual(form.$('input[name=foo]').val(), 'DEF',
- "input should be DEF");
- testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
- assert.strictEqual(form.$('input[name=foo]').val(), 'ABC',
- "input should now be ABC");
+ await testUtils.form.clickDiscard(form);
+ assert.containsOnce(document.body, '.modal', 'there should be a confirm modal');
+ assert.strictEqual(form.$('input').val(), 'DEF', 'input should be DEF');
+ await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
+ assert.strictEqual(form.$('input').val(), 'ABC', 'input should now be ABC');
// redirty and discard the field foo (to make sure initial changes haven't been lost)
- testUtils.fields.editInput(form.$('input[name=foo]'), 'GHI');
- testUtils.form.clickDiscard(form);
- assert.strictEqual(form.$('input[name=foo]').val(), 'GHI',
- "input should be GHI");
- testUtils.dom.click('.modal-footer .btn-primary') // click on confirm
- assert.strictEqual(form.$('input[name=foo]').val(), 'ABC',
- "input should now be ABC");
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'GHI');
+ await testUtils.form.clickDiscard(form);
+ assert.strictEqual(form.$('input').val(), 'GHI', 'input should be GHI');
+ await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
+ assert.strictEqual(form.$('input').val(), 'ABC', 'input should now be ABC');
form.destroy();
});
- QUnit.test('discard changes on a duplicated record', function (assert) {
+ QUnit.test('discard changes on a duplicated record', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2382,28 +2385,27 @@ QUnit.module('Views', {
res_id: 1,
viewOptions: {hasSidebar: true},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.form.clickSave(form);
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
- assert.strictEqual(form.$('input[name=foo]').val(), 'tralala',
- "input should contain ABC");
+ assert.strictEqual(form.$('input[name=foo]').val(), 'tralala', 'input should contain ABC');
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.containsNone(document.body, '.modal', "there should not be a confirm modal");
form.destroy();
});
- QUnit.test('switching to another record from a dirty one', function (assert) {
+ QUnit.test("switching to another record from a dirty one", async function (assert) {
assert.expect(11);
var nbWrite = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2425,26 +2427,25 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_pager_limit').text(), '2', "pager limit should be 2");
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=foo]').val(), 'yop', "input should contain yop");
// edit the foo field
- testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
- assert.strictEqual(form.$('input[name=foo]').val(), 'new value',
- "input should contain new value");
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
+ assert.strictEqual(form.$('input').val(), 'new value', 'input should contain new value');
// click on the pager to switch to the next record and cancel the confirm request
- testUtils.dom.click('.o_pager_next'); // click on next
+ await testUtils.dom.click('.o_pager_next'); // click on next
assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed");
- testUtils.dom.click('.modal-footer .btn-secondary'); // click on cancel
+ await testUtils.dom.click('.modal-footer .btn-secondary'); // click on cancel
assert.strictEqual(form.$('input[name=foo]').val(), 'new value',
"input should still contain new value");
assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should still be 1");
// click on the pager to switch to the next record and confirm
- testUtils.dom.click('.o_pager_next'); // click on next
+ await testUtils.dom.click('.o_pager_next'); // click on next
assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed");
- testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
+ await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
assert.strictEqual(form.$('input[name=foo]').val(), 'blip', "input should contain blip");
assert.strictEqual(form.$('.o_pager_value').text(), '2', "pager value should be 2");
@@ -2452,10 +2453,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('handling dirty state: switching to another record', function (assert) {
+ QUnit.test('handling dirty state: switching to another record', async function (assert) {
assert.expect(12);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2472,18 +2473,18 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should be 1");
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=foo]').val(), 'yop', "input should contain yop");
// edit the foo field
- testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
assert.strictEqual(form.$('input[name=foo]').val(), 'new value',
"input should contain new value");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
// click on the pager to switch to the next record and cancel the confirm request
- testUtils.dom.click('.o_pager_next'); // click on next
+ await testUtils.dom.click('.o_pager_next'); // click on next
assert.containsNone(document.body, '.modal:visible',
"no confirm modal should be displayed");
assert.strictEqual(form.$('.o_pager_value').text(), '2', "pager value should be 2");
@@ -2492,35 +2493,35 @@ QUnit.module('Views', {
'priority widget should have been rendered with correct value');
// edit the value in readonly
- testUtils.dom.click(form.$('.o_priority .fa-star-o:first')); // click on the first star
+ await testUtils.dom.click(form.$('.o_priority .fa-star-o:first')); // click on the first star
assert.containsOnce(form, '.o_priority .fa-star',
'priority widget should have been updated');
- testUtils.dom.click('.o_pager_next'); // click on next
+ await testUtils.dom.click('.o_pager_next'); // click on next
assert.containsNone(document.body, '.modal:visible',
"no confirm modal should be displayed");
assert.strictEqual(form.$('.o_pager_value').text(), '1', "pager value should be 1");
// switch to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=foo]').val(), 'new value',
"input should contain yop");
// edit the foo field
- testUtils.fields.editInput(form.$('input[name=foo]'), 'wrong value');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'wrong value');
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickDiscard(form);
assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed");
- testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
- testUtils.dom.click('.o_pager_next'); // click on next
+ await testUtils.dom.click('.modal-footer .btn-primary'); // click on confirm
+ await testUtils.dom.click('.o_pager_next'); // click on next
assert.strictEqual(form.$('.o_pager_value').text(), '2', "pager value should be 2");
form.destroy();
});
- QUnit.test('restore local state when switching to another record', function (assert) {
+ QUnit.test('restore local state when switching to another record', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2542,23 +2543,23 @@ QUnit.module('Views', {
});
// click on second page tab
- testUtils.dom.click(form.$('.o_notebook .nav-link:eq(1)'));
+ await testUtils.dom.click(form.$('.o_notebook .nav-link:eq(1)'));
assert.doesNotHaveClass(form.$('.o_notebook .nav-link:eq(0)'), 'active');
assert.hasClass(form.$('.o_notebook .nav-link:eq(1)'), 'active');
// click on the pager to switch to the next record
- testUtils.dom.click('.o_pager_next');
+ await testUtils.dom.click('.o_pager_next');
assert.doesNotHaveClass(form.$('.o_notebook .nav-link:eq(0)'), 'active');
assert.hasClass(form.$('.o_notebook .nav-link:eq(1)'), 'active');
form.destroy();
});
- QUnit.test('pager is hidden in create mode', function (assert) {
+ QUnit.test('pager is hidden in create mode', async function (assert) {
assert.expect(7);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2578,10 +2579,10 @@ QUnit.module('Views', {
assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2",
"current pager limit should be 1");
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
assert.isNotVisible(form.pager);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.isVisible(form.pager);
assert.strictEqual(form.pager.$('.o_pager_value').text(), "3",
"current pager value should be 3");
@@ -2591,12 +2592,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('switching to another record, in readonly mode', function (assert) {
+ QUnit.test('switching to another record, in readonly mode', async function (assert) {
assert.expect(5);
var pushStateCount = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2615,7 +2616,7 @@ QUnit.module('Views', {
assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode');
assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1');
- testUtils.dom.click(form.pager.$('.o_pager_next'));
+ await testUtils.dom.click(form.pager.$('.o_pager_next'));
assert.strictEqual(form.pager.$('.o_pager_value').text(), "2", 'pager value should be 2');
assert.strictEqual(form.mode, 'readonly', 'form view should be in readonly mode');
@@ -2624,10 +2625,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('modifiers are reevaluated when creating new record', function (assert) {
+ QUnit.test('modifiers are reevaluated when creating new record', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2643,7 +2644,7 @@ QUnit.module('Views', {
assert.containsOnce(form, 'span.foo_field');
assert.isNotVisible(form.$('span.foo_field'));
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
assert.containsOnce(form, 'input.foo_field');
assert.isVisible(form.$('input.foo_field'));
@@ -2651,14 +2652,14 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('empty readonly fields are visible on new records', function (assert) {
+ QUnit.test('empty readonly fields are visible on new records', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.readonly = true;
this.data.partner.fields.foo.default = undefined;
this.data.partner.records[0].foo = undefined;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2672,16 +2673,16 @@ QUnit.module('Views', {
assert.containsOnce(form, '.o_field_empty');
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
assert.containsNone(form, '.o_field_empty');
form.destroy();
});
- QUnit.test('all group children have correct layout classname', function (assert) {
+ QUnit.test('all group children have correct layout classname', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2703,10 +2704,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('deleting a record', function (assert) {
+ QUnit.test('deleting a record', async function (assert) {
assert.expect(8);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2726,13 +2727,13 @@ QUnit.module('Views', {
assert.ok(!$('.modal:visible').length, 'no confirm modal should be displayed');
// open sidebar and delete
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
assert.ok($('.modal').length, 'a confirm modal should be displayed');
// confirm the delete
- testUtils.dom.click($('.modal-footer button.btn-primary'));
+ await testUtils.dom.click($('.modal-footer button.btn-primary'));
assert.strictEqual(form.pager.$('.o_pager_value').text(), "1", 'pager value should be 1');
assert.strictEqual(form.pager.$('.o_pager_limit').text(), "2", 'pager limit should be 2');
@@ -2741,10 +2742,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('deleting the last record', function (assert) {
+ QUnit.test('deleting the last record', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2762,27 +2763,27 @@ QUnit.module('Views', {
});
// open sidebar, click on delete and confirm
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
- testUtils.mock.intercept(form, 'history_back', function () {
+ await testUtils.mock.intercept(form, 'history_back', function () {
assert.step('history_back');
});
assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
- testUtils.dom.click($('.modal-footer button.btn-primary'));
+ await testUtils.dom.click($('.modal-footer button.btn-primary'));
assert.strictEqual($('.modal').length, 0, 'no confirm modal should be displayed');
assert.verifySteps(['read', 'unlink', 'history_back']);
form.destroy();
});
- QUnit.test('empty required fields cannot be saved', function (assert) {
+ QUnit.test('empty required fields cannot be saved', async function (assert) {
assert.expect(5);
this.data.partner.fields.foo.required = true;
delete this.data.partner.fields.foo.default;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2804,22 +2805,22 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.hasClass(form.$('label.o_form_label'),'o_field_invalid');
assert.hasClass(form.$('input[name=foo]'),'o_field_invalid');
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
assert.containsNone(form, '.o_field_invalid');
form.destroy();
});
- QUnit.test('changes in a readonly form view are saved directly', function (assert) {
+ QUnit.test('changes in a readonly form view are saved directly', async function (assert) {
assert.expect(10);
var nbWrite = 0;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2844,36 +2845,36 @@ QUnit.module('Views', {
'priority widget should have been rendered with correct value');
// edit the value in readonly
- testUtils.dom.click(form.$('.o_priority .fa-star-o:first'));
+ await testUtils.dom.click(form.$('.o_priority .fa-star-o:first'));
assert.strictEqual(nbWrite, 1, 'should have saved directly');
assert.containsOnce(form, '.o_priority .fa-star',
'priority widget should have been updated');
// switch to edit mode and edit the value again
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsN(form, '.o_priority .o_priority_star', 2,
'priority widget should have been correctly rendered');
assert.containsOnce(form, '.o_priority .fa-star',
'priority widget should have correct value');
- testUtils.dom.click(form.$('.o_priority .fa-star-o:first'));
+ await testUtils.dom.click(form.$('.o_priority .fa-star-o:first'));
assert.strictEqual(nbWrite, 1, 'should not have saved directly');
assert.containsN(form, '.o_priority .fa-star', 2,
'priority widget should have been updated');
// save
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(nbWrite, 2, 'should not have saved directly');
assert.containsN(form, '.o_priority .fa-star', 2,
'priority widget should have correct value');
form.destroy();
});
- QUnit.test('display a dialog if onchange result is a warning', function (assert) {
+ QUnit.test('display a dialog if onchange result is a warning', async function (assert) {
assert.expect(5);
this.data.partner.onchanges = { foo: true };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2883,7 +2884,7 @@ QUnit.module('Views', {
res_id: 2,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: { int_field: 10 },
warning: {
title: "Warning",
@@ -2905,23 +2906,23 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name=int_field]').val(), '9');
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
assert.strictEqual(form.$('input[name=int_field]').val(), '10');
form.destroy();
});
- QUnit.test('can create record even if onchange returns a warning', function (assert) {
+ QUnit.test('can create record even if onchange returns a warning', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = { foo: true };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2930,7 +2931,7 @@ QUnit.module('Views', {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: { int_field: 10 },
warning: {
title: "Warning",
@@ -2942,7 +2943,7 @@ QUnit.module('Views', {
},
intercepts: {
warning: function (event) {
- assert.step('warning');
+ assert.ok(true, 'should trigger a warning');
},
},
});
@@ -2952,12 +2953,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('do nothing if add a line in one2many result in a onchange with a warning', function (assert) {
- assert.expect(2);
+ QUnit.test('do nothing if add a line in one2many result in a onchange with a warning', async function (assert) {
+ assert.expect(3);
this.data.partner.onchanges = { foo: true };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -2971,7 +2972,7 @@ QUnit.module('Views', {
res_id: 2,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {},
warning: {
title: "Warning",
@@ -2989,19 +2990,20 @@ QUnit.module('Views', {
});
// go to edit mode, click to add a record in the o2m
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.containsNone(form, 'tr.o_data_row',
"should not have added a line");
+ assert.verifySteps(["should have triggered a warning"]);
form.destroy();
});
- QUnit.test('default_get, onchange which fails, should still work', function (assert) {
+ QUnit.test('default_get, onchange which fails, should still work', async function (assert) {
assert.expect(1);
this.data.partner.onchanges.foo = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3013,8 +3015,8 @@ QUnit.module('Views', {
// we simulate a validation error. In the 'real' web client,
// the server error will be used by the session to display
// an error dialog. From the point of view of the basic
- // model, the deferred is just rejected.
- return $.Deferred().reject();
+ // model, the promise is just rejected.
+ return Promise.reject();
}
return this._super.apply(this, arguments);
},
@@ -3034,7 +3036,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('attrs are properly transmitted to new records', function (assert) {
+ QUnit.test('attrs are properly transmitted to new records', async function (assert) {
assert.expect(2);
// this test checks that the fieldsInfo have been transmitted to the
@@ -3046,7 +3048,7 @@ QUnit.module('Views', {
string_false: "Test Environment",
hover_false: "Switch to production environment"
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3062,7 +3064,7 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_stat_text.o_not_hover:contains(Production Environment)').length, 1,
"button should contain correct string");
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickCreate(form);
assert.strictEqual(form.$('.o_stat_text.o_not_hover:contains(Test Environment)').length, 1,
"button should contain correct string");
@@ -3070,10 +3072,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('button box is rendered in create mode', function (assert) {
+ QUnit.test('button box is rendered in create mode', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3092,21 +3094,21 @@ QUnit.module('Views', {
"button box should be displayed in readonly");
// edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, '.oe_stat_button',
"button box should be displayed in edit on an existing record");
// create mode (leave edition first!)
- testUtils.form.clickDiscard(form);
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickDiscard(form);
+ await testUtils.form.clickCreate(form);
assert.containsOnce(form, '.oe_stat_button',
"button box should be displayed when creating a new record as well");
form.destroy();
});
- QUnit.test('properly apply onchange on one2many fields', function (assert) {
+ QUnit.test('properly apply onchange on one2many fields', async function (assert) {
assert.expect(5);
this.data.partner.records[0].p = [4];
@@ -3119,7 +3121,7 @@ QUnit.module('Views', {
];
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3140,8 +3142,8 @@ QUnit.module('Views', {
"the 'display_name' of the one2many record should be correct");
// switch to edit mode
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'let us trigger an onchange');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'let us trigger an onchange');
var $o2m = form.$('.o_field_one2many');
assert.strictEqual($o2m.find('.o_data_row').length, 2,
"there should be two linked record");
@@ -3153,7 +3155,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('update many2many value in one2many after onchange', function (assert) {
+ QUnit.test('update many2many value in one2many after onchange', async function (assert) {
assert.expect(2);
this.data.partner.records[1].p = [4];
@@ -3168,7 +3170,7 @@ QUnit.module('Views', {
];
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3185,21 +3187,21 @@ QUnit.module('Views', {
});
assert.strictEqual($('div[name="p"] .o_data_row td').text().trim(), "aaaNo records",
"should have proper initial content");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'tralala');
assert.strictEqual($('div[name="p"] .o_data_row td').text().trim(), "goldNo records",
"should have proper initial content");
form.destroy();
});
- QUnit.test('delete a line in a one2many while editing another line triggers a warning', function (assert) {
+ QUnit.test('delete a line in a one2many while editing another line triggers a warning', async function (assert) {
assert.expect(3);
this.data.partner.records[0].p = [1, 2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3213,15 +3215,15 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_data_cell').first());
- testUtils.fields.editInput(form.$('input[name=display_name]'), '');
- testUtils.dom.click(form.$('.fa-trash-o').eq(1));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_data_cell').first());
+ await testUtils.fields.editInput(form.$('input[name=display_name]'), '');
+ await testUtils.dom.click(form.$('.fa-trash-o').eq(1));
assert.strictEqual($('.modal').find('.modal-title').first().text(), "Warning",
"Clicking out of a dirty line while editing should trigger a warning modal.");
- testUtils.dom.click($('.modal').find('.btn-primary'));
+ await testUtils.dom.click($('.modal').find('.btn-primary'));
assert.strictEqual(form.$('.o_data_cell').first().text(), "first record",
"Value should have been reset to what it was before editing began.");
@@ -3230,7 +3232,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('properly apply onchange on many2many fields', function (assert) {
+ QUnit.test('properly apply onchange on many2many fields', async function (assert) {
assert.expect(14);
this.data.partner.onchanges = {
@@ -3242,7 +3244,7 @@ QUnit.module('Views', {
];
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3274,8 +3276,8 @@ QUnit.module('Views', {
"there should be no many2many record linked at first");
// switch to edit mode
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'let us trigger an onchange');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'let us trigger an onchange');
var $m2m = form.$('.o_field_many2many');
assert.strictEqual($m2m.find('.o_data_row').length, 2,
"there should be two linked records");
@@ -3284,14 +3286,14 @@ QUnit.module('Views', {
assert.strictEqual($m2m.find('.o_data_row:nth(1) td:first').text(), 'silver',
"the 'display_name' of the second m2m record should be correctly displayed");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps(['read', 'onchange', 'read', 'write', 'read', 'read']);
form.destroy();
});
- QUnit.test('display_name not sent for onchanges if not in view', function (assert) {
+ QUnit.test('display_name not sent for onchanges if not in view', async function (assert) {
assert.expect(7);
this.data.partner.records[0].timmy = [12];
@@ -3302,7 +3304,7 @@ QUnit.module('Views', {
name: function () {},
};
var readInModal = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3367,17 +3369,17 @@ QUnit.module('Views', {
});
// trigger the onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), "coucou");
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), "coucou");
// open a subrecord and trigger an onchange
readInModal = true;
- testUtils.dom.click(form.$('.o_data_row .o_data_cell:first'));
- testUtils.fields.editInput($('.modal .o_field_widget[name=name]'), "new name");
+ await testUtils.dom.click(form.$('.o_data_row .o_data_cell:first'));
+ await testUtils.fields.editInput($('.modal .o_field_widget[name=name]'), "new name");
form.destroy();
});
- QUnit.test('onchanges on date(time) fields', function (assert) {
+ QUnit.test('onchanges on date(time) fields', async function (assert) {
assert.expect(6);
this.data.partner.onchanges = {
@@ -3386,7 +3388,7 @@ QUnit.module('Views', {
obj.datetime = '2021-12-12 10:55:05';
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3410,7 +3412,7 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_field_widget[name=datetime]').text(),
'12/12/2016 12:55:05', "the initial datetime should be correct");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_field_widget[name=date] input').val(),
'01/25/2017', "the initial date should be correct in edit");
@@ -3418,7 +3420,7 @@ QUnit.module('Views', {
'12/12/2016 12:55:05', "the initial datetime should be correct in edit");
// trigger the onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name="foo"]'), "coucou");
+ await testUtils.fields.editInput(form.$('.o_field_widget[name="foo"]'), "coucou");
assert.strictEqual(form.$('.o_field_widget[name=date] input').val(),
'12/12/2021', "the initial date should be correct in edit");
@@ -3428,7 +3430,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('onchanges are not sent for each keystrokes', function (assert) {
+ QUnit.test('onchanges are not sent for each keystrokes', async function (assert) {
var done = assert.async();
assert.expect(5);
@@ -3439,8 +3441,8 @@ QUnit.module('Views', {
obj.int_field = obj.foo.length + 1000;
},
};
- var def = $.Deferred();
- var form = createView({
+ var def = testUtils.makeTestPromise();
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3462,19 +3464,18 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
testUtils.fields.editInput(form.$('input[name=foo]'), '1');
assert.strictEqual(onchangeNbr, 0, "no onchange has been called yet");
testUtils.fields.editInput(form.$('input[name=foo]'), '12');
assert.strictEqual(onchangeNbr, 0, "no onchange has been called yet");
- return waitForFinishedOnChange().then(function () {
+ return waitForFinishedOnChange().then(async function () {
assert.strictEqual(onchangeNbr, 1, "one onchange has been called");
// add something in the input, then focus another input
- testUtils.fields.editInput(form.$('input[name=foo]'), '123');
- form.$('input[name=foo]').change();
+ await testUtils.fields.editAndTrigger(form.$('input[name=foo]'), '123', ['change']);
assert.strictEqual(onchangeNbr, 2, "one onchange has been called immediately");
return waitForFinishedOnChange();
@@ -3487,13 +3488,13 @@ QUnit.module('Views', {
function waitForFinishedOnChange() {
return def.then(function () {
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
return concurrency.delay(0);
});
}
});
- QUnit.test('onchanges are not sent for invalid values', function (assert) {
+ QUnit.test('onchanges are not sent for invalid values', async function (assert) {
assert.expect(6);
this.data.partner.onchanges = {
@@ -3501,7 +3502,7 @@ QUnit.module('Views', {
obj.foo = String(obj.int_field);
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3515,21 +3516,21 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// edit int_field, and check that an onchange has been applied
- testUtils.fields.editInput(form.$('input[name="int_field"]'), "123");
+ await testUtils.fields.editInput(form.$('input[name="int_field"]'), "123");
assert.strictEqual(form.$('input[name="foo"]').val(), "123",
"the onchange has been applied");
// enter an invalid value in a float, and check that no onchange has
// been applied
- testUtils.fields.editInput(form.$('input[name="int_field"]'), "123a");
+ await testUtils.fields.editInput(form.$('input[name="int_field"]'), "123a");
assert.strictEqual(form.$('input[name="foo"]').val(), "123",
"the onchange has not been applied");
// save, and check that the int_field input is marked as invalid
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.hasClass(form.$('input[name="int_field"]'),'o_field_invalid',
"input int_field is marked as invalid");
@@ -3537,10 +3538,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('rpc complete after destroying parent', function (assert) {
+ QUnit.test('rpc complete after destroying parent', async function (assert) {
// We just test that there is no crash in this situation
assert.expect(0);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3555,20 +3556,20 @@ QUnit.module('Views', {
}
}
});
- testUtils.dom.click(form.$('.o_form_button_update'));
+ await testUtils.dom.click(form.$('.o_form_button_update'));
});
- QUnit.test('onchanges that complete after discarding', function (assert) {
- assert.expect(4);
+ QUnit.test('onchanges that complete after discarding', async function (assert) {
+ assert.expect(5);
- var def1 = $.Deferred();
+ var def1 = testUtils.makeTestPromise();
this.data.partner.onchanges = {
foo: function (obj) {
obj.int_field = obj.foo.length + 1000;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3591,31 +3592,33 @@ QUnit.module('Views', {
// go into edit mode
assert.strictEqual(form.$('span[name="foo"]').text(), "blip",
"field foo should be displayed to initial value");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// edit a value
- testUtils.fields.editInput(form.$('input[name=foo]'), '1234');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), '1234');
// discard changes
- testUtils.form.clickDiscard(form);
- testUtils.dom.click($('.modal-footer .btn-primary'));
+ await testUtils.form.clickDiscard(form);
+ await testUtils.dom.click($('.modal-footer .btn-primary'));
assert.strictEqual(form.$('span[name="foo"]').text(), "blip",
"field foo should still be displayed to initial value");
// complete the onchange
def1.resolve();
+ await testUtils.nextTick();
assert.strictEqual(form.$('span[name="foo"]').text(), "blip",
"field foo should still be displayed to initial value");
+ assert.verifySteps(['onchange is done']);
form.destroy();
});
- QUnit.test('discarding before save returns', function (assert) {
+ QUnit.test('discarding before save returns', async function (assert) {
assert.expect(4);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3635,10 +3638,10 @@ QUnit.module('Views', {
},
});
- testUtils.fields.editInput(form.$('input[name=foo]'), '1234');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), '1234');
// save the value and discard directly
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.discardChanges(); // Simulate click on breadcrumb
assert.strictEqual(form.$('.o_field_widget[name="foo"]').val(), "1234",
@@ -3648,7 +3651,7 @@ QUnit.module('Views', {
// complete the write
def.resolve();
-
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 0,
"Confirm dialog should not be displayed");
assert.strictEqual(form.$('.o_field_widget[name="foo"]').text(), "1234",
@@ -3657,7 +3660,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('unchanged relational data is sent for onchanges', function (assert) {
+ QUnit.test('unchanged relational data is sent for onchanges', async function (assert) {
assert.expect(1);
this.data.partner.records[1].p = [4];
@@ -3666,7 +3669,7 @@ QUnit.module('Views', {
obj.int_field = obj.foo.length + 1000;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3692,13 +3695,13 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger an onchange');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger an onchange');
form.destroy();
});
- QUnit.test('onchanges on unknown fields of o2m are ignored', function (assert) {
+ QUnit.test('onchanges on unknown fields of o2m are ignored', async function (assert) {
// many2one fields need to be postprocessed (the onchange returns [id,
// display_name]), but if we don't know the field, we can't know it's a
// many2one, so it isn't ignored, its value is an array instead of a
@@ -3709,7 +3712,7 @@ QUnit.module('Views', {
this.data.partner.onchanges = {
foo: function () {},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3732,7 +3735,7 @@ QUnit.module('Views', {
res_id: 2,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
p: [
[5],
@@ -3753,25 +3756,25 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger an onchange');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger an onchange');
assert.strictEqual(form.$('.o_data_row td:first').text(), 'foo changed',
"onchange should have been correctly applied on field in o2m list");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('onchange value are not discarded on o2m edition', function (assert) {
+ QUnit.test('onchange value are not discarded on o2m edition', async function (assert) {
assert.expect(4);
this.data.partner.records[1].p = [4];
this.data.partner.onchanges = {
foo: function () {},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3794,7 +3797,7 @@ QUnit.module('Views', {
res_id: 2,
mockRPC: function (route, args) {
if (args.method === 'onchange') {
- return $.when({
+ return Promise.resolve({
value: {
p: [[5], [1, 4, {foo: 'foo changed'}]],
},
@@ -3809,17 +3812,17 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_data_row td:first').text(), 'My little Foo Value',
"the initial value should be the default one");
- testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger an onchange');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'trigger an onchange');
assert.strictEqual(form.$('.o_data_row td:first').text(), 'foo changed',
"onchange should have been correctly applied on field in o2m list");
- testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
assert.strictEqual($('.modal .modal-title').text().trim(), 'Open: one2many field',
"the field string is displayed in the modal title");
assert.strictEqual($('.modal .o_field_widget').val(), 'foo changed',
@@ -3828,7 +3831,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('args of onchanges in o2m fields are correct (inline edition)', function (assert) {
+ QUnit.test('args of onchanges in o2m fields are correct (inline edition)', async function (assert) {
assert.expect(3);
this.data.partner.records[1].p = [4];
@@ -3839,7 +3842,7 @@ QUnit.module('Views', {
obj.foo = '[' + obj.rel_field.foo + '] ' + obj.int_field;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3857,26 +3860,26 @@ QUnit.module('Views', {
res_id: 2,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_data_row td:first').text(), 'My little Foo Value',
"the initial value should be the default one");
- testUtils.dom.click(form.$('.o_data_row td:nth(1)'));
- testUtils.fields.editInput(form.$('.o_data_row input:nth(1)'), 77);
+ await testUtils.dom.click(form.$('.o_data_row td:nth(1)'));
+ await testUtils.fields.editInput(form.$('.o_data_row input:nth(1)'), 77);
assert.strictEqual(form.$('.o_data_row input:first').val(), '[blip] 77',
"onchange should have been correctly applied");
// create a new o2m record
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('.o_data_row input:first').val(), '[blip] 14',
"onchange should have been correctly applied after default get");
form.destroy();
});
- QUnit.test('args of onchanges in o2m fields are correct (dialog edition)', function (assert) {
+ QUnit.test('args of onchanges in o2m fields are correct (dialog edition)', async function (assert) {
assert.expect(6);
this.data.partner.records[1].p = [4];
@@ -3887,7 +3890,7 @@ QUnit.module('Views', {
obj.foo = '[' + obj.rel_field.foo + '] ' + obj.int_field;
},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3908,39 +3911,41 @@ QUnit.module('Views', {
res_id: 2,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('.o_data_row td:first').text(), 'My little Foo Value',
"the initial value should be the default one");
- testUtils.dom.click(form.$('.o_data_row td:first'));
- testUtils.fields.editInput($('.modal input:nth(1)'), 77);
+ await testUtils.dom.click(form.$('.o_data_row td:first'));
+ await testUtils.nextTick();
+ await testUtils.fields.editInput($('.modal input:nth(1)'), 77);
assert.strictEqual($('.modal input:first').val(), '[blip] 77',
"onchange should have been correctly applied");
- testUtils.dom.click($('.modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_data_row td:first').text(), '[blip] 77',
"onchange should have been correctly applied");
// create a new o2m record
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal .modal-title').text().trim(), 'Create custom label',
"the custom field label is applied in the modal title");
assert.strictEqual($('.modal input:first').val(), '[blip] 14',
"onchange should have been correctly applied after default get");
- testUtils.dom.clickFirst($('.modal-footer .btn-primary'));
+ await testUtils.dom.clickFirst($('.modal-footer .btn-primary'));
+ await testUtils.nextTick();
assert.strictEqual(form.$('.o_data_row:nth(1) td:first').text(), '[blip] 14',
"onchange should have been correctly applied after default get");
form.destroy();
});
- QUnit.test('context of onchanges contains the context of changed fields', function (assert) {
+ QUnit.test('context of onchanges contains the context of changed fields', async function (assert) {
assert.expect(2);
this.data.partner.onchanges = {
foo: function () {},
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3962,16 +3967,16 @@ QUnit.module('Views', {
res_id: 2,
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name=foo]'), 'coucou');
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'coucou');
form.destroy();
});
- QUnit.test('navigation with tab key in form view', function (assert) {
+ QUnit.test('navigation with tab key in form view', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -3988,7 +3993,7 @@ QUnit.module('Views', {
});
// go to edit mode
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// focus first input, trigger tab
form.$('input[name="foo"]').focus();
@@ -4010,12 +4015,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('navigation with tab key in readonly form view', function (assert) {
+ QUnit.test('navigation with tab key in readonly form view', async function (assert) {
assert.expect(3);
this.data.partner.records[1].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4055,12 +4060,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('skip invisible fields when navigating with TAB', function (assert) {
+ QUnit.test('skip invisible fields when navigating with TAB', async function (assert) {
assert.expect(1);
this.data.partner.records[0].bar = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4075,7 +4080,7 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
form.$('input[name="foo"]').focus();
form.$('input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
assert.strictEqual(form.$('input[name="int_field"]')[0], document.activeElement,
@@ -4084,10 +4089,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('clicking on a stat button with a context', function (assert) {
+ QUnit.test('clicking on a stat button with a context', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4114,15 +4119,15 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.oe_stat_button'));
+ await testUtils.dom.click(form.$('.oe_stat_button'));
form.destroy();
});
- QUnit.test('clicking on a stat button with no context', function (assert) {
+ QUnit.test('clicking on a stat button with no context', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4148,15 +4153,15 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.oe_stat_button'));
+ await testUtils.dom.click(form.$('.oe_stat_button'));
form.destroy();
});
- QUnit.test('diplay a stat button outside a buttonbox', function (assert) {
+ QUnit.test('diplay a stat button outside a buttonbox', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4180,10 +4185,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('diplay something else than a button in a buttonbox', function (assert) {
+ QUnit.test('diplay something else than a button in a buttonbox', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4208,10 +4213,41 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('display correctly buttonbox, in large size class', function (assert) {
+ QUnit.test('invisible fields are not considered as visible in a buttonbox', async function (assert) {
+ assert.expect(2);
+
+ var form = await createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch: '<form>' +
+ '<div name="button_box" class="oe_button_box">' +
+ '<field name="foo" invisible="1"/>' +
+ '<field name="bar" invisible="1"/>' +
+ '<field name="int_field" invisible="1"/>' +
+ '<field name="qux" invisible="1"/>' +
+ '<field name="display_name" invisible="1"/>' +
+ '<field name="state" invisible="1"/>' +
+ '<field name="date" invisible="1"/>' +
+ '<field name="datetime" invisible="1"/>' +
+ '<button type="object" class="oe_stat_button" icon="fa-check-square"/>' +
+ '</div>' +
+ '</form>',
+ res_id: 2,
+ });
+
+ assert.strictEqual(form.$('.oe_button_box').children().length, 9,
+ "button box should contain nine children");
+ assert.hasClass(form.$('.oe_button_box'), 'o_not_full',
+ "the buttonbox should not be full (only 1 visible child)");
+
+ form.destroy();
+ });
+
+ QUnit.test('display correctly buttonbox, in large size class', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4237,12 +4273,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('one2many default value creation', function (assert) {
+ QUnit.test('one2many default value creation', async function (assert) {
assert.expect(1);
this.data.partner.records[0].product_ids = [37];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4259,7 +4295,7 @@ QUnit.module('Views', {
'</form>',
mockRPC: function (route, args) {
if (args.method === 'default_get') {
- return $.when({
+ return Promise.resolve({
product_ids: [[0, 0, {
name: 'xdroid',
partner_type_id: 12,
@@ -4274,14 +4310,14 @@ QUnit.module('Views', {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('many2manys inside one2manys are saved correctly', function (assert) {
+ QUnit.test('many2manys inside one2manys are saved correctly', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4306,19 +4342,19 @@ QUnit.module('Views', {
});
// add a o2m subrecord with a m2m tag
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.many2one.clickOpenDropdown('timmy');
- testUtils.fields.many2one.clickHighlightedItem('timmy');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.many2one.clickOpenDropdown('timmy');
+ await testUtils.fields.many2one.clickHighlightedItem('timmy');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('one2manys (list editable) inside one2manys are saved correctly', function (assert) {
+ QUnit.test('one2manys (list editable) inside one2manys are saved correctly', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4353,10 +4389,10 @@ QUnit.module('Views', {
});
// add a o2m subrecord
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click($('.modal-body .o_field_one2many .o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($('.modal-body input'), 'xtv');
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($('.modal-body .o_field_one2many .o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($('.modal-body input'), 'xtv');
+ await testUtils.dom.click($('.modal-footer button:first'));
assert.strictEqual($('.modal').length, 0,
"dialog should be closed");
@@ -4364,16 +4400,16 @@ QUnit.module('Views', {
assert.strictEqual(row.children()[0].textContent, '1 record',
"the cell should contains the number of record: 1");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('*_view_ref in context are passed correctly', function (assert) {
+ QUnit.test('*_view_ref in context are passed correctly', async function (assert) {
var done = assert.async();
assert.expect(3);
- createAsyncView({
+ createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4401,15 +4437,15 @@ QUnit.module('Views', {
}
return this._super.apply(this, arguments);
},
- }).then(function (form) {
+ }).then(async function (form) {
// reload to check that the record's context hasn't been modified
- form.reload();
+ await form.reload();
form.destroy();
done();
});
});
- QUnit.test('readonly fields with modifiers may be saved', function (assert) {
+ QUnit.test('readonly fields with modifiers may be saved', async function (assert) {
// the readonly property on the field description only applies on view,
// this is not a DB constraint. It should be seen as a default value,
// that may be overriden in views, for example with modifiers. So
@@ -4417,7 +4453,7 @@ QUnit.module('Views', {
assert.expect(3);
this.data.partner.fields.foo.readonly = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4439,13 +4475,13 @@ QUnit.module('Views', {
// bar being set to true, foo shouldn't be readonly and thus its value
// could be saved, even if in its field description it is readonly
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.containsOnce(form, 'input[name="foo"]',
"foo field should be editable");
- testUtils.fields.editInput(form.$('input[name="foo"]'), 'New foo value');
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), 'New foo value');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.strictEqual(form.$('.o_field_widget[name=foo]').text(), 'New foo value',
"new value for foo field should have been saved");
@@ -4453,10 +4489,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('check if id and active_id are defined', function (assert) {
+ QUnit.test('check if id and active_id are defined', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4474,8 +4510,8 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === 'default_get' && args.args[0][0] === 'trululu') {
- assert.strictEqual(args.kwargs.context.current_id, false,
- "current_id should be false");
+ assert.strictEqual(args.kwargs.context.current_id, false,
+ "current_id should be false");
assert.strictEqual(args.kwargs.context.default_trululu, false,
"default_trululu should be false");
}
@@ -4483,14 +4519,14 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
form.destroy();
});
- QUnit.test('modifiers are considered on multiple <footer/> tags', function (assert) {
+ QUnit.test('modifiers are considered on multiple <footer/> tags', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4515,7 +4551,7 @@ QUnit.module('Views', {
assert.deepEqual(getVisibleButtonTexts(), ["Hello", "World"],
"only the first button section should be visible");
- testUtils.dom.click(form.$(".o_field_boolean input"));
+ await testUtils.dom.click(form.$(".o_field_boolean input"));
assert.deepEqual(getVisibleButtonTexts(), ["Foo"],
"only the second button section should be visible");
@@ -4530,10 +4566,10 @@ QUnit.module('Views', {
}
});
- QUnit.test('buttons in footer are moved to $buttons if necessary', function (assert) {
+ QUnit.test('buttons in footer are moved to $buttons if necessary', async function (assert) {
assert.expect(4);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4551,7 +4587,7 @@ QUnit.module('Views', {
assert.containsNone(form.$('.o_form_view'), 'button.infooter');
// check that this still works after a reload
- testUtils.form.reload(form);
+ await testUtils.form.reload(form);
assert.containsOnce(form.$('.o_control_panel'), 'button.infooter');
assert.containsNone(form.$('.o_form_view'), 'button.infooter');
@@ -4559,10 +4595,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('render stat button with string inline', function (assert) {
+ QUnit.test('render stat button with string inline', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 1,
@@ -4581,11 +4617,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('renderer waits for asynchronous fields rendering', function (assert) {
+ QUnit.test('renderer waits for asynchronous fields rendering', async function (assert) {
assert.expect(1);
var done = assert.async();
- testUtils.createAsyncView({
+ testUtils.createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4603,7 +4639,7 @@ QUnit.module('Views', {
});
});
- QUnit.test('open one2many form containing one2many', function (assert) {
+ QUnit.test('open one2many form containing one2many', async function (assert) {
assert.expect(9);
this.data.partner.records[0].product_ids = [37];
@@ -4612,7 +4648,7 @@ QUnit.module('Views', {
};
this.data.product.records[0].partner_type_ids = [12];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 1,
@@ -4652,7 +4688,7 @@ QUnit.module('Views', {
var row = form.$('.o_field_one2many .o_list_view .o_data_row');
assert.strictEqual(row.children()[1].textContent, '1 record',
"the cell should contains the number of record: 1");
- testUtils.dom.click(row);
+ await testUtils.dom.click(row);
var modal_row = $('.modal-body .o_form_sheet .o_field_one2many .o_list_view .o_data_row');
assert.strictEqual(modal_row.children().length, 2,
"the row should contains the 2 fields defined in the form view");
@@ -4663,10 +4699,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('in edit mode, first field is focused', function (assert) {
+ QUnit.test('in edit mode, first field is focused', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4676,7 +4712,7 @@ QUnit.module('Views', {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0],
"foo field should have focus");
@@ -4686,10 +4722,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('autofocus fields are focused', function (assert) {
+ QUnit.test('autofocus fields are focused', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4699,17 +4735,17 @@ QUnit.module('Views', {
'</form>',
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0],
"foo field should have focus");
form.destroy();
});
- QUnit.test('in create mode, autofocus fields are focused', function (assert) {
+ QUnit.test('in create mode, autofocus fields are focused', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4724,9 +4760,9 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('create with false values', function (assert) {
+ QUnit.test('create with false values', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4742,15 +4778,15 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('autofocus first visible field', function (assert) {
+ QUnit.test('autofocus first visible field', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4765,10 +4801,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('no autofocus with disable_autofocus option [REQUIRE FOCUS]', function (assert) {
+ QUnit.test('no autofocus with disable_autofocus option [REQUIRE FOCUS]', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4783,7 +4819,7 @@ QUnit.module('Views', {
assert.notStrictEqual(document.activeElement, form.$('input[name="int_field"]')[0],
"int_field field should not have focus");
- form.update({});
+ await form.update({});
assert.notStrictEqual(document.activeElement, form.$('input[name="int_field"]')[0],
"int_field field should not have focus");
@@ -4791,7 +4827,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('open one2many form containing many2many_tags', function (assert) {
+ QUnit.test('open one2many form containing many2many_tags', async function (assert) {
assert.expect(4);
this.data.partner.records[0].product_ids = [37];
@@ -4800,7 +4836,7 @@ QUnit.module('Views', {
};
this.data.product.records[0].partner_type_ids = [12, 14];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 1,
@@ -4833,21 +4869,21 @@ QUnit.module('Views', {
},
});
var row = form.$('.o_field_one2many .o_list_view .o_data_row');
- testUtils.dom.click(row);
+ await testUtils.dom.click(row);
assert.verifySteps(['read', 'read', 'read'],
"there should be 3 read rpcs");
form.destroy();
});
- QUnit.test('onchanges are applied before checking if it can be saved', function (assert) {
+ QUnit.test('onchanges are applied before checking if it can be saved', async function (assert) {
assert.expect(4);
this.data.partner.onchanges.foo = function (obj) {};
this.data.partner.fields.foo.required = true;
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4876,20 +4912,21 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name="foo"]'), '');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), '');
+ await testUtils.form.clickSave(form);
def.resolve();
+ await testUtils.nextTick();
assert.verifySteps(['read', 'onchange', 'warning']);
form.destroy();
});
- QUnit.test('display toolbar', function (assert) {
+ QUnit.test('display toolbar', async function (assert) {
assert.expect(8);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -4915,7 +4952,7 @@ QUnit.module('Views', {
"the active_id shoud be 1.");
assert.deepEqual(args.context.active_ids, [1],
"the active_ids should be an array with 1 inside.");
- return $.when({});
+ return Promise.resolve({});
}
return this._super.apply(this, arguments);
},
@@ -4932,19 +4969,19 @@ QUnit.module('Views', {
var $customAction = $actionMenu.find('.dropdown-item:last');
assert.strictEqual($customAction.text().trim(), 'Action partner',
"the custom action should have 'Action partner' as name");
- testUtils.mock.intercept(form, 'do_action', function (event) {
+ await testUtils.mock.intercept(form, 'do_action', function (event) {
var context = event.data.action.context.__contexts[1];
assert.strictEqual(context.active_id, 1,
"the active_id shoud be 1.");
assert.deepEqual(context.active_ids, [1],
"the active_ids should be an array with 1 inside.");
});
- testUtils.dom.click($customAction);
+ await testUtils.dom.click($customAction);
form.destroy();
});
- QUnit.test('check interactions between multiple FormViewDialogs', function (assert) {
+ QUnit.test('check interactions between multiple FormViewDialogs', async function (assert) {
assert.expect(8);
this.data.product.fields.product_ids = {
@@ -4953,7 +4990,7 @@ QUnit.module('Views', {
this.data.partner.records[0].product_id = 37;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 1,
@@ -4979,7 +5016,7 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
} else if (args.method === 'write') {
assert.strictEqual(args.model, 'product',
"should write on product model");
@@ -4990,9 +5027,9 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
// Open first dialog
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
assert.strictEqual($('.modal').length, 1,
"One FormViewDialog should be opened");
var $firstModal = $('.modal');
@@ -5002,27 +5039,27 @@ QUnit.module('Views', {
"display_name should be correctly displayed");
// Open second dialog
- testUtils.dom.click($firstModal.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($firstModal.find('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal').length, 2,
"two FormViewDialogs should be opened");
var $secondModal = $('.modal:nth(1)');
// Add new value
- testUtils.fields.editInput($secondModal.find('input'), 'xtv');
- testUtils.dom.click($secondModal.find('.modal-footer button:first'));
+ await testUtils.fields.editInput($secondModal.find('input'), 'xtv');
+ await testUtils.dom.click($secondModal.find('.modal-footer button:first'));
assert.strictEqual($('.modal').length, 1,
"last opened dialog should be closed");
// Check that data in first dialog is correctly updated
assert.strictEqual($firstModal.find('tr.o_data_row td').text(), 'xtv',
"should have added a line with xtv as new record");
- testUtils.dom.click($firstModal.find('.modal-footer button:first'));
+ await testUtils.dom.click($firstModal.find('.modal-footer button:first'));
form.destroy();
});
- QUnit.test('fields and record contexts are not mixed', function (assert) {
+ QUnit.test('fields and record contexts are not mixed', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5047,15 +5084,15 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=trululu] input'));
form.destroy();
});
- QUnit.test('do not activate an hidden tab when switching between records', function (assert) {
+ QUnit.test('do not activate an hidden tab when switching between records', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5084,14 +5121,14 @@ QUnit.module('Views', {
"first tab should be active");
// click on the pager to switch to the next record
- testUtils.dom.click(form.pager.$('.o_pager_next'));
+ await testUtils.dom.click(form.pager.$('.o_pager_next'));
assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 1,
"only the second tab should be visible");
assert.hasClass(form.$('.o_notebook .nav-item:not(.o_invisible_modifier) .nav-link'),'active',
"the visible tab should be active");
// click on the pager to switch back to the previous record
- testUtils.dom.click(form.pager.$('.o_pager_previous'));
+ await testUtils.dom.click(form.pager.$('.o_pager_previous'));
assert.strictEqual(form.$('.o_notebook .nav-item:not(.o_invisible_modifier)').length, 2,
"both tabs should be visible again");
assert.hasClass(form.$('.o_notebook .nav-link:nth(1)'),'active',
@@ -5100,16 +5137,16 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('support anchor tags with action type', function (assert) {
+ QUnit.test('support anchor tags with action type', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
arch: '<form string="Partners">' +
'<a type="action" name="42"><i class="fa fa-arrow-right"/> Click me !</a>' +
- '</form>',
+ '</form>',
res_id: 1,
intercepts: {
do_action: function (event) {
@@ -5118,17 +5155,17 @@ QUnit.module('Views', {
}
}
});
- testUtils.dom.click(form.$('a[type="action"]'));
+ await testUtils.dom.click(form.$('a[type="action"]'));
form.destroy();
});
- QUnit.test('do not perform extra RPC to read invisible many2one fields', function (assert) {
+ QUnit.test('do not perform extra RPC to read invisible many2one fields', async function (assert) {
assert.expect(2);
this.data.partner.fields.trululu.default = 2;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5148,14 +5185,14 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('do not perform extra RPC to read invisible x2many fields', function (assert) {
+ QUnit.test('do not perform extra RPC to read invisible x2many fields', async function (assert) {
assert.expect(2);
this.data.partner.records[0].p = [2]; // one2many
this.data.partner.records[0].product_ids = [37]; // one2many
this.data.partner.records[0].timmy = [12]; // many2many
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5180,13 +5217,13 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('default_order on x2many embedded view', function (assert) {
+ QUnit.test('default_order on x2many embedded view', async function (assert) {
assert.expect(11);
this.data.partner.fields.display_name.sortable = true;
this.data.partner.records[0].p = [1, 4];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5215,14 +5252,14 @@ QUnit.module('Views', {
assert.ok(form.$('.o_field_one2many tbody tr:first td:contains(yop)').length,
"record 1 should be first");
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual($('.modal').length, 1,
"FormViewDialog should be opened");
- testUtils.fields.editInput($('.modal input[name="foo"]'), 'xop')
- testUtils.dom.click($('.modal-footer button:eq(1)'));
- testUtils.fields.editInput($('.modal input[name="foo"]'), 'zop')
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.fields.editInput($('.modal input[name="foo"]'), 'xop');
+ await testUtils.dom.click($('.modal-footer button:eq(1)'));
+ await testUtils.fields.editInput($('.modal input[name="foo"]'), 'zop');
+ await testUtils.dom.click($('.modal-footer button:first'));
// client-side sort
assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zop)').length,
@@ -5233,7 +5270,7 @@ QUnit.module('Views', {
"record xop should be third");
// server-side sort
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zop)').length,
"record zop should be first");
assert.ok(form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)').length,
@@ -5242,10 +5279,10 @@ QUnit.module('Views', {
"record xop should be third");
// client-side sort on edit
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)'));
- testUtils.fields.editInput($('.modal input[name="foo"]'), 'zzz');
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_one2many tbody tr:eq(1) td:contains(yop)'));
+ await testUtils.fields.editInput($('.modal input[name="foo"]'), 'zzz');
+ await testUtils.dom.click($('.modal-footer button:first'));
assert.ok(form.$('.o_field_one2many tbody tr:eq(0) td:contains(zzz)').length,
"record zzz should be first");
assert.ok(form.$('.o_field_one2many tbody tr:eq(1) td:contains(zop)').length,
@@ -5256,10 +5293,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('action context is used when evaluating domains', function (assert) {
+ QUnit.test('action context is used when evaluating domains', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5280,16 +5317,16 @@ QUnit.module('Views', {
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('div[name="trululu"] input'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('div[name="trululu"] input'));
form.destroy();
});
- QUnit.test('form rendering with groups with col/colspan', function (assert) {
+ QUnit.test('form rendering with groups with col/colspan', async function (assert) {
assert.expect(46);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5411,10 +5448,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('outer and inner groups string attribute', function (assert) {
+ QUnit.test('outer and inner groups string attribute', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5451,10 +5488,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('form group with newline tag inside', function (assert) {
+ QUnit.test('form group with newline tag inside', async function (assert) {
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5508,11 +5545,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('custom open record dialog title', function (assert) {
+ QUnit.test('custom open record dialog title', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5530,14 +5567,14 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.dom.click(form.$('.o_data_row:first'));
+ await testUtils.dom.click(form.$('.o_data_row:first'));
assert.strictEqual($('.modal .modal-title').first().text().trim(), 'Open: custom label',
"modal should use the python field string as title");
form.destroy();
});
- QUnit.test('display translation alert', function (assert) {
+ QUnit.test('display translation alert', async function (assert) {
assert.expect(2);
this.data.partner.fields.foo.translate = true;
@@ -5546,7 +5583,7 @@ QUnit.module('Views', {
var multi_lang = _t.database.multi_lang;
_t.database.multi_lang = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5561,15 +5598,15 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name="foo"]'), "test");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "test");
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_form_view > .alert > div .oe_field_translate',
"should have single translation alert");
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name="display_name"]'), "test2");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name="display_name"]'), "test2");
+ await testUtils.form.clickSave(form);
assert.containsN(form, '.o_form_view > .alert > div .oe_field_translate', 2,
"should have two translate fields in translation alert");
@@ -5578,7 +5615,7 @@ QUnit.module('Views', {
_t.database.multi_lang = multi_lang;
});
- QUnit.test('translation alerts are preserved on pager change', function (assert) {
+ QUnit.test('translation alerts are preserved on pager change', async function (assert) {
assert.expect(5);
this.data.partner.fields.foo.translate = true;
@@ -5586,7 +5623,7 @@ QUnit.module('Views', {
var multi_lang = _t.database.multi_lang;
_t.database.multi_lang = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5602,27 +5639,27 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name="foo"]'), "test");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "test");
+ await testUtils.form.clickSave(form);
assert.containsOnce(form, '.o_form_view > .alert > div',"should have a translation alert");
// click on the pager to switch to the next record
- form.pager.$('.o_pager_next').click();
+ await testUtils.dom.click(form.pager.$('.o_pager_next'));
assert.strictEqual(form.$('.o_form_view > .alert > div').length, 0,
"should not have a translation alert");
// click on the pager to switch back to the previous record
- form.pager.$('.o_pager_previous').click();
+ await testUtils.dom.click(form.pager.$('.o_pager_previous'));
assert.containsOnce(form, '.o_form_view > .alert > div',"should have a translation alert");
// remove translation alert by click X and check alert even after form reload
- form.$('.o_form_view > .alert > .close').click();
+ await testUtils.dom.click(form.$('.o_form_view > .alert > .close'));
assert.strictEqual(form.$('.o_form_view > .alert > div').length, 0,
"should not have a translation alert");
- form.reload();
+ await form.reload();
assert.strictEqual(form.$('.o_form_view > .alert > div').length, 0,
"should not have a translation alert after reload");
@@ -5630,7 +5667,7 @@ QUnit.module('Views', {
_t.database.multi_lang = multi_lang;
});
- QUnit.test('translation alerts preseved on reverse breadcrumb', function (assert) {
+ QUnit.test('translation alerts preseved on reverse breadcrumb', async function (assert) {
assert.expect(2);
this.data['ir.translation'] = {
@@ -5678,23 +5715,21 @@ QUnit.module('Views', {
flags: {'search_view': true, 'action_buttons': true},
}];
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: actions,
archs: archs,
data: this.data,
});
- actionManager.doAction(1);
-
- actionManager.$('.o_form_button_edit').click();
+ await actionManager.doAction(1);
actionManager.$('input[name="foo"]').val("test").trigger("input");
- actionManager.$('.o_form_button_save').click();
+ await testUtils.dom.click(actionManager.$('.o_form_button_save'));
assert.strictEqual(actionManager.$('.o_form_view > .alert > div').length, 1,
"should have a translation alert");
var currentController = actionManager.getCurrentController().widget;
- actionManager.doAction(2, {
+ await actionManager.doAction(2, {
on_reverse_breadcrumb: function () {
if (!_.isEmpty(currentController.renderer.alertFields)) {
currentController.renderer.displayTranslationAlert();
@@ -5703,7 +5738,7 @@ QUnit.module('Views', {
},
});
- $('.o_control_panel .breadcrumb a:first').click();
+ await testUtils.dom.click($('.o_control_panel .breadcrumb a:first'));
assert.strictEqual(actionManager.$('.o_form_view > .alert > div').length, 1,
"should have a translation alert");
@@ -5711,7 +5746,7 @@ QUnit.module('Views', {
_t.database.multi_lang = multi_lang;
});
- QUnit.test('translate event correctly handled with multiple controllers', function (assert) {
+ QUnit.test('translate event correctly handled with multiple controllers', async function (assert) {
assert.expect(3);
this.data.product.fields.name.translate = true;
@@ -5721,7 +5756,7 @@ QUnit.module('Views', {
var multi_lang = _t.database.multi_lang;
_t.database.multi_lang = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5745,23 +5780,23 @@ QUnit.module('Views', {
res_id: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/product/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
} else if (route === "/web/dataset/call_button" && args.method === 'translate_fields') {
assert.deepEqual(args.args, ["product",37,"name",{}], 'should call "call_button" route');
nbTranslateCalls++;
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('[name="product_id"] .o_external_button'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('[name="product_id"] .o_external_button'));
assert.strictEqual($('.modal-body .o_field_translate').length, 1,
"there should be a translate button in the modal");
- testUtils.dom.click($('.modal-body .o_field_translate'));
+ await testUtils.dom.click($('.modal-body .o_field_translate'));
assert.strictEqual(nbTranslateCalls, 1, "should call_button translate once");
@@ -5769,12 +5804,12 @@ QUnit.module('Views', {
_t.database.multi_lang = multi_lang;
});
- QUnit.test('buttons are disabled until status bar action is resolved', function (assert) {
+ QUnit.test('buttons are disabled until status bar action is resolved', async function (assert) {
assert.expect(9);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5811,9 +5846,9 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.oe_button_box button:not(:disabled)').length, 1,
"stat buttons should be enabled");
- testUtils.dom.clickFirst(form.$('.o_form_statusbar button'));
+ await testUtils.dom.clickFirst(form.$('.o_form_statusbar button'));
- // The unresolved deferred lets us check the state of the buttons
+ // The unresolved promise lets us check the state of the buttons
assert.strictEqual(form.$buttons.find('button:disabled').length, 4,
"control panel buttons should be disabled");
assert.containsN(form, '.o_form_statusbar button:disabled', 2,
@@ -5822,7 +5857,7 @@ QUnit.module('Views', {
"stat buttons should be disabled");
def.resolve();
-
+ await testUtils.nextTick();
assert.strictEqual(form.$buttons.find('button:not(:disabled)').length, 4,
"control panel buttons should be enabled");
assert.strictEqual(form.$('.o_form_statusbar button:not(:disabled)').length, 2,
@@ -5833,12 +5868,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('buttons are disabled until button box action is resolved', function (assert) {
+ QUnit.test('buttons are disabled until button box action is resolved', async function (assert) {
assert.expect(9);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5875,9 +5910,9 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.oe_button_box button:not(:disabled)').length, 1,
"stat buttons should be enabled");
- testUtils.dom.click(form.$('.oe_button_box button'));
+ await testUtils.dom.click(form.$('.oe_button_box button'));
- // The unresolved deferred lets us check the state of the buttons
+ // The unresolved promise lets us check the state of the buttons
assert.strictEqual(form.$buttons.find('button:disabled').length, 4,
"control panel buttons should be disabled");
assert.containsN(form, '.o_form_statusbar button:disabled', 2,
@@ -5886,7 +5921,7 @@ QUnit.module('Views', {
"stat buttons should be disabled");
def.resolve();
-
+ await testUtils.nextTick();
assert.strictEqual(form.$buttons.find('button:not(:disabled)').length, 4,
"control panel buttons should be enabled");
assert.strictEqual(form.$('.o_form_statusbar button:not(:disabled)').length, 2,
@@ -5897,10 +5932,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('buttons with "confirm" attribute save before calling the method', function (assert) {
+ QUnit.test('buttons with "confirm" attribute save before calling the method', async function (assert) {
assert.expect(9);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5920,36 +5955,36 @@ QUnit.module('Views', {
intercepts: {
execute_action: function (event) {
assert.step('execute_action');
+ event.data.on_success();
},
},
});
// click on button, and cancel in confirm dialog
- testUtils.dom.click(form.$('.o_statusbar_buttons button'));
+ await testUtils.dom.click(form.$('.o_statusbar_buttons button'));
assert.ok(form.$('.o_statusbar_buttons button').prop('disabled'),
'button should be disabled');
- testUtils.dom.click($('.modal-footer button.btn-secondary'));
+ await testUtils.dom.click($('.modal-footer button.btn-secondary'));
assert.ok(!form.$('.o_statusbar_buttons button').prop('disabled'),
'button should no longer be disabled');
assert.verifySteps(['default_get']);
// click on button, and click on ok in confirm dialog
- testUtils.dom.click(form.$('.o_statusbar_buttons button'));
- assert.verifySteps(['default_get']);
- testUtils.dom.click($('.modal-footer button.btn-primary'));
-
- assert.verifySteps(['default_get', 'create', 'read', 'execute_action']);
+ await testUtils.dom.click(form.$('.o_statusbar_buttons button'));
+ assert.verifySteps([]);
+ await testUtils.dom.click($('.modal-footer button.btn-primary'));
+ assert.verifySteps(['create', 'read', 'execute_action']);
form.destroy();
});
- QUnit.test('buttons are disabled until action is resolved (in dialogs)', function (assert) {
+ QUnit.test('buttons are disabled until action is resolved (in dialogs)', async function (assert) {
assert.expect(3);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -5982,7 +6017,7 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === 'get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
@@ -5991,30 +6026,30 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
assert.notOk($('.modal .oe_button_box button').attr('disabled'),
"stat buttons should be enabled");
- testUtils.dom.click($('.modal .oe_button_box button'));
+ await testUtils.dom.click($('.modal .oe_button_box button'));
assert.ok($('.modal .oe_button_box button').attr('disabled'),
"stat buttons should be disabled");
def.resolve();
-
+ await testUtils.nextTick();
assert.notOk($('.modal .oe_button_box button').attr('disabled'),
"stat buttons should be enabled");
form.destroy();
});
- QUnit.test('multiple clicks on save should reload only once', function (assert) {
+ QUnit.test('multiple clicks on save should reload only once', async function (assert) {
assert.expect(4);
- var def = $.Deferred();
+ var def = testUtils.makeTestPromise();
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6039,13 +6074,13 @@ QUnit.module('Views', {
},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name="foo"]'), "test");
- testUtils.form.clickSave(form);
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "test");
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
def.resolve();
-
+ await testUtils.nextTick();
assert.verifySteps([
'read', // initial read to render the view
'write', // write on save
@@ -6055,10 +6090,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('form view is not broken if save operation fails', function (assert) {
+ QUnit.test('form view is not broken if save operation fails', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6073,19 +6108,19 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
assert.step(args.method);
if (args.method === 'write' && args.args[1].foo === 'incorrect value') {
- return $.Deferred().reject();
+ return Promise.reject();
}
return this._super.apply(this, arguments);
},
});
- testUtils.form.clickEdit(form);
- testUtils.fields.editInput(form.$('input[name="foo"]'), "incorrect value");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "incorrect value");
+ await testUtils.form.clickSave(form);
- testUtils.fields.editInput(form.$('input[name="foo"]'), "correct value");
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "correct value");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.verifySteps([
'read', // initial read to render the view
@@ -6097,10 +6132,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('support password attribute', function (assert) {
+ QUnit.test('support password attribute', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6112,7 +6147,7 @@ QUnit.module('Views', {
assert.strictEqual(form.$('span[name="foo"]').text(), '***',
"password should be displayed with stars");
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.strictEqual(form.$('input[name="foo"]').val(), 'yop',
"input value should be the password");
assert.strictEqual(form.$('input[name="foo"]').prop('type'), 'password',
@@ -6120,10 +6155,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('support autocomplete attribute', function (assert) {
+ QUnit.test('support autocomplete attribute', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6133,16 +6168,16 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.hasAttrValue(form.$('input[name="display_name"]'), 'autocomplete', 'coucou',
"attribute autocomplete should be set");
form.destroy();
});
- QUnit.test('context is correctly passed after save & new in FormViewDialog', function (assert) {
+ QUnit.test('context is correctly passed after save & new in FormViewDialog', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
res_id: 4,
@@ -6174,27 +6209,30 @@ QUnit.module('Views', {
return this._super.apply(this, arguments);
},
});
-
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.nextTick();
assert.strictEqual($('.modal').length, 1,
"One FormViewDialog should be opened");
// set a value on the m2o
- testUtils.fields.many2one.clickOpenDropdown('partner_type_id');
- testUtils.fields.many2one.clickHighlightedItem('partner_type_id');
+ await testUtils.fields.many2one.clickOpenDropdown('partner_type_id');
+ await testUtils.fields.many2one.clickHighlightedItem('partner_type_id');
- testUtils.dom.click($('.modal-footer button:eq(1)'));
- testUtils.dom.click($('.modal .o_field_many2one input'));
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.dom.click($('.modal-footer button:eq(1)'));
+ await testUtils.nextTick();
+ await testUtils.dom.click($('.modal .o_field_many2one input'));
+ await testUtils.fields.many2one.clickHighlightedItem('partner_type_id');
+ await testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('render domain field widget without model', function (assert) {
+ QUnit.test('render domain field widget without model', async function (assert) {
assert.expect(3);
this.data.partner.fields.model_name = { string: "Model name", type: "char" };
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6209,11 +6247,11 @@ QUnit.module('Views', {
assert.strictEqual(args.model, 'test',
"should search_count on test");
if (!args.kwargs.domain) {
- return $.Deferred().reject({
+ return Promise.reject({message:{
code: 200,
data: {},
message: "MockServer._getRecords: given domain has to be an array.",
- }, $.Event());
+ }, event: $.Event()});
}
}
return this._super.apply(this, arguments);
@@ -6222,13 +6260,13 @@ QUnit.module('Views', {
assert.strictEqual(form.$('.o_field_widget[name="display_name"]').text(), "Select a model to add a filter.",
"should contain an error message saying the model is missing");
- testUtils.fields.editInput(form.$('input[name="model_name"]'), "test");
+ await testUtils.fields.editInput(form.$('input[name="model_name"]'), "test");
assert.notStrictEqual(form.$('.o_field_widget[name="display_name"]').text(), "Select a model to add a filter.",
"should not contain an error message anymore");
form.destroy();
});
- QUnit.test('readonly fields are not sent when saving', function (assert) {
+ QUnit.test('readonly fields are not sent when saving', async function (assert) {
assert.expect(6);
// define an onchange on display_name to check that the value of readonly
@@ -6239,7 +6277,7 @@ QUnit.module('Views', {
};
var checkOnchange = false;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6274,31 +6312,33 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.nextTick();
assert.strictEqual($('.modal input.o_field_widget[name=foo]').length, 1,
- 'foo should be editable');
+ 'foo should be editable');
checkOnchange = true;
- testUtils.fields.editInput($('.modal .o_field_widget[name=foo]'), 'foo value');
- testUtils.fields.editInput($('.modal .o_field_widget[name=display_name]'), 'readonly');
+ await testUtils.fields.editInput($('.modal .o_field_widget[name=foo]'), 'foo value');
+ await testUtils.fields.editInput($('.modal .o_field_widget[name=display_name]'), 'readonly');
assert.strictEqual($('.modal span.o_field_widget[name=foo]').length, 1,
- 'foo should be readonly');
- testUtils.dom.clickFirst($('.modal-footer .btn-primary'));
+ 'foo should be readonly');
+ await testUtils.dom.clickFirst($('.modal-footer .btn-primary'));
+ await testUtils.nextTick();
checkOnchange = false;
- testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
assert.strictEqual($('.modal .o_field_widget[name=foo]').text(), 'foo value',
- "the edited value should have been kept");
- testUtils.dom.clickFirst($('.modal-footer .btn-primary'));
-
- testUtils.form.clickSave(form); // save the record
+ "the edited value should have been kept");
+ await testUtils.dom.clickFirst($('.modal-footer .btn-primary'));
+ await testUtils.nextTick();
+ await testUtils.form.clickSave(form); // save the record
form.destroy();
});
- QUnit.test('id is False in evalContext for new records', function (assert) {
+ QUnit.test('id is False in evalContext for new records', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6311,8 +6351,8 @@ QUnit.module('Views', {
assert.hasClass(form.$('.o_field_widget[name=foo]'),'o_readonly_modifier',
"foo should be readonly in 'Create' mode");
- testUtils.form.clickSave(form);
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickEdit(form);
assert.doesNotHaveClass(form.$('.o_field_widget[name=foo]'), 'o_readonly_modifier',
"foo should not be readonly anymore");
@@ -6320,11 +6360,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('delete a duplicated record', function (assert) {
+ QUnit.test('delete a duplicated record', async function (assert) {
assert.expect(5);
var newRecordID;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6350,20 +6390,20 @@ QUnit.module('Views', {
});
// duplicate record 1
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Duplicate)'));
assert.containsOnce(form, '.o_form_editable',
"form should be in edit mode");
assert.strictEqual(form.$('.o_field_widget').val(), 'first record (copy)',
"duplicated record should have correct name");
- testUtils.form.clickSave(form); // save duplicated record
+ await testUtils.form.clickSave(form); // save duplicated record
// delete duplicated record
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
assert.strictEqual($('.modal').length, 1, "should have opened a confirm dialog");
- testUtils.dom.click($('.modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal-footer .btn-primary'));
assert.strictEqual(form.$('.o_field_widget').text(), 'first record',
"should have come back to previous record");
@@ -6371,13 +6411,13 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('display tooltips for buttons', function (assert) {
+ QUnit.test('display tooltips for buttons', async function (assert) {
assert.expect(2);
var initialDebugMode = config.debug;
config.debug = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6409,7 +6449,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('reload event is handled only once', function (assert) {
+ QUnit.test('reload event is handled only once', async function (assert) {
// In this test, several form controllers are nested (two of them are
// opened in dialogs). When the users clicks on save in the last
// opened dialog, a 'reload' event is triggered up to reload the (direct)
@@ -6422,7 +6462,7 @@ QUnit.module('Views', {
'<field name="display_name"/>' +
'<field name="trululu"/>' +
'</form>';
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6434,7 +6474,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
assert.step(args.method);
if (args.method === 'get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
@@ -6443,11 +6483,11 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.o_external_button'));
- testUtils.dom.click($('.modal .o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click($('.modal .o_external_button'));
- testUtils.fields.editInput($('.modal:nth(1) .o_field_widget[name=display_name]'), 'new name');
- testUtils.dom.click($('.modal:nth(1) footer .btn-primary').first());
+ await testUtils.fields.editInput($('.modal:nth(1) .o_field_widget[name=display_name]'), 'new name');
+ await testUtils.dom.click($('.modal:nth(1) footer .btn-primary').first());
assert.strictEqual($('.modal .o_field_widget[name=trululu] input').val(), 'new name',
"record should have been reloaded");
@@ -6466,12 +6506,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('process the context for inline subview', function (assert) {
+ QUnit.test('process the context for inline subview', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6493,12 +6533,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('process the context for subview not inline', function (assert) {
+ QUnit.test('process the context for subview not inline', async function (assert) {
assert.expect(1);
this.data.partner.records[0].p = [2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6521,12 +6561,12 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('can toggle column in x2many in sub form view', function (assert) {
+ QUnit.test('can toggle column in x2many in sub form view', async function (assert) {
assert.expect(2);
this.data.partner.records[2].p = [1,2];
this.data.partner.fields.foo.sortable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6536,7 +6576,7 @@ QUnit.module('Views', {
res_id: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/call_kw/partner/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super.apply(this, arguments);
},
@@ -6551,20 +6591,20 @@ QUnit.module('Views', {
},
viewOptions: {mode: 'edit'},
});
- testUtils.dom.click(form.$('.o_external_button'));
+ await testUtils.dom.click(form.$('.o_external_button'));
assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "yopblip",
"table has some initial order");
- testUtils.dom.click($('.modal-body .o_form_view .o_list_view th'));
+ await testUtils.dom.click($('.modal-body .o_form_view .o_list_view th'));
assert.strictEqual($('.modal-body .o_form_view .o_list_view .o_data_cell').text(), "blipyop",
"table is now sorted");
form.destroy();
});
- QUnit.test('rainbowman attributes correctly passed on button click', function (assert) {
+ QUnit.test('rainbowman attributes correctly passed on button click', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6578,14 +6618,14 @@ QUnit.module('Views', {
var effectDescription = pyUtils.py_eval(event.data.action_data.effect);
assert.deepEqual(effectDescription, {message: 'Congrats!'}, "should have correct effect description");
}
- }
+ },
});
- testUtils.dom.click(form.$('.o_form_statusbar .btn-secondary'));
+ await testUtils.dom.click(form.$('.o_form_statusbar .btn-secondary'));
form.destroy();
});
- QUnit.test('basic support for widgets', function (assert) {
+ QUnit.test('basic support for widgets', async function (assert) {
assert.expect(1);
var MyWidget = Widget.extend({
@@ -6598,7 +6638,7 @@ QUnit.module('Views', {
});
widgetRegistry.add('test', MyWidget);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6616,10 +6656,10 @@ QUnit.module('Views', {
delete widgetRegistry.map.test;
});
- QUnit.test('support header button as widgets on form statusbar', function (assert) {
+ QUnit.test('support header button as widgets on form statusbar', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6638,7 +6678,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('basic support for widgets', function (assert) {
+ QUnit.test('basic support for widgets', async function (assert) {
assert.expect(1);
var MyWidget = Widget.extend({
@@ -6654,7 +6694,7 @@ QUnit.module('Views', {
});
widgetRegistry.add('test', MyWidget);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6664,7 +6704,7 @@ QUnit.module('Views', {
'</form>',
});
- testUtils.fields.editInput(form.$('input[name="foo"]'), "I am alive");
+ await testUtils.fields.editInput(form.$('input[name="foo"]'), "I am alive");
assert.strictEqual(form.$('.o_widget').text(), 'I am alive!',
"widget should have been updated");
@@ -6673,10 +6713,10 @@ QUnit.module('Views', {
});
- QUnit.test('bounce edit button in readonly mode', function (assert) {
+ QUnit.test('bounce edit button in readonly mode', async function (assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6694,24 +6734,24 @@ QUnit.module('Views', {
});
// in readonly
- testUtils.dom.click(form.$('[name="display_name"]'));
+ await testUtils.dom.click(form.$('[name="display_name"]'));
assert.verifySteps(['bounce']);
// in edit
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('[name="display_name"]'));
- assert.verifySteps(['bounce']);
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('[name="display_name"]'));
+ assert.verifySteps([]);
form.destroy();
});
- QUnit.test('proper stringification in debug mode tooltip', function (assert) {
+ QUnit.test('proper stringification in debug mode tooltip', async function (assert) {
assert.expect(4);
var initialDebugMode = config.debug;
config.debug = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6740,14 +6780,14 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('autoresize of text fields is done when switching to edit mode', function (assert) {
+ QUnit.test('autoresize of text fields is done when switching to edit mode', async function (assert) {
assert.expect(4);
this.data.partner.fields.text_field = { string: 'Text field', type: 'text' };
this.data.partner.fields.text_field.default = "some\n\nmulti\n\nline\n\ntext\n";
this.data.partner.records[0].text_field = "a\nb\nc\nd\ne\nf";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6761,7 +6801,7 @@ QUnit.module('Views', {
});
// switch to edit mode to ensure that autoresize is correctly done
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
var height = form.$('.o_field_widget[name=text_field]').height();
// focus the field to manually trigger autoresize
form.$('.o_field_widget[name=text_field]').trigger('focus');
@@ -6772,8 +6812,8 @@ QUnit.module('Views', {
assert.ok(height > 80, "textarea should have an height of at least 80px");
// save and create a new record to ensure that autoresize is correctly done
- testUtils.form.clickSave(form);
- testUtils.form.clickCreate(form);
+ await testUtils.form.clickSave(form);
+ await testUtils.form.clickCreate(form);
height = form.$('.o_field_widget[name=text_field]').height();
// focus the field to manually trigger autoresize
form.$('.o_field_widget[name=text_field]').trigger('focus');
@@ -6784,11 +6824,11 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
assert.expect(1);
var instanceNumber = 0;
- testUtils.mock.patch(mixins.ParentedMixin, {
+ await testUtils.mock.patch(mixins.ParentedMixin, {
init: function () {
instanceNumber++;
return this._super.apply(this, arguments);
@@ -6844,13 +6884,13 @@ QUnit.module('Views', {
res_id: 1,
};
- var form = createView(params);
+ var form = await createView(params);
form.destroy();
var initialInstanceNumber = instanceNumber;
instanceNumber = 0;
- form = createView(params);
+ form = await createView(params);
// call destroy function of controller to ensure that it correctly destroys everything
form.__destroy();
@@ -6861,13 +6901,13 @@ QUnit.module('Views', {
form.destroy();
- testUtils.mock.unpatch(mixins.ParentedMixin);
+ await testUtils.mock.unpatch(mixins.ParentedMixin);
});
- QUnit.test('do not change pager when discarding current record', function (assert) {
+ QUnit.test('do not change pager when discarding current record', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6884,8 +6924,8 @@ QUnit.module('Views', {
assert.strictEqual(form.pager.$('.o_pager_counter').text().trim(), '2 / 2',
'pager should indicate that we are on second record');
- testUtils.form.clickEdit(form);
- testUtils.form.clickDiscard(form);
+ await testUtils.form.clickEdit(form);
+ await testUtils.form.clickDiscard(form);
assert.strictEqual(form.pager.$('.o_pager_counter').text().trim(), '2 / 2',
'pager should not have changed');
@@ -6893,14 +6933,14 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('edition in form view on a "noCache" model', function (assert) {
- assert.expect(4);
+ QUnit.test('edition in form view on a "noCache" model', async function (assert) {
+ assert.expect(5);
- testUtils.mock.patch(BasicModel, {
+ await testUtils.mock.patch(BasicModel, {
noCacheModels: BasicModel.prototype.noCacheModels.concat(['partner']),
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6922,23 +6962,25 @@ QUnit.module('Views', {
});
core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value');
+ await testUtils.form.clickSave(form);
assert.verifySteps(['write', 'clear_cache']);
form.destroy();
- testUtils.mock.unpatch(BasicModel);
+ await testUtils.mock.unpatch(BasicModel);
+
+ assert.verifySteps(['clear_cache']); // triggered by the test environment on destroy
});
- QUnit.test('creation in form view on a "noCache" model', function (assert) {
- assert.expect(4);
+ QUnit.test('creation in form view on a "noCache" model', async function (assert) {
+ assert.expect(5);
- testUtils.mock.patch(BasicModel, {
+ await testUtils.mock.patch(BasicModel, {
noCacheModels: BasicModel.prototype.noCacheModels.concat(['partner']),
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6956,23 +6998,25 @@ QUnit.module('Views', {
});
core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache'));
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'value');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'value');
+ await testUtils.form.clickSave(form);
assert.verifySteps(['create', 'clear_cache']);
form.destroy();
- testUtils.mock.unpatch(BasicModel);
+ await testUtils.mock.unpatch(BasicModel);
+
+ assert.verifySteps(['clear_cache']); // triggered by the test environment on destroy
});
- QUnit.test('deletion in form view on a "noCache" model', function (assert) {
- assert.expect(4);
+ QUnit.test('deletion in form view on a "noCache" model', async function (assert) {
+ assert.expect(5);
- testUtils.mock.patch(BasicModel, {
+ await testUtils.mock.patch(BasicModel, {
noCacheModels: BasicModel.prototype.noCacheModels.concat(['partner']),
});
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -6994,17 +7038,19 @@ QUnit.module('Views', {
});
core.bus.on('clear_cache', form, assert.step.bind(assert, 'clear_cache'));
- testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
- testUtils.dom.click($('.modal-footer .btn-primary'));
+ await testUtils.dom.click(form.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(form.sidebar.$('a:contains(Delete)'));
+ await testUtils.dom.click($('.modal-footer .btn-primary'));
assert.verifySteps(['unlink', 'clear_cache']);
form.destroy();
- testUtils.mock.unpatch(BasicModel);
+ await testUtils.mock.unpatch(BasicModel);
+
+ assert.verifySteps(['clear_cache']); // triggered by the test environment on destroy
});
- QUnit.test('reload currencies when writing on records of model res.currency', function (assert) {
+ QUnit.test('reload currencies when writing on records of model res.currency', async function (assert) {
assert.expect(5);
this.data['res.currency'] = {
@@ -7012,7 +7058,7 @@ QUnit.module('Views', {
records: [{id: 1, display_name: "some currency"}],
};
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'res.currency',
data: this.data,
@@ -7032,8 +7078,8 @@ QUnit.module('Views', {
},
});
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value');
- testUtils.form.clickSave(form);
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'new value');
+ await testUtils.form.clickSave(form);
assert.verifySteps([
'read',
@@ -7045,8 +7091,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('a popup window should automatically close after a do_action event', function (assert) {
-
+ QUnit.test('a popup window should automatically close after a do_action event', async function (assert) {
// Having clicked on a one2many in a form view and clicked on a many2one
// field in the resulting popup window that popup window should automatically close.
@@ -7055,7 +7100,7 @@ QUnit.module('Views', {
this.data.partner.records[0].product_ids = [37];
this.data.product.records[0].partner_type_id = 12;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7068,7 +7113,7 @@ QUnit.module('Views', {
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'get_formview_action' && args.model === 'partner_type') {
- return $.when();
+ return Promise.resolve();
}
return this._super(route, args);
},
@@ -7079,16 +7124,16 @@ QUnit.module('Views', {
},
});
// Open one2many
- testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
assert.strictEqual($('.modal-content').length, 1, "a popup window should have opened");
// Click on many2one and trigger do_action
- testUtils.dom.click($('.modal-content a[name="partner_type_id"]'));
+ await testUtils.dom.click($('.modal-content a[name="partner_type_id"]'));
assert.strictEqual($('.modal-content').length, 0, "the popup window should have closed");
form.destroy();
});
- QUnit.test('all popup windows should automatically close after a do_action event', function (assert) {
+ QUnit.test('all popup windows should automatically close after a do_action event', async function (assert) {
// Having clicked successively on two different one2many in form views
// and clicked on a many2one in the last popup window all popup
@@ -7100,7 +7145,7 @@ QUnit.module('Views', {
this.data.partner.records[1].product_ids = [37];
this.data.product.records[0].partner_type_id = 12;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7118,7 +7163,7 @@ QUnit.module('Views', {
res_id: 1,
mockRPC: function (route, args) {
if (args.method === 'get_formview_action' && args.model === 'partner_type') {
- return $.when();
+ return Promise.resolve();
}
return this._super(route, args);
},
@@ -7129,21 +7174,21 @@ QUnit.module('Views', {
},
});
// Open two one2manys
- testUtils.dom.click(form.$('.o_data_row'));
- testUtils.dom.click($('.modal-content .o_data_row'));
+ await testUtils.dom.click(form.$('.o_data_row'));
+ await testUtils.dom.click($('.modal-content .o_data_row'));
assert.strictEqual($('.modal-content').length, 2, "Two popup windows should have opened.");
// Click on many2one and trigger do_action
- testUtils.dom.click($('.modal-content a[name="partner_type_id"]'));
+ await testUtils.dom.click($('.modal-content a[name="partner_type_id"]'));
assert.strictEqual($('.modal-content').length, 0, "All popup windows should have closed.");
form.destroy();
});
- QUnit.test('keep editing after call_button fail', function (assert) {
+ QUnit.test('keep editing after call_button fail', async function (assert) {
assert.expect(4);
var values;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7175,21 +7220,20 @@ QUnit.module('Views', {
});
// add a row and partially fill it
- form.$('.o_field_x2many_list_row_add a').click();
- form.$('input[name=display_name]').val('abc').trigger('input');
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput(form.$('input[name=display_name]'), 'abc');
// click button which will trigger_up 'execute_action' (this will save)
values = {
display_name: 'abc',
product_id: false,
};
- form.$('button.p').click();
-
+ await testUtils.dom.click(form.$('button.p'));
// edit the new row again and set a many2one value
- form.$('.o_form_view .o_field_one2many .o_data_row .o_data_cell').click();
- var $dropdown = form.$('.o_field_many2one input').autocomplete('widget');
- form.$('.o_field_many2one input').click();
- $dropdown.find('li:first()').click();
+ await testUtils.dom.clickLast(form.$('.o_form_view .o_field_one2many .o_data_row .o_data_cell'));
+ await testUtils.nextTick();
+ await testUtils.fields.many2one.clickOpenDropdown('product_id');
+ await testUtils.fields.many2one.clickHighlightedItem('product_id');
assert.strictEqual(form.$('.o_field_many2one input').val(), 'xphone',
"value of the m2o should have been correctly updated");
@@ -7197,15 +7241,15 @@ QUnit.module('Views', {
values = {
product_id: 37,
};
- form.$buttons.find('.o_form_button_save').click();
+ await testUtils.form.clickSave(form);
form.destroy();
});
- QUnit.test('asynchronous rendering of a widget tag', function (assert) {
+ QUnit.test('asynchronous rendering of a widget tag', async function (assert) {
assert.expect(1);
- var def1 = $.Deferred();
+ var def1 = testUtils.makeTestPromise();
var MyWidget = Widget.extend({
willStart: function() {
@@ -7215,7 +7259,7 @@ QUnit.module('Views', {
widgetRegistry.add('test', MyWidget);
- createAsyncView({
+ createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7230,9 +7274,10 @@ QUnit.module('Views', {
});
def1.resolve();
+ await testUtils.nextTick();
});
- QUnit.test('no deadlock when saving with uncommitted changes', function (assert) {
+ QUnit.test('no deadlock when saving with uncommitted changes', async function (assert) {
// Before saving a record, all field widgets are asked to commit their changes (new values
// that they wouldn't have sent to the model yet). This test is added alongside a bug fix
// ensuring that we don't end up in a deadlock when a widget actually has some changes to
@@ -7245,7 +7290,7 @@ QUnit.module('Views', {
// on 'Save'.
assert.expect(6);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7254,16 +7299,18 @@ QUnit.module('Views', {
assert.step(args.method);
return this._super.apply(this, arguments);
},
- // we set a fieldDebounce to precisely mock the behavior of the webclient: changes are
- // not sent to the model at keystrokes, but when the input is left
+ // we set a fieldDebounce to precisely mock the behavior of the webclient: changes are
+ // not sent to the model at keystrokes, but when the input is left
fieldDebounce: 5000,
});
- testUtils.fields.editInput(form.$('input[name=foo]'), 'some foo value');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'some foo value');
// manually save the record, to prevent the field widget to notify the model of its new
// value before being requested to
form.saveRecord();
+ await testUtils.nextTick();
+
assert.containsOnce(form, '.o_form_readonly', "form view should be in readonly");
assert.strictEqual(form.$('.o_form_view').text().trim(), 'some foo value',
"foo field should have correct value");
@@ -7272,7 +7319,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('save record with onchange on one2many with required field', function (assert) {
+ QUnit.test('save record with onchange on one2many with required field', async function (assert) {
// in this test, we have a one2many with a required field, whose value is
// set by an onchange on another field ; we manually set the value of that
// first field, and directly click on Save (before the onchange RPC returns
@@ -7287,7 +7334,7 @@ QUnit.module('Views', {
};
var onchangeDef;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7302,7 +7349,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(onchangeDef).then(_.constant(result));
+ return Promise.resolve(onchangeDef).then(_.constant(result));
}
if (args.method === 'create') {
assert.step('create');
@@ -7313,28 +7360,29 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
assert.strictEqual(form.$('.o_field_widget[name=display_name]').val(), '',
"display_name should be the empty string by default");
assert.strictEqual(form.$('.o_field_widget[name=foo]').val(), '',
"foo should be the empty string by default");
- onchangeDef = $.Deferred(); // delay the onchange
+ onchangeDef = testUtils.makeTestPromise(); // delay the onchange
- testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'some value');
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=display_name]'), 'some value');
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.step('resolve');
onchangeDef.resolve();
+ await testUtils.nextTick();
assert.verifySteps(['resolve', 'create']);
form.destroy();
});
- QUnit.test('call canBeRemoved while saving', function (assert) {
+ QUnit.test('call canBeRemoved while saving', async function (assert) {
assert.expect(10);
this.data.partner.onchanges = {
@@ -7344,8 +7392,8 @@ QUnit.module('Views', {
};
var onchangeDef;
- var createDef = $.Deferred();
- var form = createView({
+ var createDef = testUtils.makeTestPromise();
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7353,41 +7401,43 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(onchangeDef).then(_.constant(result));
+ return Promise.resolve(onchangeDef).then(_.constant(result));
}
if (args.method === 'create') {
- return $.when(createDef).then(_.constant(result));
+ return Promise.resolve(createDef).then(_.constant(result));
}
return result;
},
});
// edit foo to trigger a delayed onchange
- onchangeDef = $.Deferred();
- testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange');
+ onchangeDef = testUtils.makeTestPromise();
+ await testUtils.fields.editInput(form.$('.o_field_widget[name=foo]'), 'trigger onchange');
assert.strictEqual(form.$('.o_field_widget[name=display_name]').val(), 'default');
// save (will wait for the onchange to return), and will be delayed as well
- testUtils.dom.click(form.$buttons.find('.o_form_button_save'));
+ await testUtils.dom.click(form.$buttons.find('.o_form_button_save'));
assert.hasClass(form.$('.o_form_view'), 'o_form_editable');
assert.strictEqual(form.$('.o_field_widget[name=display_name]').val(), 'default');
// simulate a click on the breadcrumbs to leave the form view
form.canBeRemoved();
+ await testUtils.nextTick();
assert.hasClass(form.$('.o_form_view'), 'o_form_editable');
assert.strictEqual(form.$('.o_field_widget[name=display_name]').val(), 'default');
// unlock the onchange
onchangeDef.resolve();
-
+ await testUtils.nextTick();
assert.hasClass(form.$('.o_form_view'), 'o_form_editable');
assert.strictEqual(form.$('.o_field_widget[name=display_name]').val(), 'changed');
// unlock the create
createDef.resolve();
+ await testUtils.nextTick();
assert.hasClass(form.$('.o_form_view'), 'o_form_readonly');
assert.strictEqual(form.$('.o_field_widget[name=display_name]').text(), 'changed');
@@ -7397,7 +7447,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('domain returned by onchange is cleared on discard', function (assert) {
+ QUnit.test('domain returned by onchange is cleared on discard', async function (assert) {
assert.expect(4);
this.data.partner.onchanges = {
@@ -7406,7 +7456,7 @@ QUnit.module('Views', {
var domain = ['id', '=', 1];
var expectedDomain = domain;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7414,7 +7464,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
if (args.method === 'onchange' && args.args[0][0] === 1) {
// onchange returns a domain only on record 1
- return $.when({
+ return Promise.resolve({
domain: {
trululu: domain,
},
@@ -7435,30 +7485,30 @@ QUnit.module('Views', {
assert.strictEqual(form.$('input[name=foo]').val(), 'yop', "should be on record 1");
// change foo to trigger the onchange
- testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
+ await testUtils.fields.editInput(form.$('input[name=foo]'), 'new value');
// open many2one dropdown to check if the domain is applied
- testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
// switch to another record (should ask to discard changes, and reset the domain)
- testUtils.dom.click(form.pager.$('.o_pager_next'));
+ await testUtils.dom.click(form.pager.$('.o_pager_next'));
// discard changes by clicking on confirm in the dialog
- testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
+ await testUtils.dom.click($('.modal .modal-footer .btn-primary:first'));
assert.strictEqual(form.$('input[name=foo]').val(), 'blip', "should be on record 2");
// open many2one dropdown to check if the domain is applied
expectedDomain = [];
- testUtils.fields.many2one.clickOpenDropdown('trululu');
+ await testUtils.fields.many2one.clickOpenDropdown('trululu');
form.destroy();
});
- QUnit.test('discard after a failed save', function (assert) {
+ QUnit.test('discard after a failed save', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,form': '<form>' +
@@ -7472,13 +7522,13 @@ QUnit.module('Views', {
actions: this.actions,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
- testUtils.dom.click('.o_control_panel .o-kanban-button-new');
+ await testUtils.dom.click('.o_control_panel .o-kanban-button-new');
//cannot save because there is a required field
- testUtils.dom.click('.o_control_panel .o_form_button_save');
- testUtils.dom.click('.o_control_panel .o_form_button_cancel');
+ await testUtils.dom.click('.o_control_panel .o_form_button_save');
+ await testUtils.dom.click('.o_control_panel .o_form_button_cancel');
assert.containsNone(actionManager, '.o_form_view');
assert.containsOnce(actionManager, '.o_kanban_view');
@@ -7486,10 +7536,10 @@ QUnit.module('Views', {
actionManager.destroy();
});
- QUnit.test("one2many create record dialog shouldn't have a 'remove' button", function (assert) {
+ QUnit.test("one2many create record dialog shouldn't have a 'remove' button", async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7510,8 +7560,8 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickCreate(form);
- form.$('.o-kanban-button-new').click();
+ await testUtils.form.clickCreate(form);
+ await testUtils.dom.click(form.$('.o-kanban-button-new'));
assert.containsOnce(document.body, '.modal');
assert.strictEqual($('.modal .modal-footer .o_btn_remove').length, 0,
@@ -7522,10 +7572,10 @@ QUnit.module('Views', {
QUnit.module('FormViewTABMainButtons');
- QUnit.test('using tab in an empty required string field should not move to the next field',function(assert) {
+ QUnit.test('using tab in an empty required string field should not move to the next field', async function(assert) {
assert.expect(3);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7539,7 +7589,7 @@ QUnit.module('Views', {
'</form>',
});
- testUtils.dom.click(form.$('input[name=display_name]'));
+ await testUtils.dom.click(form.$('input[name=display_name]'));
assert.strictEqual(form.$('input[name="display_name"]')[0], document.activeElement,
"display_name should be focused");
form.$('input[name="display_name"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
@@ -7550,10 +7600,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('using tab in an empty required date field should not move to the next field',function(assert) {
+ QUnit.test('using tab in an empty required date field should not move to the next field', async function(assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7567,7 +7617,7 @@ QUnit.module('Views', {
'</form>',
});
- testUtils.dom.click(form.$('input[name=date]'));
+ await testUtils.dom.click(form.$('input[name=date]'));
assert.strictEqual(form.$('input[name="date"]')[0], document.activeElement,
"display_name should be focused");
form.$('input[name="date"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
@@ -7577,10 +7627,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('Edit button get the focus when pressing TAB from form', function (assert) {
+ QUnit.test('Edit button get the focus when pressing TAB from form', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7593,7 +7643,7 @@ QUnit.module('Views', {
});
// in edit
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
form.$('input[name="display_name"]').focus().trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
assert.strictEqual(form.$buttons.find('.btn-primary:visible')[0], document.activeElement,
"the first primary button (save) should be focused");
@@ -7602,9 +7652,9 @@ QUnit.module('Views', {
QUnit.module('FormViewTABFormButtons');
- QUnit.test('In Edition mode, after navigating to the last field, the default button when pressing TAB is SAVE', function (assert) {
+ QUnit.test('In Edition mode, after navigating to the last field, the default button when pressing TAB is SAVE', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7634,10 +7684,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('In READ mode, the default button with focus is the first primary button of the form', function (assert) {
+ QUnit.test('In READ mode, the default button with focus is the first primary button of the form', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7662,10 +7712,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('In READ mode, the default button when pressing TAB is EDIT when there is no primary button on the form', function (assert) {
+ QUnit.test('In READ mode, the default button when pressing TAB is EDIT when there is no primary button on the form', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7690,10 +7740,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('In Edition mode, when an attribute is dynamically required (and not required), TAB should navigate to the next field', function (assert) {
+ QUnit.test('In Edition mode, when an attribute is dynamically required (and not required), TAB should navigate to the next field', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7718,10 +7768,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('In Edition mode, when an attribute is dynamically required, TAB should stop on the field if it is required', function (assert) {
+ QUnit.test('In Edition mode, when an attribute is dynamically required, TAB should stop on the field if it is required', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7739,7 +7789,7 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(form.$('div[name="bar"]>input'));
+ await testUtils.dom.click(form.$('div[name="bar"]>input'));
form.$('input[name="foo"]').focus();
$(document.activeElement).trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
@@ -7747,10 +7797,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('display tooltips for save and discard buttons', function (assert) {
+ QUnit.test('display tooltips for save and discard buttons', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7762,12 +7812,13 @@ QUnit.module('Views', {
form.$buttons.find('.o_form_buttons_edit').tooltip('show',false);
assert.strictEqual($('.tooltip .oe_tooltip_string').length, 1,
"should have rendered a tooltip");
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('if the focus is on the save button, hitting ENTER should save', function (assert) {
+ QUnit.test('if the focus is on the save button, hitting ENTER should save', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7786,14 +7837,15 @@ QUnit.module('Views', {
});
form.$buttons.find('.o_form_button_save')
- .focus()
- .trigger($.Event('keydown', {which: $.ui.keyCode.ENTER}));
+ .focus()
+ .trigger($.Event('keydown', {which: $.ui.keyCode.ENTER}));
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('if the focus is on the discard button, hitting ENTER should save', function (assert) {
+ QUnit.test('if the focus is on the discard button, hitting ENTER should save', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7812,14 +7864,15 @@ QUnit.module('Views', {
});
form.$buttons.find('.o_form_button_cancel')
- .focus()
- .trigger($.Event('keydown', {which: $.ui.keyCode.ENTER}));
+ .focus()
+ .trigger($.Event('keydown', {which: $.ui.keyCode.ENTER}));
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('if the focus is on the save button, hitting ESCAPE should discard', function (assert) {
+ QUnit.test('if the focus is on the save button, hitting ESCAPE should discard', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7838,14 +7891,15 @@ QUnit.module('Views', {
});
form.$buttons.find('.o_form_button_save')
- .focus()
- .trigger($.Event('keydown', {which: $.ui.keyCode.ESCAPE}));
+ .focus()
+ .trigger($.Event('keydown', {which: $.ui.keyCode.ESCAPE}));
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('if the focus is on the discard button, hitting ESCAPE should discard', function (assert) {
+ QUnit.test('if the focus is on the discard button, hitting ESCAPE should discard', async function (assert) {
assert.expect(1);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -7864,18 +7918,19 @@ QUnit.module('Views', {
});
form.$buttons.find('.o_form_button_cancel')
- .focus()
- .trigger($.Event('keydown', {which: $.ui.keyCode.ESCAPE}));
+ .focus()
+ .trigger($.Event('keydown', {which: $.ui.keyCode.ESCAPE}));
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('if the focus is on the save button, hitting TAB should not move to the next button', function (assert) {
+ QUnit.test('if the focus is on the save button, hitting TAB should not move to the next button', async function (assert) {
assert.expect(1);
/*
this test has only one purpose: to say that it is normal that the focus stays within a button primary even after the TAB key has been pressed.
It is not possible here to execute the default action of the TAB on a button : https://stackoverflow.com/questions/32428993/why-doesnt-simulating-a-tab-keypress-move-focus-to-the-next-input-field
so writing a test that will always succeed is not useful.
- */
+ */
assert.ok("Behavior can't be tested");
});
});
diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js
index d9cec90bc4e..cae561e4889 100644
--- a/addons/web/static/tests/views/graph_tests.js
+++ b/addons/web/static/tests/views/graph_tests.js
@@ -59,10 +59,10 @@ QUnit.module('Views', {
QUnit.module('GraphView');
- QUnit.test('simple graph rendering', function (assert) {
+ QUnit.test('simple graph rendering', async function (assert) {
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -92,10 +92,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('default type attribute', function (assert) {
+ QUnit.test('default type attribute', async function (assert) {
assert.expect(1);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -107,10 +107,10 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('title attribute', function (assert) {
+ QUnit.test('title attribute', async function (assert) {
assert.expect(1);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -123,10 +123,10 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('switching mode', function (assert) {
+ QUnit.test('switching mode', async function (assert) {
assert.expect(6);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -139,7 +139,7 @@ QUnit.module('Views', {
'bar type button should not be active');
assert.hasClass(graph.$buttons.find('button[data-mode="line"]'),'active',
'line type button should be active');
- testUtils.dom.click(graph.$buttons.find('button[data-mode="bar"]'));
+ await testUtils.dom.click(graph.$buttons.find('button[data-mode="bar"]'));
assert.strictEqual(graph.renderer.state.mode, "bar", "should be in bar chart mode by default");
assert.doesNotHaveClass(graph.$buttons.find('button[data-mode="line"]'), 'active',
'line type button should not be active');
@@ -148,13 +148,13 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('displaying line chart with only 1 data point', function (assert) {
+ QUnit.test('displaying line chart with only 1 data point', async function (assert) {
assert.expect(1);
// this test makes sure the line chart does not crash when only one data
// point is displayed.
var done = assert.async();
this.data.foo.records = this.data.foo.records.slice(0,1);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -169,12 +169,12 @@ QUnit.module('Views', {
});
});
- QUnit.test('displaying line chart data with multiple groupbys', function (assert) {
+ QUnit.test('displaying line chart data with multiple groupbys', async function (assert) {
// this test makes sure the line chart shows all data labels (X axis) when
// it is grouped by several fields
assert.expect(3);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: 'foo',
data: this.data,
@@ -192,10 +192,10 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('displaying bar chart data with multiple groupbys', function (assert) {
+ QUnit.test('displaying bar chart data with multiple groupbys', async function (assert) {
assert.expect(3);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: 'foo',
data: this.data,
@@ -213,13 +213,13 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('switching measures', function (assert) {
+ QUnit.test('switching measures', async function (assert) {
var done = assert.async();
assert.expect(4);
var rpcCount = 0;
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -249,11 +249,11 @@ QUnit.module('Views', {
});
});
- QUnit.test('no content helper (bar chart)', function (assert) {
+ QUnit.test('no content helper (bar chart)', async function (assert) {
assert.expect(2);
this.data.foo.records = [];
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -268,11 +268,11 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('no content helper (pie chart)', function (assert) {
+ QUnit.test('no content helper (pie chart)', async function (assert) {
assert.expect(2);
this.data.foo.records = []
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -287,10 +287,10 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('render pie chart in comparison mode', function (assert) {
+ QUnit.test('render pie chart in comparison mode', async function (assert) {
assert.expect(2);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -316,11 +316,10 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('no content helper after update', function (assert) {
- var done = assert.async();
+ QUnit.test('no content helper after update', async function (assert) {
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -328,27 +327,26 @@ QUnit.module('Views', {
'<field name="product_id"/>' +
'</graph>',
});
- return concurrency.delay(0).then(function () {
- assert.ok(graph.$('div.o_graph_svg_container svg.nvd3-svg').length,
- "should contain a div with a svg element");
- assert.notOk(graph.$('div.o_view_nocontent').length,
- "should not display the no content helper");
- testUtils.graph.reload(graph, {domain: [['product_id', '=', 4]]});
-
- assert.notOk(graph.$('div.o_graph_svg_container svg.nvd3-svg').length,
- "should not contain a div with a svg element");
- assert.ok(graph.$('div.o_view_nocontent').length,
- "should display the no content helper");
- graph.destroy();
- done();
- });
+
+ await testUtils.nextTick();
+ assert.ok(graph.$('div.o_graph_svg_container svg.nvd3-svg').length,
+ "should contain a div with a svg element");
+ assert.notOk(graph.$('div.o_view_nocontent').length,
+ "should not display the no content helper");
+ testUtils.graph.reload(graph, {domain: [['product_id', '=', 4]]});
+ await testUtils.nextTick();
+ assert.notOk(graph.$('div.o_graph_svg_container svg.nvd3-svg').length,
+ "should not contain a div with a svg element");
+ assert.ok(graph.$('div.o_view_nocontent').length,
+ "should display the no content helper");
+ graph.destroy();
});
- QUnit.test('can reload with other group by', function (assert) {
+ QUnit.test('can reload with other group by', async function (assert) {
var done = assert.async();
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -375,11 +373,11 @@ QUnit.module('Views', {
});
});
- QUnit.test('getOwnedQueryParams correctly returns mode, measure, groupbys and interval mapping', function (assert) {
+ QUnit.test('getOwnedQueryParams correctly returns mode, measure, groupbys and interval mapping', async function (assert) {
var done = assert.async();
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -442,14 +440,14 @@ QUnit.module('Views', {
});
});
- QUnit.test('correctly uses graph_ keys from the context', function (assert) {
+ QUnit.test('correctly uses graph_ keys from the context', async function (assert) {
var done = assert.async();
assert.expect(6);
var lastOne = _.last(this.data.foo.records);
lastOne.color_id = 14;
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -485,14 +483,14 @@ QUnit.module('Views', {
});
});
- QUnit.test('correctly use group_by key from the context', function (assert) {
+ QUnit.test('correctly use group_by key from the context', async function (assert) {
var done = assert.async();
assert.expect(2);
var lastOne = _.last(this.data.foo.records);
lastOne.color_id = 14;
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: 'foo',
data: this.data,
@@ -515,14 +513,14 @@ QUnit.module('Views', {
});
});
- QUnit.test('correctly uses graph_ keys from the context (at reload)', function (assert) {
+ QUnit.test('correctly uses graph_ keys from the context (at reload)', async function (assert) {
var done = assert.async();
assert.expect(8);
var lastOne = _.last(this.data.foo.records);
lastOne.color_id = 14;
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -564,10 +562,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('reload graph with correct fields', function (assert) {
+ QUnit.test('reload graph with correct fields', async function (assert) {
assert.expect(2);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: 'foo',
data: this.data,
@@ -584,16 +582,16 @@ QUnit.module('Views', {
},
});
- testUtils.graph.reload(graph, {groupBy: []});
+ await testUtils.graph.reload(graph, {groupBy: []});
graph.destroy();
});
- QUnit.test('initial groupby is kept when reloading', function (assert) {
+ QUnit.test('initial groupby is kept when reloading', async function (assert) {
var done = assert.async();
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: 'foo',
data: this.data,
@@ -626,10 +624,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('use a many2one as a measure should work (without groupBy)', function (assert) {
+ QUnit.test('use a many2one as a measure should work (without groupBy)', async function (assert) {
assert.expect(3);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -651,10 +649,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('use a many2one as a measure should work (with groupBy)', function (assert) {
+ QUnit.test('use a many2one as a measure should work (with groupBy)', async function (assert) {
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -679,10 +677,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('use a many2one as a measure and as a groupby should work', function (assert) {
+ QUnit.test('use a many2one as a measure and as a groupby should work', async function (assert) {
assert.expect(2);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -693,27 +691,24 @@ QUnit.module('Views', {
additionalMeasures: ['product_id'],
},
});
- var done = assert.async();
- return concurrency.delay(0).then(function () {
- // need to set the measure this way because it cannot be set in the
- // arch.
- testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)'));
- testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="product_id"]'));
+ await testUtils.nextTick();
+ // need to set the measure this way because it cannot be set in the
+ // arch.
+ await testUtils.dom.click(graph.$buttons.find('.dropdown-toggle:contains(Measures)'));
+ await testUtils.dom.click(graph.$buttons.find('.dropdown-item[data-field="product_id"]'));
- assert.strictEqual(graph.model.chart.data[0].value, 1,
- "should have first datapoint with value 1");
- assert.strictEqual(graph.model.chart.data[1].value, 1,
- "should have second datapoint with value 1");
+ assert.strictEqual(graph.model.chart.data[0].value, 1,
+ "should have first datapoint with value 1");
+ assert.strictEqual(graph.model.chart.data[1].value, 1,
+ "should have second datapoint with value 1");
- graph.destroy();
- done();
- });
+ graph.destroy();
});
- QUnit.test('not use a many2one as a measure by default', function (assert) {
+ QUnit.test('not use a many2one as a measure by default', async function (assert) {
assert.expect(1);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -730,10 +725,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('use a many2one as a measure if set as additional fields', function (assert) {
+ QUnit.test('use a many2one as a measure if set as additional fields', async function (assert) {
assert.expect(1);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -753,10 +748,10 @@ QUnit.module('Views', {
});
});
- QUnit.test('graph view crash when moving from search view using Down key', function (assert) {
+ QUnit.test('graph view crash when moving from search view using Down key', async function (assert) {
assert.expect(1);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: this.data,
@@ -769,13 +764,13 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('graph measures should be alphabetically sorted', function (assert) {
+ QUnit.test('graph measures should be alphabetically sorted', async function (assert) {
assert.expect(2);
var data = this.data;
data.foo.fields.bouh = {string: "bouh", type: "integer"};
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
data: data,
@@ -793,10 +788,10 @@ QUnit.module('Views', {
graph.destroy();
});
- QUnit.test('Undefined should appear in bar, pie graph but not in line graph', function (assert) {
+ QUnit.test('Undefined should appear in bar, pie graph but not in line graph', async function (assert) {
assert.expect(4);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
groupBy:['date'],
@@ -809,17 +804,17 @@ QUnit.module('Views', {
assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0);
assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
- testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=bar]'));
+ await testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=bar]'));
assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 1);
assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
graph.destroy();
});
- QUnit.test('Undefined should appear in bar, pie graph but not in line graph with multiple groupbys', function (assert) {
+ QUnit.test('Undefined should appear in bar, pie graph but not in line graph with multiple groupbys', async function (assert) {
assert.expect(6);
- var graph = createView({
+ var graph = await createView({
View: GraphView,
model: "foo",
groupBy:['date', 'color_id'],
@@ -832,12 +827,12 @@ QUnit.module('Views', {
assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0);
assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
- graph.$buttons.find('.o_graph_button[data-mode=bar]').click();
+ await testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=bar]'));
assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 1);
assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
// Undefined should not appear after switching back to line chart
- graph.$buttons.find('.o_graph_button[data-mode=line]').click();
+ await testUtils.dom.click(graph.$buttons.find('.o_graph_button[data-mode=line]'));
assert.strictEqual(graph.$("svg.nvd3-svg .nv-x:contains('Undefined')").length, 0);
assert.strictEqual(graph.$("svg.nvd3-svg:contains('January')").length, 1);
graph.destroy();
diff --git a/addons/web/static/tests/views/kanban_mobile_tests.js b/addons/web/static/tests/views/kanban_mobile_tests.js
index cc8354432e3..52bfa60a180 100644
--- a/addons/web/static/tests/views/kanban_mobile_tests.js
+++ b/addons/web/static/tests/views/kanban_mobile_tests.js
@@ -55,10 +55,10 @@ QUnit.module('Views', {
QUnit.module('KanbanView Mobile');
- QUnit.test('mobile grouped rendering', function (assert) {
+ QUnit.test('mobile grouped rendering', async function (assert) {
assert.expect(13);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -83,13 +83,13 @@ QUnit.module('Views', {
"there is no records in next tab. Records will be loaded when it will be opened");
// quick create in first column
- testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new'));
- assert.hasClass(kanban.$('.o_kanban_group:nth(0) > div:nth(1)'), 'o_kanban_quick_create',
+ await testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new'));
+ assert.hasClass(kanban.$('.o_kanban_group:nth(0) > div:nth(1)'),'o_kanban_quick_create',
"clicking on create should open the quick_create in the first column");
// move to second column
- kanban.$('.o_kanban_mobile_tab:nth(1)').trigger('click');
- assert.hasClass(kanban.$('.o_kanban_mobile_tab:nth(1)'), 'o_current',
+ await testUtils.dom.click(kanban.$('.o_kanban_mobile_tab:nth(1)'));
+ assert.hasClass(kanban.$('.o_kanban_mobile_tab:nth(1)'),'o_current',
"second tab is now active with class 'o_current'");
assert.hasClass(kanban.$('.o_kanban_group:nth(1)'),'o_current',
"second column is now active with class 'o_current'");
@@ -97,8 +97,8 @@ QUnit.module('Views', {
"the 2 records of the second group have now been loaded");
// quick create in second column
- testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new'));
- assert.hasClass(kanban.$('.o_kanban_group:nth(1) > div:nth(1)'), 'o_kanban_quick_create',
+ await testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new'));
+ assert.hasClass(kanban.$('.o_kanban_group:nth(1) > div:nth(1)'),'o_kanban_quick_create',
"clicking on create should open the quick_create in the second column");
// kanban column should match kanban mobile tabs
@@ -118,10 +118,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('mobile grouped with undefined column', function (assert) {
+
+ QUnit.test('mobile grouped with undefined column', async function (assert) {
assert.expect(5);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -155,10 +156,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('mobile grouped on many2one rendering', function (assert) {
+
+ QUnit.test('mobile grouped on many2one rendering', async function (assert) {
assert.expect(5);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -193,10 +195,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('kanban with searchpanel: there should be no searchpanel in mobile', function (assert) {
+ QUnit.test('kanban with searchpanel: there should be no searchpanel in mobile', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
diff --git a/addons/web/static/tests/views/kanban_model_tests.js b/addons/web/static/tests/views/kanban_model_tests.js
index 20eb2918d04..29dd60c3d15 100644
--- a/addons/web/static/tests/views/kanban_model_tests.js
+++ b/addons/web/static/tests/views/kanban_model_tests.js
@@ -57,12 +57,13 @@ QUnit.module('Views', {
openGroupByDefault: true,
viewType: 'kanban',
};
- }
+ },
}, function () {
QUnit.module('KanbanModel');
- QUnit.test('load grouped + add a new group', function (assert) {
+ QUnit.test('load grouped + add a new group', async function (assert) {
+ var done = assert.async();
assert.expect(22);
var calledRoutes = {};
@@ -84,7 +85,7 @@ QUnit.module('Views', {
fieldNames: ['foo'],
});
- model.load(params).then(function (resultID) {
+ model.load(params).then(async function (resultID) {
// various checks on the load result
var state = model.get(resultID);
assert.ok(_.isEqual(state.groupedBy, ['product_id']), 'should be grouped by "product_id"');
@@ -102,7 +103,7 @@ QUnit.module('Views', {
assert.strictEqual(xphoneGroup.limit, 40, 'limit in a group should be 40');
// add a new group
- model.createGroup('xpod', resultID);
+ await model.createGroup('xpod', resultID);
state = model.get(resultID);
assert.strictEqual(state.data.length, 3, 'should now have 3 groups');
assert.strictEqual(state.count, 2, 'there are still 2 records');
@@ -123,10 +124,12 @@ QUnit.module('Views', {
assert.strictEqual(nbSearchRead, 2, 'should have done 2 search_read');
assert.strictEqual(nbNameCreate, 1, 'should have done 1 name_create');
model.destroy();
+ done();
});
});
- QUnit.test('archive/restore a column', function (assert) {
+ QUnit.test('archive/restore a column', async function (assert) {
+ var done = assert.async();
assert.expect(4);
var model = createModel({
@@ -139,7 +142,7 @@ QUnit.module('Views', {
fieldNames: ['foo'],
});
- model.load(params).then(function (resultID) {
+ model.load(params).then(async function (resultID) {
var state = model.get(resultID);
var xphoneGroup = _.findWhere(state.data, {res_id: 37});
var xpadGroup = _.findWhere(state.data, {res_id: 41});
@@ -148,17 +151,19 @@ QUnit.module('Views', {
// archive the column 'xphone'
var recordIDs = _.pluck(xphoneGroup.data, 'id');
- model.toggleActive(recordIDs, false, xphoneGroup.id);
+ await model.toggleActive(recordIDs, false, xphoneGroup.id);
state = model.get(resultID);
xphoneGroup = _.findWhere(state.data, {res_id: 37});
assert.strictEqual(xphoneGroup.count, 0, 'xphone group has no record anymore');
xpadGroup = _.findWhere(state.data, {res_id: 41});
assert.strictEqual(xpadGroup.count, 1, 'xpad group still has one record');
model.destroy();
+ done();
});
});
- QUnit.test('kanban model does not allow nested groups', function (assert) {
+ QUnit.test('kanban model does not allow nested groups', async function (assert) {
+ var done = assert.async();
assert.expect(2);
var model = createModel({
@@ -185,10 +190,11 @@ QUnit.module('Views', {
"the second level of groupBy should have been removed");
model.destroy();
+ done();
});
});
- QUnit.test('resequence columns and records', function (assert) {
+ QUnit.test('resequence columns and records', async function (assert) {
var done = assert.async();
assert.expect(8);
@@ -252,7 +258,8 @@ QUnit.module('Views', {
});
});
- QUnit.test('add record to group', function (assert) {
+ QUnit.test('add record to group', async function (assert) {
+ var done = assert.async();
assert.expect(8);
var self = this;
@@ -289,9 +296,11 @@ QUnit.module('Views', {
assert.strictEqual(state.data[0].data[0].data.foo, 'new record',
"new record should have been fetched");
});
- });
+ }).then(function() {
+ model.destroy();
+ done();
+ })
- model.destroy();
});
});
diff --git a/addons/web/static/tests/views/kanban_tests.js b/addons/web/static/tests/views/kanban_tests.js
index bb2231a025d..956578f2bf8 100644
--- a/addons/web/static/tests/views/kanban_tests.js
+++ b/addons/web/static/tests/views/kanban_tests.js
@@ -11,6 +11,8 @@ var testUtils = require('web.test_utils');
var Widget = require('web.Widget');
var widgetRegistry = require('web.widget_registry');
+var makeTestPromise = testUtils.makeTestPromise;
+var nextTick = testUtils.nextTick;
var createView = testUtils.createView;
QUnit.module('Views', {
@@ -69,10 +71,10 @@ QUnit.module('Views', {
QUnit.module('KanbanView');
- QUnit.test('basic ungrouped rendering', function (assert) {
+ QUnit.test('basic ungrouped rendering', async function (assert) {
assert.expect(5);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -92,10 +94,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('basic grouped rendering', function (assert) {
+ QUnit.test('basic grouped rendering', async function (assert) {
assert.expect(13);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -131,20 +133,21 @@ QUnit.module('Views', {
// the next line makes sure that reload works properly. It looks useless,
// but it actually test that a grouped local record can be reloaded without
// changing its result.
- testUtils.kanban.reload(kanban);
+ await kanban.reload(kanban);
assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 3);
kanban.destroy();
});
- QUnit.test('basic grouped rendering with active field (archivable by default)', function (assert) {
+ QUnit.test('basic grouped rendering with active field (archivable by default)', async function (assert) {
+ // var done = assert.async();
assert.expect(9);
// 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({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -166,28 +169,28 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3);
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
assert.containsOnce(document.body, '.modal', "a confirm modal should be displayed");
- testUtils.modal.clickButton('Cancel');
+ await testUtils.modal.clickButton('Cancel');
assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3, "still last column should contain 3 records");
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
assert.ok($('.modal').length, 'a confirm modal should be displayed');
- testUtils.modal.clickButton('Ok');
+ await testUtils.modal.clickButton('Ok');
assert.containsNone(kanban, '.o_kanban_group:last .o_kanban_record', "last column should not contain any records");
envIDs = [4];
assert.deepEqual(kanban.exportState().resIds, envIDs);
kanban.destroy();
});
- QUnit.test('basic grouped rendering with active field and archive enabled (archivable true)', function (assert) {
+ QUnit.test('basic grouped rendering with active field and archive enabled (archivable true)', async function (assert) {
assert.expect(7);
// 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({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -209,26 +212,26 @@ QUnit.module('Views', {
"last column should contain 3 records");
envIDs = [4];
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
assert.ok($('.modal').length, 'a confirm modal should be displayed');
- testUtils.modal.clickButton('Cancel'); // Click on 'Cancel'
+ await testUtils.modal.clickButton('Cancel'); // Click on 'Cancel'
assert.containsN(kanban, '.o_kanban_group:last .o_kanban_record', 3, "still last column should contain 3 records");
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_archive_records'));
assert.ok($('.modal').length, 'a confirm modal should be displayed');
- testUtils.modal.clickButton('Ok'); // Click on 'Ok'
+ await testUtils.modal.clickButton('Ok'); // Click on 'Ok'
assert.containsNone(kanban, '.o_kanban_group:last .o_kanban_record', "last column should not contain any records");
kanban.destroy();
});
- QUnit.test('basic grouped rendering with active field and hidden archive buttons (archivable false)', function (assert) {
+ QUnit.test('basic grouped rendering with active field and hidden archive buttons (archivable false)', async function (assert) {
assert.expect(2);
// 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({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -251,10 +254,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('context can be used in kanban template', function (assert) {
+ QUnit.test('context can be used in kanban template', async function (assert) {
assert.expect(2);
- var form = createView({
+ var form = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -281,10 +284,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('pager should be hidden in grouped mode', function (assert) {
+ QUnit.test('pager should be hidden in grouped mode', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -295,17 +298,17 @@ QUnit.module('Views', {
'</t></templates></kanban>',
groupBy: ['bar'],
});
- kanban.renderPager();
+ await kanban.renderPager();
assert.isNotVisible(kanban.pager.$el,
"pager should be hidden in grouped kanban");
kanban.destroy();
});
- QUnit.test('pager, ungrouped, with default limit', function (assert) {
+ QUnit.test('pager, ungrouped, with default limit', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -325,10 +328,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('pager, ungrouped, with limit given in options', function (assert) {
+ QUnit.test('pager, ungrouped, with limit given in options', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -350,11 +353,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('pager, ungrouped, with limit set on arch and given in options', function (assert) {
+ QUnit.test('pager, ungrouped, with limit set on arch and given in options', async function (assert) {
assert.expect(3);
// the limit given in the arch should take the priority over the one given in options
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -376,10 +379,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('create in grouped on m2o', function (assert) {
+ QUnit.test('create in grouped on m2o', async function (assert) {
assert.expect(5);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -399,7 +402,7 @@ QUnit.module('Views', {
assert.hasClass(kanban.$('.o_kanban_view > div:last'),'o_column_quick_create',
"column quick create should be enabled when grouped by a many2one field)");
- testUtils.kanban.clickCreate(kanban); // Click on 'Create'
+ await testUtils.kanban.clickCreate(kanban); // Click on 'Create'
assert.hasClass(kanban.$('.o_kanban_group:first() > div:nth(1)'),'o_kanban_quick_create',
"clicking on create should open the quick_create in the first column");
@@ -408,10 +411,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('create in grouped on char', function (assert) {
+ QUnit.test('create in grouped on char', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -433,10 +436,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record without quick_create_view', function (assert) {
+ QUnit.test('quick create record without quick_create_view', async function (assert) {
assert.expect(16);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -460,7 +463,7 @@ QUnit.module('Views', {
"first column should contain one record");
// click on 'Create' -> should open the quick create in the first column
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
assert.strictEqual($quickCreate.length, 1,
@@ -469,14 +472,14 @@ QUnit.module('Views', {
"should have rendered an XXS form view");
assert.strictEqual($quickCreate.find('input').length, 1,
"should have only one input");
- assert.hasClass($quickCreate.find('input'),'o_required_modifier',
+ assert.hasClass($quickCreate.find('input'), 'o_required_modifier',
"the field should be required");
assert.strictEqual($quickCreate.find('input[placeholder=Title]').length, 1,
"input placeholder should be 'Title'");
// fill the quick create and validate
- testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column should contain two records");
@@ -494,10 +497,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record with quick_create_view', function (assert) {
+ QUnit.test('quick create record with quick_create_view', async function (assert) {
assert.expect(19);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -532,7 +535,7 @@ QUnit.module('Views', {
"first column should contain one record");
// click on 'Create' -> should open the quick create in the first column
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
assert.strictEqual($quickCreate.length, 1,
@@ -546,10 +549,10 @@ QUnit.module('Views', {
"should have rendered three widgets");
// fill the quick create and validate
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '4');
- testUtils.dom.click($quickCreate.find('.o_field_widget[name=state] .o_priority_star:first'));
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '4');
+ await testUtils.dom.click($quickCreate.find('.o_field_widget[name=state] .o_priority_star:first'));
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column should contain two records");
@@ -569,10 +572,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped on m2o (no quick_create_view)', function (assert) {
+ QUnit.test('quick create record in grouped on m2o (no quick_create_view)', async function (assert) {
assert.expect(12);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -604,10 +607,10 @@ QUnit.module('Views', {
"first column should contain two records");
// click on 'Create', fill the quick create and validate
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3,
"first column should contain three records");
@@ -625,10 +628,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped on m2o (with quick_create_view)', function (assert) {
+ QUnit.test('quick create record in grouped on m2o (with quick_create_view)', async function (assert) {
assert.expect(14);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -669,12 +672,12 @@ QUnit.module('Views', {
"first column should contain two records");
// click on 'Create', fill the quick create and validate
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '4');
- testUtils.dom.click($quickCreate.find('.o_field_widget[name=state] .o_priority_star:first'));
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '4');
+ await testUtils.dom.click($quickCreate.find('.o_field_widget[name=state] .o_priority_star:first'));
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3,
"first column should contain three records");
@@ -694,7 +697,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record with default values and onchanges', function (assert) {
+ QUnit.test('quick create record with default values and onchanges', async function (assert) {
assert.expect(11);
this.data.partner.fields.int_field.default = 4;
@@ -706,7 +709,7 @@ QUnit.module('Views', {
},
};
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -729,16 +732,17 @@ QUnit.module('Views', {
});
// click on 'Create' -> should open the quick create in the first column
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
+ var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
assert.strictEqual($quickCreate.length, 1,
"should have a quick create element in the first column");
assert.strictEqual($quickCreate.find('.o_field_widget[name=int_field]').val(), '4',
"default value should be set");
// fill the 'foo' field -> should trigger the onchange
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
assert.strictEqual($quickCreate.find('.o_field_widget[name=int_field]').val(), '8',
"onchange should have been triggered");
@@ -756,10 +760,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record with quick_create_view: modifiers', function (assert) {
+ QUnit.test('quick create record with quick_create_view: modifiers', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -778,7 +782,7 @@ QUnit.module('Views', {
});
// create a new record
- testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_quick_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_quick_add'));
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
assert.hasClass($quickCreate.find('.o_field_widget[name=foo]'),'o_required_modifier',
@@ -787,7 +791,7 @@ QUnit.module('Views', {
"int_field should be invisible");
// fill 'foo' field
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=foo]'), 'new partner');
assert.doesNotHaveClass($quickCreate.find('.o_field_widget[name=int_field]'), 'o_invisible_modifier',
"int_field should now be visible");
@@ -795,7 +799,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record and change state in grouped mode', function (assert) {
+ QUnit.test('quick create record and change state in grouped mode', async function (assert) {
assert.expect(1);
this.data.partner.fields.kanban_state = {
@@ -804,7 +808,7 @@ QUnit.module('Views', {
selection: [["normal", "Grey"], ["done", "Green"], ["blocked", "Red"]],
};
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -820,24 +824,24 @@ QUnit.module('Views', {
});
// Quick create kanban record
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
var $quickAdd = kanban.$('.o_kanban_quick_create');
$quickAdd.find('.o_input').val('Test');
- testUtils.dom.click($quickAdd.find('.o_kanban_add'));
+ await testUtils.dom.click($quickAdd.find('.o_kanban_add'));
// Select state in kanban
- testUtils.dom.click(kanban.$('.o_status').first());
- testUtils.dom.click(kanban.$('.o_selection .dropdown-item:first'));
+ await testUtils.dom.click(kanban.$('.o_status').first());
+ await testUtils.dom.click(kanban.$('.o_selection .dropdown-item:first'));
assert.hasClass(kanban.$('.o_status').first(),'o_status_green',
"Kanban state should be done (Green)");
kanban.destroy();
});
- QUnit.test('quick create record: cancel and validate without using the buttons', function (assert) {
+ QUnit.test('quick create record: cancel and validate without using the buttons', async function (assert) {
assert.expect(8);
var nbRecords = 4;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -852,7 +856,7 @@ QUnit.module('Views', {
assert.strictEqual(kanban.exportState().resIds.length, nbRecords);
// click to add an element and cancel the quick creation by pressing ESC
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
var $quickCreate = kanban.$('.o_kanban_quick_create');
assert.strictEqual($quickCreate.length, 1, "should have a quick create element");
@@ -865,18 +869,18 @@ QUnit.module('Views', {
"should have destroyed the quick create element");
// click to add and element and click outside, should cancel the quick creation
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
- testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
assert.containsNone(kanban, '.o_kanban_quick_create',
"the quick create should be destroyed when the user clicks outside");
// click to really add an element
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
$quickCreate = kanban.$('.o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
+ await testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
// clicking outside should no longer destroy the quick create as it is dirty
- testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
assert.containsOnce(kanban, '.o_kanban_quick_create',
"the quick create should not have been destroyed");
@@ -887,6 +891,7 @@ QUnit.module('Views', {
which: $.ui.keyCode.ENTER,
}));
+ await nextTick();
assert.strictEqual(this.data.partner.records.length, 5,
"should have created a partner");
assert.strictEqual(_.last(this.data.partner.records).name, "new partner",
@@ -896,7 +901,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: validate with ENTER', function (assert) {
+ QUnit.test('quick create record: validate with ENTER', async function (assert) {
// in this test, we accurately mock the behavior of the webclient by specifying a
// fieldDebounce > 0, meaning that the changes in an InputField aren't notified to the model
// on 'input' events, but they wait for the 'change' event (or a call to 'commitChanges',
@@ -906,7 +911,7 @@ QUnit.module('Views', {
// directly
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -929,8 +934,8 @@ QUnit.module('Views', {
"should have 4 records at the beginning");
// add an element and confirm by pressing ENTER
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
- testUtils.kanban.quickCreate(kanban, 'new partner', 'foo');
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.kanban.quickCreate(kanban, 'new partner', 'foo');
// triggers a navigation event, leading to the 'commitChanges' and record creation
assert.containsN(kanban, '.o_kanban_record', 5,
@@ -941,11 +946,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: prevent multiple adds with ENTER', function (assert) {
+ QUnit.test('quick create record: prevent multiple adds with ENTER', async function (assert) {
assert.expect(9);
- var def;
- var kanban = createView({
+ var prom = makeTestPromise();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -969,7 +974,9 @@ QUnit.module('Views', {
var result = this._super.apply(this, arguments);
if (args.method === 'create') {
assert.step('create');
- return $.when(def).then(_.constant(result));
+ return prom.then(function () {
+ return result;
+ });
}
return result;
},
@@ -979,8 +986,7 @@ QUnit.module('Views', {
"should have 4 records at the beginning");
// add an element and press ENTER twice
- def = $.Deferred();
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
var enterEvent = {
keyCode: $.ui.keyCode.ENTER,
which: $.ui.keyCode.ENTER,
@@ -995,10 +1001,11 @@ QUnit.module('Views', {
"should not have created the record yet");
assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), 'new partner',
"quick create should not be empty yet");
- assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled',
+ assert.hasClass(kanban.$('.o_kanban_quick_create'), 'o_disabled',
"quick create should be disabled");
- def.resolve();
+ prom.resolve();
+ await nextTick();
assert.containsN(kanban, '.o_kanban_record', 5,
"should have created a new record");
@@ -1012,11 +1019,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: prevent multiple adds with Add clicked', function (assert) {
+ QUnit.test('quick create record: prevent multiple adds with Add clicked', async function (assert) {
assert.expect(9);
- var def;
- var kanban = createView({
+ var prom = makeTestPromise();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1036,7 +1043,9 @@ QUnit.module('Views', {
var result = this._super.apply(this, arguments);
if (args.method === 'create') {
assert.step('create');
- return $.when(def).then(_.constant(result));
+ return prom.then(function () {
+ return result;
+ });
}
return result;
},
@@ -1046,11 +1055,10 @@ QUnit.module('Views', {
"should have 4 records at the beginning");
// add an element and click 'Add' twice
- def = $.Deferred();
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create').find('input[name=foo]'), 'new partner');
- testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add'));
- testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create').find('input[name=foo]'), 'new partner');
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_record', 4,
"should not have created the record yet");
@@ -1059,8 +1067,9 @@ QUnit.module('Views', {
assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled',
"quick create should be disabled");
- def.resolve();
+ prom.resolve();
+ await nextTick();
assert.containsN(kanban, '.o_kanban_record', 5,
"should have created a new record");
assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '',
@@ -1073,7 +1082,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: prevent multiple adds with ENTER, with onchange', function (assert) {
+ QUnit.test('quick create record: prevent multiple adds with ENTER, with onchange', async function (assert) {
assert.expect(13);
this.data.partner.onchanges = {
@@ -1081,8 +1090,9 @@ QUnit.module('Views', {
obj.int_field += (obj.foo ? 3 : 0);
},
};
- var def;
- var kanban = createView({
+ var shouldDelayOnchange = false;
+ var prom = makeTestPromise();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1102,7 +1112,11 @@ QUnit.module('Views', {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
assert.step('onchange');
- return $.when(def).then(_.constant(result));
+ if (shouldDelayOnchange) {
+ return Promise.resolve(prom).then(function () {
+ return result
+ });
+ }
}
if (args.method === 'create') {
assert.step('create');
@@ -1123,8 +1137,8 @@ QUnit.module('Views', {
"should have 4 records at the beginning");
// add an element and press ENTER twice
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
- def = $.Deferred();
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ shouldDelayOnchange = true;
var enterEvent = {
keyCode: $.ui.keyCode.ENTER,
which: $.ui.keyCode.ENTER,
@@ -1143,8 +1157,9 @@ QUnit.module('Views', {
assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled',
"quick create should be disabled");
- def.resolve();
+ prom.resolve();
+ await nextTick();
assert.containsN(kanban, '.o_kanban_record', 5,
"should have created a new record");
assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '',
@@ -1162,7 +1177,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: click Add to create, with delayed onchange', function (assert) {
+ QUnit.test('quick create record: click Add to create, with delayed onchange', async function (assert) {
assert.expect(13);
this.data.partner.onchanges = {
@@ -1170,8 +1185,9 @@ QUnit.module('Views', {
obj.int_field += (obj.foo ? 3 : 0);
},
};
- var def;
- var kanban = createView({
+ var shouldDelayOnchange = false;
+ var prom = makeTestPromise();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1191,7 +1207,11 @@ QUnit.module('Views', {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
assert.step('onchange');
- return $.when(def).then(_.constant(result));
+ if (shouldDelayOnchange) {
+ return Promise.resolve(prom).then(function () {
+ return result
+ });
+ }
}
if (args.method === 'create') {
assert.step('create');
@@ -1208,10 +1228,10 @@ QUnit.module('Views', {
"should have 4 records at the beginning");
// add an element and click 'add'
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
- def = $.Deferred();
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create').find('input[name=foo]'), 'new partner');
- testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ shouldDelayOnchange = true;
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create').find('input[name=foo]'), 'new partner');
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_create').find('.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_record', 4,
"should not have created the record yet");
@@ -1220,8 +1240,9 @@ QUnit.module('Views', {
assert.hasClass(kanban.$('.o_kanban_quick_create'),'o_disabled',
"quick create should be disabled");
- def.resolve(); // the onchange returns
+ prom.resolve(); // the onchange returns
+ await nextTick();
assert.containsN(kanban, '.o_kanban_record', 5,
"should have created a new record");
assert.strictEqual(kanban.$('.o_kanban_quick_create input[name=foo]').val(), '',
@@ -1239,10 +1260,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create when first column is folded', function (assert) {
+ QUnit.test('quick create when first column is folded', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1259,13 +1280,13 @@ QUnit.module('Views', {
// fold the first column
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:first'));
- testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold'));
assert.hasClass(kanban.$('.o_kanban_group:first'),'o_column_folded',
"first column should be folded");
// click on 'Create' to open the quick create in the first column
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
assert.doesNotHaveClass(kanban.$('.o_kanban_group:first'), 'o_column_folded',
"first column should no longer be folded");
@@ -1275,7 +1296,7 @@ QUnit.module('Views', {
// fold again the first column
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:first'));
- testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:first .o_kanban_toggle_fold'));
assert.hasClass(kanban.$('.o_kanban_group:first'),'o_column_folded',
"first column should be folded");
@@ -1285,10 +1306,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: cancel when not dirty', function (assert) {
+ QUnit.test('quick create record: cancel when not dirty', async function (assert) {
assert.expect(9);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1304,22 +1325,22 @@ QUnit.module('Views', {
"first column should contain one record");
// click to add an element
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have open the quick create widget");
// click again to add an element -> should have kept the quick create open
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have kept the quick create open");
// click outside: should remove the quick create
- testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
assert.containsNone(kanban, '.o_kanban_quick_create',
"the quick create should not have been destroyed");
// click to reopen the quick create
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have open the quick create widget");
@@ -1332,13 +1353,13 @@ QUnit.module('Views', {
"quick create widget should have been removed");
// click to reopen the quick create
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have open the quick create widget");
// click on 'Discard': should remove the quick create
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
- testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
assert.containsNone(kanban, '.o_kanban_quick_create',
"the quick create should be destroyed when the user clicks outside");
@@ -1348,10 +1369,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record: cancel when dirty', function (assert) {
+ QUnit.test('quick create record: cancel when dirty', async function (assert) {
assert.expect(7);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1367,15 +1388,15 @@ QUnit.module('Views', {
"first column should contain one record");
// click to add an element and edit it
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have open the quick create widget");
var $quickCreate = kanban.$('.o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'some value');
+ await testUtils.fields.editInput($quickCreate.find('input'), 'some value');
// click outside: should not remove the quick create
- testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group .o_kanban_record:first'));
assert.containsOnce(kanban, '.o_kanban_quick_create',
"the quick create should not have been destroyed");
@@ -1388,15 +1409,15 @@ QUnit.module('Views', {
"quick create widget should have been removed");
// click to reopen quick create and edit it
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have open the quick create widget");
$quickCreate = kanban.$('.o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'some value');
+ await testUtils.fields.editInput($quickCreate.find('input'), 'some value');
// click on 'Discard': should remove the quick create
- testUtils.dom.click(kanban.$('.o_kanban_quick_create .o_kanban_cancel'));
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_create .o_kanban_cancel'));
assert.containsNone(kanban, '.o_kanban_quick_create',
"the quick create should be destroyed when the user clicks outside");
@@ -1406,11 +1427,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record and edit in grouped mode', function (assert) {
+ QUnit.test('quick create record and edit in grouped mode', async function (assert) {
assert.expect(6);
var newRecordID;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1444,10 +1465,10 @@ QUnit.module('Views', {
// click to add and edit an element
var $quickCreate = kanban.$('.o_kanban_quick_create');
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
$quickCreate = kanban.$('.o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
- testUtils.dom.click($quickCreate.find('button.o_kanban_edit'));
+ await testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_edit'));
assert.strictEqual(this.data.partner.records.length, 5,
"should have created a partner");
@@ -1459,10 +1480,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create several records in a row', function (assert) {
+ QUnit.test('quick create several records in a row', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1478,12 +1499,12 @@ QUnit.module('Views', {
"first column should contain one record");
// click to add an element, fill the input and press ENTER
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"the quick create should be open");
- testUtils.kanban.quickCreate(kanban, 'new partner 1');
+ await testUtils.kanban.quickCreate(kanban, 'new partner 1');
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column should now contain two records");
@@ -1491,7 +1512,7 @@ QUnit.module('Views', {
"the quick create should still be open");
// create a second element in a row
- testUtils.kanban.quickCreate(kanban, 'new partner 2');
+ await testUtils.kanban.quickCreate(kanban, 'new partner 2');
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3,
"first column should now contain three records");
@@ -1501,11 +1522,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create is disabled until record is created and read', function (assert) {
+ QUnit.test('quick create is disabled until record is created and read', async function (assert) {
assert.expect(6);
- var def;
- var kanban = createView({
+ var prom = makeTestPromise();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1518,7 +1539,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'read') {
- return $.when(def).then(_.constant(result));
+ return prom.then(_.constant(result));
}
return result;
},
@@ -1528,22 +1549,21 @@ QUnit.module('Views', {
"first column should contain one record");
// click to add a record, and add two in a row (first one will be delayed)
- testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
+ await testUtils.dom.click(kanban.$('.o_kanban_header .o_kanban_quick_add i').first());
assert.containsOnce(kanban, '.o_kanban_quick_create',
"the quick create should be open");
- def = $.Deferred();
-
- testUtils.kanban.quickCreate(kanban, 'new partner 1');
+ await testUtils.kanban.quickCreate(kanban, 'new partner 1');
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"first column should still contain one record");
assert.containsOnce(kanban, '.o_kanban_quick_create.o_disabled',
"quick create should be disabled");
- def.resolve();
+ prom.resolve();
+ await nextTick();
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column should now contain two records");
assert.strictEqual(kanban.$('.o_kanban_quick_create:not(.o_disabled)').length, 1,
@@ -1552,10 +1572,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record fail in grouped by many2one', function (assert) {
+ QUnit.test('quick create record fail in grouped by many2one', async function (assert) {
assert.expect(8);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1574,11 +1594,14 @@ QUnit.module('Views', {
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (args.method === 'name_create') {
- return $.Deferred().reject({
- code: 200,
- data: {},
- message: "Odoo server error",
- }, $.Event());
+ return Promise.reject({
+ message: {
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ },
+ event: $.Event()
+ });
}
return this._super.apply(this, arguments);
},
@@ -1587,11 +1610,11 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"there should be 2 records in first column");
- testUtils.kanban.clickCreate(kanban); // Click on 'Create'
+ await testUtils.kanban.clickCreate(kanban); // Click on 'Create'
assert.hasClass(kanban.$('.o_kanban_group:first() > div:nth(1)'),'o_kanban_quick_create',
"clicking on create should open the quick_create in the first column");
- testUtils.kanban.quickCreate(kanban, 'test');
+ await testUtils.kanban.quickCreate(kanban, 'test');
assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1,
"a form view dialog should have been opened (in edit)");
@@ -1599,8 +1622,8 @@ QUnit.module('Views', {
"the correct product_id should already be set");
// specify a name and save
- testUtils.fields.editInput($('.modal input[name=foo]'), 'test');
- testUtils.modal.clickButton('Save');
+ await testUtils.fields.editInput($('.modal input[name=foo]'), 'test');
+ await testUtils.modal.clickButton('Save');
assert.strictEqual($('.modal').length, 0, "the modal should be closed");
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3,
@@ -1614,10 +1637,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record is re-enabled after discard on failure', function (assert) {
+ QUnit.test('quick create record is re-enabled after discard on failure', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1636,26 +1659,29 @@ QUnit.module('Views', {
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (args.method === 'name_create') {
- return $.Deferred().reject({
- code: 200,
- data: {},
- message: "Odoo server error",
- }, $.Event());
+ return Promise.reject({
+ message: {
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ },
+ event: $.Event()
+ });
}
return this._super.apply(this, arguments);
}
});
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
assert.containsOnce(kanban, '.o_kanban_quick_create',
"should have a quick create widget");
- testUtils.kanban.quickCreate(kanban, 'test');
+ await testUtils.kanban.quickCreate(kanban, 'test');
assert.strictEqual($('.modal .o_form_view.o_form_editable').length, 1,
"a form view dialog should have been opened (in edit)");
- testUtils.modal.clickButton('Discard');
+ await testUtils.modal.clickButton('Discard');
assert.strictEqual($('.modal').length, 0, "the modal should be closed");
assert.strictEqual(kanban.$('.o_kanban_quick_create:not(.o_disabled)').length, 1,
@@ -1664,10 +1690,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record fails in grouped by char', function (assert) {
+ QUnit.test('quick create record fails in grouped by char', async function (assert) {
assert.expect(7);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1683,11 +1709,14 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === 'name_create') {
- return $.Deferred().reject({
- code: 200,
- data: {},
- message: "Odoo server error",
- }, $.Event());
+ return Promise.reject({
+ message: {
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ },
+ event: $.Event()
+ });
}
if (args.method === 'create') {
assert.deepEqual(args.args[0], {foo: 'yop'},
@@ -1703,15 +1732,15 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"there should be 1 record in first column");
- testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'test');
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'test');
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
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");
- testUtils.modal.clickButton('Save');
+ await testUtils.modal.clickButton('Save');
assert.strictEqual($('.modal').length, 0, "the modal should be closed");
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
@@ -1720,10 +1749,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record fails in grouped by selection', function (assert) {
+ QUnit.test('quick create record fails in grouped by selection', async function (assert) {
assert.expect(7);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1739,11 +1768,14 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.method === 'name_create') {
- return $.Deferred().reject({
- code: 200,
- data: {},
- message: "Odoo server error",
- }, $.Event());
+ return Promise.reject({
+ message: {
+ code: 200,
+ data: {},
+ message: "Odoo server error",
+ },
+ event: $.Event()
+ });
}
if (args.method === 'create') {
assert.deepEqual(args.args[0], {state: 'abc'},
@@ -1759,16 +1791,16 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"there should be 1 record in first column");
- testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'test');
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'test');
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
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");
- testUtils.modal.clickButton('Save');
+ await testUtils.modal.clickButton('Save');
assert.strictEqual($('.modal').length, 0, "the modal should be closed");
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
@@ -1777,10 +1809,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in empty grouped kanban', function (assert) {
+ QUnit.test('quick create record in empty grouped kanban', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1800,7 +1832,7 @@ QUnit.module('Views', {
{__domain: [['product_id', '=', 3]], product_id_count: 0},
{__domain: [['product_id', '=', 5]], product_id_count: 0},
];
- return $.when(result);
+ return Promise.resolve(result);
}
return this._super.apply(this, arguments);
},
@@ -1811,7 +1843,7 @@ QUnit.module('Views', {
assert.containsNone(kanban, '.o_kanban_record',
"both columns should be empty");
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_quick_create',
"should have opened the quick create in the first column");
@@ -1819,10 +1851,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped on date(time) field', function (assert) {
+ QUnit.test('quick create record in grouped on date(time) field', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1846,27 +1878,27 @@ QUnit.module('Views', {
"quick create should be disabled when grouped on a date field");
// clicking on CREATE in control panel should not open a quick create
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
assert.containsNone(kanban, '.o_kanban_quick_create',
"should not have opened the quick create widget");
- kanban.reload({groupBy: ['datetime']});
+ await kanban.reload({groupBy: ['datetime']});
assert.containsNone(kanban, '.o_kanban_header .o_kanban_quick_add i',
"quick create should be disabled when grouped on a datetime field");
// clicking on CREATE in control panel should not open a quick create
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
assert.containsNone(kanban, '.o_kanban_quick_create',
"should not have opened the quick create widget");
kanban.destroy();
});
- QUnit.test('quick create record feature is properly enabled/disabled at reload', function (assert) {
+ QUnit.test('quick create record feature is properly enabled/disabled at reload', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1881,12 +1913,12 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 3,
"quick create should be enabled when grouped on a char field");
- kanban.reload({groupBy: ['date']});
+ await kanban.reload({groupBy: ['date']});
assert.containsNone(kanban, '.o_kanban_header .o_kanban_quick_add i',
"quick create should now be disabled (grouped on date field)");
- kanban.reload({groupBy: ['bar']});
+ await kanban.reload({groupBy: ['bar']});
assert.containsN(kanban, '.o_kanban_header .o_kanban_quick_add i', 2,
"quick create should be enabled again (grouped on boolean field)");
@@ -1894,10 +1926,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped by char field', function (assert) {
+ QUnit.test('quick create record in grouped by char field', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1921,9 +1953,9 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"first column should contain 1 record");
- testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column should now contain 2 records");
@@ -1931,10 +1963,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped by boolean field', function (assert) {
+ QUnit.test('quick create record in grouped by boolean field', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1958,9 +1990,9 @@ QUnit.module('Views', {
assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 3,
"second column (true) should contain 3 records");
- testUtils.dom.click(kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 4,
"second column (true) should now contain 4 records");
@@ -1968,10 +2000,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped on selection field', function (assert) {
+ QUnit.test('quick create record in grouped on selection field', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1995,9 +2027,9 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"first column (abc) should contain 1 record");
- testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column (abc) should contain 2 records");
@@ -2005,10 +2037,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped by char field (within quick_create_view)', function (assert) {
+ QUnit.test('quick create record in grouped by char field (within quick_create_view)', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2039,10 +2071,10 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"first column should contain 1 record");
- testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
assert.strictEqual(kanban.$('.o_kanban_quick_create input').val(), 'yop',
"should have set the correct foo value by default");
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column should now contain 2 records");
@@ -2050,10 +2082,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped by boolean field (within quick_create_view)', function (assert) {
+ QUnit.test('quick create record in grouped by boolean field (within quick_create_view)', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2084,10 +2116,10 @@ QUnit.module('Views', {
assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 3,
"second column (true) should contain 3 records");
- testUtils.dom.click(kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:nth(1) .o_kanban_quick_add i'));
assert.ok(kanban.$('.o_kanban_quick_create .o_field_boolean input').is(':checked'),
"should have set the correct bar value by default");
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
assert.strictEqual(kanban.$('.o_kanban_group:nth(1) .o_kanban_record').length, 4,
"second column (true) should now contain 4 records");
@@ -2095,10 +2127,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record in grouped by selection field (within quick_create_view)', function (assert) {
+ QUnit.test('quick create record in grouped by selection field (within quick_create_view)', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2129,10 +2161,10 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_group:first .o_kanban_record',
"first column (abc) should contain 1 record");
- testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
+ await testUtils.dom.click(kanban.$('.o_kanban_header:first .o_kanban_quick_add i'));
assert.strictEqual(kanban.$('.o_kanban_quick_create select').val(), '"abc"',
"should have set the correct state value by default");
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 2,
"first column (abc) should now contain 2 records");
@@ -2140,11 +2172,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create record while adding a new column', function (assert) {
+ QUnit.test('quick create record while adding a new column', async function (assert) {
assert.expect(10);
- var def = $.Deferred();
- var kanban = createView({
+ var def = testUtils.makeTestPromise();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2170,17 +2202,17 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_column_quick_create');
assert.isNotVisible(kanban.$('.o_column_quick_create input'));
- testUtils.dom.click(kanban.$('.o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_quick_create_folded'));
assert.isVisible(kanban.$('.o_column_quick_create input'));
- testUtils.fields.editInput(kanban.$('.o_column_quick_create input'), 'new column');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.fields.editInput(kanban.$('.o_column_quick_create input'), 'new column');
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group', 2);
// click to add a new record
- testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new'));
+ await testUtils.dom.click(kanban.$buttons.find('.o-kanban-button-new'));
// should wait for the column to be created (and view to be re-rendered
// before opening the quick create
@@ -2188,20 +2220,20 @@ QUnit.module('Views', {
// unlock column creation
def.resolve();
-
+ await testUtils.nextTick();
assert.containsN(kanban, '.o_kanban_group', 3);
assert.containsOnce(kanban, '.o_kanban_quick_create');
// quick create record in first column
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
- testUtils.dom.click(kanban.$('.o_kanban_quick_create .o_kanban_add'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'new record');
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_create .o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group:first .o_kanban_record', 3);
kanban.destroy();
});
- QUnit.test('many2many_tags in kanban views', function (assert) {
+ QUnit.test('many2many_tags in kanban views', async function (assert) {
assert.expect(12);
this.data.partner.records[0].category_ids = [6, 7];
@@ -2212,7 +2244,7 @@ QUnit.module('Views', {
color: 0,
});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2254,10 +2286,8 @@ QUnit.module('Views', {
'there should be only one tag in second record');
// Write on the record using the priority widget to trigger a re-render in readonly
- testUtils.dom.click(kanban.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').first());
+ await testUtils.dom.click(kanban.$('.o_field_widget.o_priority a.o_priority_star.fa-star-o').first());
assert.verifySteps([
- '/web/dataset/search_read',
- '/web/dataset/call_kw/category/read',
'/web/dataset/call_kw/partner/write',
'/web/dataset/call_kw/partner/read',
'/web/dataset/call_kw/category/read'
@@ -2266,19 +2296,19 @@ QUnit.module('Views', {
'first record should still contain only 2 tags');
// click on a tag (should trigger switch_view)
- testUtils.dom.click(kanban.$('.o_tag:contains(gold):first'));
+ await testUtils.dom.click(kanban.$('.o_tag:contains(gold):first'));
kanban.destroy();
});
- QUnit.test('Do not open record when clicking on `a` with `href`', function (assert) {
+ QUnit.test('Do not open record when clicking on `a` with `href`', async function (assert) {
assert.expect(5);
this.data.partner.records = [
{ id: 1, foo: 'yop' },
];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2331,13 +2361,13 @@ QUnit.module('Views', {
ev.preventDefault();
});
- testUtils.dom.click($testLink);
+ await testUtils.dom.click($testLink);
$(document.body).off('click.o_test');
kanban.destroy();
});
- QUnit.test('o2m loaded in only one batch', function (assert) {
+ QUnit.test('o2m loaded in only one batch', async function (assert) {
assert.expect(9);
this.data.subtask = {
@@ -2357,7 +2387,7 @@ QUnit.module('Views', {
this.data.partner.records[0].subtask_ids = [1];
this.data.partner.records[1].subtask_ids = [2];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2376,7 +2406,7 @@ QUnit.module('Views', {
},
});
- kanban.reload();
+ await kanban.reload();
assert.verifySteps([
'read_group',
'/web/dataset/search_read',
@@ -2390,10 +2420,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('m2m loaded in only one batch', function (assert) {
+ QUnit.test('m2m loaded in only one batch', async function (assert) {
assert.expect(9);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2412,7 +2442,7 @@ QUnit.module('Views', {
},
});
- testUtils.kanban.reload(kanban);
+ await kanban.reload(kanban);
assert.verifySteps([
'read_group',
'/web/dataset/search_read',
@@ -2426,7 +2456,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('fetch reference in only one batch', function (assert) {
+ QUnit.test('fetch reference in only one batch', async function (assert) {
assert.expect(9);
this.data.partner.records[0].ref_product = 'product,3';
@@ -2436,7 +2466,7 @@ QUnit.module('Views', {
type: 'reference',
};
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2455,7 +2485,7 @@ QUnit.module('Views', {
},
});
- kanban.reload();
+ await kanban.reload();
assert.verifySteps([
'read_group',
'/web/dataset/search_read',
@@ -2469,12 +2499,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('wait x2manys batch fetches to re-render', function (assert) {
- assert.expect(4);
+ QUnit.test('wait x2manys batch fetches to re-render', async function (assert) {
+ assert.expect(7);
var done = assert.async();
- var def;
- var kanban = createView({
+ var def = Promise.resolve();
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2490,7 +2520,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super(route, args);
if (args.method === 'read') {
- return $.when(def).then(function() {
+ return def.then(function() {
return result;
});
}
@@ -2498,13 +2528,17 @@ QUnit.module('Views', {
},
});
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
assert.containsN(kanban, '.o_tag', 2);
+ assert.containsN(kanban, '.o_kanban_group', 2);
kanban.update({groupBy: ['state']});
+ def.then(async function () {
+ assert.containsN(kanban, '.o_kanban_group', 2);
+ await testUtils.nextTick();
+ assert.containsN(kanban, '.o_kanban_group', 3);
- def.resolve().then(function () {
assert.containsN(kanban, '.o_tag', 2,
- 'Should display 2 tags after update');
+ 'Should display 2 tags after update');
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_tag').text(),
'gold', 'First category should be \'gold\'');
assert.strictEqual(kanban.$('.o_kanban_group:eq(2) .o_tag').text(),
@@ -2512,20 +2546,22 @@ QUnit.module('Views', {
kanban.destroy();
done();
});
+ await testUtils.nextTick();
+ def.resolve();
});
- QUnit.test('can drag and drop a record from one column to the next', function (assert) {
+ QUnit.test('can drag and drop a record from one column to the next', async function (assert) {
assert.expect(9);
// @todo: remove this resequenceDef whenever the jquery upgrade branch
// is merged. This is currently necessary to simulate the reality: we
// need the click handlers to be executed after the end of the drag and
// drop operation, not before.
- var resequenceDef = $.Deferred();
+ var resequenceDef = testUtils.makeTestPromise();
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({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2554,9 +2590,10 @@ QUnit.module('Views', {
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.dom.dragAndDrop($record, $group, {withTrailingClick: true});
+ await testUtils.dom.dragAndDrop($record, $group, {withTrailingClick: true});
resequenceDef.resolve();
+ await testUtils.nextTick();
assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 3);
assert.containsN(kanban, '.thisiseditable', 4);
@@ -2566,10 +2603,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('drag and drop a record, grouped by selection', function (assert) {
+ QUnit.test('drag and drop a record, grouped by selection', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2584,7 +2621,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
assert.ok(true, "should call resequence");
- return $.when(true);
+ return Promise.resolve(true);
}
if (args.model === 'partner' && args.method === 'write') {
assert.deepEqual(args.args[1], {state: 'def'});
@@ -2597,18 +2634,19 @@ QUnit.module('Views', {
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
- testUtils.dom.dragAndDrop($record, $group);
+ await testUtils.dom.dragAndDrop($record, $group);
+ await nextTick(); // wait for resequence after drag and drop
assert.containsNone(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2);
kanban.destroy();
});
- QUnit.test('prevent drag and drop of record if grouped by readonly', function (assert) {
+ QUnit.test('prevent drag and drop of record if grouped by readonly', async function (assert) {
assert.expect(12);
this.data.partner.fields.foo.readonly = true;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2622,7 +2660,7 @@ QUnit.module('Views', {
'</kanban>',
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
- return $.when();
+ return Promise.resolve();
}
if (args.model === 'partner' && args.method === 'write') {
throw new Error('should not be draggable');
@@ -2631,27 +2669,29 @@ QUnit.module('Views', {
},
});
// simulate an update coming from the searchview, with another groupby given
- kanban.update({groupBy: ['state']});
+ await kanban.update({groupBy: ['state']});
assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsOnce(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record');
// drag&drop a record in another column
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
- testUtils.dom.dragAndDrop($record, $group);
+ await testUtils.dom.dragAndDrop($record, $group);
+ await nextTick(); // wait for resequence after drag and drop
// should not be draggable
assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsOnce(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record');
// simulate an update coming from the searchview, with another groupby given
- kanban.update({groupBy: ['foo']});
+ await kanban.update({groupBy: ['foo']});
assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2);
// drag&drop a record in another column
$record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
$group = kanban.$('.o_kanban_group:nth-child(2)');
- testUtils.dom.dragAndDrop($record, $group);
+ await testUtils.dom.dragAndDrop($record, $group);
+ await nextTick(); // wait for resequence after drag and drop
// should not be draggable
assert.containsOnce(kanban, '.o_kanban_group:nth-child(1) .o_kanban_record');
assert.containsN(kanban, '.o_kanban_group:nth-child(2) .o_kanban_record', 2);
@@ -2661,7 +2701,7 @@ QUnit.module('Views', {
var $record2 = kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(1)');
assert.strictEqual($record1.text(), "blipDEF", "first record should be DEF");
assert.strictEqual($record2.text(), "blipGHI", "second record should be GHI");
- testUtils.dom.dragAndDrop($record2, $record1, {position: 'top'});
+ await testUtils.dom.dragAndDrop($record2, $record1, {position: 'top'});
// should still be able to resequence
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(2) .o_kanban_record:eq(0)').text(), "blipGHI",
"records should have been resequenced");
@@ -2671,7 +2711,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('prevent drag and drop if grouped by date/datetime field', function (assert) {
+ QUnit.test('prevent drag and drop if grouped by date/datetime field', async function (assert) {
assert.expect(5);
this.data.partner.records[0].date = '2017-01-08';
@@ -2679,7 +2719,7 @@ QUnit.module('Views', {
this.data.partner.records[2].date = '2017-02-08';
this.data.partner.records[3].date = '2017-02-10';
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2700,7 +2740,7 @@ QUnit.module('Views', {
// drag&drop a record in another column
var $record = kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record:first');
var $group = kanban.$('.o_kanban_group:nth-child(2)');
- testUtils.dragAndDrop($record, $group);
+ await testUtils.dragAndDrop($record, $group);
// should not drag&drop record
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length , 2,
@@ -2710,13 +2750,13 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('kanban view with default_group_by', function (assert) {
+ QUnit.test('kanban view with default_group_by', async function (assert) {
assert.expect(7);
this.data.partner.records.product_id = 1;
this.data.product.records.push({id: 1, display_name: "third product"});
var readGroupCount = 0;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2746,19 +2786,19 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_group', 2, "should have " + 2 + " columns");
// simulate an update coming from the searchview, with another groupby given
- kanban.update({groupBy: ['product_id']});
+ await kanban.update({groupBy: ['product_id']});
assert.containsN(kanban, '.o_kanban_group', 2, "should now have " + 3 + " columns");
// simulate an update coming from the searchview, removing the previously set groupby
- kanban.update({groupBy: []});
+ await kanban.update({groupBy: []});
assert.containsN(kanban, '.o_kanban_group', 2, "should have " + 2 + " columns again");
kanban.destroy();
});
- QUnit.test('kanban view with create=False', function (assert) {
+ QUnit.test('kanban view with create=False', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2773,10 +2813,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('clicking on a link triggers correct event', function (assert) {
+ QUnit.test('clicking on a link triggers correct event', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2793,15 +2833,15 @@ QUnit.module('Views', {
model: 'partner',
});
});
- testUtils.dom.click(kanban.$('a').first());
+ await testUtils.dom.click(kanban.$('a').first());
kanban.destroy();
});
- QUnit.test('environment is updated when (un)folding groups', function (assert) {
+ QUnit.test('environment is updated when (un)folding groups', async 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({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2819,24 +2859,24 @@ QUnit.module('Views', {
// fold the second group and check that the res_ids it contains are no
// longer in the environment
envIDs = [1, 3];
- testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_kanban_toggle_fold'));
+ await testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_kanban_toggle_fold'));
assert.deepEqual(kanban.exportState().resIds, envIDs);
// re-open the second group and check that the res_ids it contains are
// back in the environment
envIDs = [1, 3, 2, 4];
- testUtils.dom.click(kanban.$('.o_kanban_group:last'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last'));
assert.deepEqual(kanban.exportState().resIds, envIDs);
kanban.destroy();
});
- QUnit.test('create a column in grouped on m2o', function (assert) {
+ QUnit.test('create a column in grouped on m2o', async function (assert) {
assert.expect(14);
var nbRPCs = 0;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2855,7 +2895,7 @@ QUnit.module('Views', {
//Create column will call resequence to set column order
if (route === '/web/dataset/resequence') {
assert.ok(true, "should call resequence");
- return $.when(true);
+ return Promise.resolve(true);
}
return this._super(route, args);
},
@@ -2864,25 +2904,25 @@ QUnit.module('Views', {
assert.notOk(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should not be visible");
- testUtils.dom.click(kanban.$('.o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_quick_create_folded'));
assert.ok(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should be visible");
// discard the column creation and click it again
- kanban.$('.o_column_quick_create input').trigger($.Event('keydown', {
+ await kanban.$('.o_column_quick_create input').trigger($.Event('keydown', {
keyCode: $.ui.keyCode.ESCAPE,
which: $.ui.keyCode.ESCAPE,
}));
assert.notOk(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should not be visible after discard");
- testUtils.dom.click(kanban.$('.o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_quick_create_folded'));
assert.ok(kanban.$('.o_column_quick_create input').is(':visible'),
"the input should be visible");
- kanban.$('.o_column_quick_create input').val('new value');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await kanban.$('.o_column_quick_create input').val('new value').trigger('input');
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new value)').length, 1,
"the last column should be the newly created one");
@@ -2893,22 +2933,22 @@ QUnit.module('Views', {
// fold and unfold the created column, and check that no RPC is done (as there is no record)
nbRPCs = 0;
- testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_kanban_toggle_fold'));
+ await testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_kanban_toggle_fold'));
assert.hasClass(kanban.$('.o_kanban_group:last'),'o_column_folded',
'the created column should now be folded');
- testUtils.dom.click(kanban.$('.o_kanban_group:last'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last'));
assert.doesNotHaveClass(kanban.$('.o_kanban_group:last'), 'o_column_folded');
assert.strictEqual(nbRPCs, 0, 'no rpc should have been done when folding/unfolding');
// quick create a record
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
assert.hasClass(kanban.$('.o_kanban_group:first() > div:nth(1)'),'o_kanban_quick_create',
"clicking on create should open the quick_create in the first column");
kanban.destroy();
});
- QUnit.test('auto fold group when reach the limit', function (assert) {
+ QUnit.test('auto fold group when reach the limit', async function (assert) {
assert.expect(9);
var data = this.data;
@@ -2924,7 +2964,7 @@ QUnit.module('Views', {
});
}
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: data,
@@ -2965,10 +3005,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('hide and display help message (ESC) in kanban quick create', function (assert) {
+ QUnit.test('hide and display help message (ESC) in kanban quick create', async function (assert) {
assert.expect(2);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -2981,20 +3021,20 @@ QUnit.module('Views', {
groupBy: ['product_id'],
});
- testUtils.dom.click(kanban.$('.o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_quick_create_folded'));
assert.ok(kanban.$('.o_discard_msg').is(':visible'),
'the ESC to discard message is visible');
// click outside the column (to lose focus)
- testUtils.dom.clickFirst(kanban.$('.o_kanban_header'));
+ await testUtils.dom.clickFirst(kanban.$('.o_kanban_header'));
assert.notOk(kanban.$('.o_discard_msg').is(':visible'),
'the ESC to discard message is no longer visible');
kanban.destroy();
});
- QUnit.test('delete a column in grouped on m2o', function (assert) {
- assert.expect(36);
+ QUnit.test('delete a column in grouped on m2o', async function (assert) {
+ assert.expect(37);
testUtils.mock.patch(KanbanRenderer, {
_renderGrouped: function () {
@@ -3008,7 +3048,7 @@ QUnit.module('Views', {
var resequencedIDs;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3024,7 +3064,7 @@ QUnit.module('Views', {
resequencedIDs = args.ids;
assert.strictEqual(_.reject(args.ids, _.isNumber).length, 0,
"column resequenced should be existing records with IDs");
- return $.when(true);
+ return Promise.resolve(true);
}
if (args.method) {
assert.step(args.method);
@@ -3056,15 +3096,15 @@ QUnit.module('Views', {
// delete second column (first cancel the confirm request, then confirm)
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete'));
assert.ok($('.modal').length, 'a confirm modal should be displayed');
- testUtils.modal.clickButton('Cancel'); // click on cancel
+ await testUtils.modal.clickButton('Cancel'); // click on cancel
assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 5,
'column [5, "xmo"] should still be there');
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete'));
assert.ok($('.modal').length, 'a confirm modal should be displayed');
- testUtils.modal.clickButton('Ok'); // click on confirm
+ await testUtils.modal.clickButton('Ok'); // click on confirm
assert.strictEqual(kanban.$('.o_kanban_group:last').data('id'), 3,
'last column should now be [3, "hello"]');
assert.containsN(kanban, '.o_kanban_group', 2, "should still have two columns");
@@ -3084,37 +3124,39 @@ QUnit.module('Views', {
"the old widgets should have been correctly deleted");
// test column drag and drop having an 'Undefined' column
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
kanban.$('.o_kanban_header_title:first'),
kanban.$('.o_kanban_header_title:last'), {position: 'right'}
);
assert.strictEqual(resequencedIDs, undefined,
"resequencing require at least 2 not Undefined columns");
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
kanban.$('.o_column_quick_create input').val('once third column');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
var newColumnID = kanban.$('.o_kanban_group:last').data('id');
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
kanban.$('.o_kanban_header_title:first'),
kanban.$('.o_kanban_header_title:last'), {position: 'right'}
);
assert.deepEqual([3, newColumnID], resequencedIDs,
"moving the Undefined column should not affect order of other columns")
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
kanban.$('.o_kanban_header_title:first'),
kanban.$('.o_kanban_header_title:nth(1)'), {position: 'right'}
);
+ await nextTick(); // wait for resequence after drag and drop
assert.deepEqual([newColumnID, 3], resequencedIDs,
"moved column should be resequenced accordingly")
+ assert.verifySteps(['name_create', 'read', 'read', 'read']);
kanban.destroy();
testUtils.mock.unpatch(KanbanRenderer);
});
- QUnit.test('create a column, delete it and create another one', function (assert) {
+ QUnit.test('create a column, delete it and create another one', async function (assert) {
assert.expect(5);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3129,21 +3171,21 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_group', 2, "should have two columns");
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
kanban.$('.o_column_quick_create input').val('new column 1');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group', 3, "should have two columns");
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:last'));
- testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete'));
- testUtils.modal.clickButton('Ok');
+ await testUtils.dom.click(kanban.$('.o_kanban_group:last .o_column_delete'));
+ await testUtils.modal.clickButton('Ok');
assert.containsN(kanban, '.o_kanban_group', 2, "should have twos columns");
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
kanban.$('.o_column_quick_create input').val('new column 2');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
assert.containsN(kanban, '.o_kanban_group', 3, "should have three columns");
assert.strictEqual(kanban.$('.o_kanban_group:last span:contains(new column 2)').length, 1,
@@ -3151,11 +3193,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('edit a column in grouped on m2o', function (assert) {
+ QUnit.test('edit a column in grouped on m2o', async function (assert) {
assert.expect(12);
var nbRPCs = 0;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3179,14 +3221,14 @@ QUnit.module('Views', {
// edit the title of column [5, 'xmo'] and close without saving
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group[data-id=5]'));
- testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit'));
assert.containsOnce(document.body, '.modal .o_form_editable',
"a form view should be open in a modal");
assert.strictEqual($('.modal .o_form_editable input').val(), 'xmo',
'the name should be "xmo"');
- testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
+ await testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
nbRPCs = 0;
- testUtils.dom.click($('.modal-header .close'));
+ await testUtils.dom.click($('.modal-header .close'));
assert.containsNone(document.body, '.modal');
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo',
'title of the column should still be "xmo"');
@@ -3194,10 +3236,10 @@ QUnit.module('Views', {
// edit the title of column [5, 'xmo'] and discard
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group[data-id=5]'));
- testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit'));
- testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
+ await testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit'));
+ await testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
nbRPCs = 0;
- testUtils.modal.clickButton('Discard');
+ await testUtils.modal.clickButton('Discard');
assert.containsNone(document.body, '.modal');
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'xmo',
'title of the column should still be "xmo"');
@@ -3205,10 +3247,10 @@ QUnit.module('Views', {
// edit the title of column [5, 'xmo'] and save
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group[data-id=5]'));
- testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit'));
- testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
+ await testUtils.dom.click(kanban.$('.o_kanban_group[data-id=5] .o_column_edit'));
+ await testUtils.fields.editInput($('.modal .o_form_editable input'), 'ged'); // change the value
nbRPCs = 0;
- testUtils.modal.clickButton('Save'); // click on save
+ await testUtils.modal.clickButton('Save'); // click on save
assert.ok(!$('.modal').length, 'the modal should be closed');
assert.strictEqual(kanban.$('.o_kanban_group[data-id=5] .o_column_title').text(), 'ged',
'title of the column should be "ged"');
@@ -3216,10 +3258,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create column should be opened if there is no column', function (assert) {
+ QUnit.test('quick create column should be opened if there is no column', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3241,10 +3283,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick create several columns in a row', function (assert) {
+ QUnit.test('quick create several columns in a row', async function (assert) {
assert.expect(10);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3267,13 +3309,13 @@ QUnit.module('Views', {
"the ColumnQuickCreate should be folded");
// add a new column
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
assert.containsNone(kanban, '.o_column_quick_create .o_quick_create_folded:visible',
"the ColumnQuickCreate should be unfolded");
assert.containsOnce(kanban, '.o_column_quick_create .o_quick_create_unfolded:visible',
"the ColumnQuickCreate should be unfolded");
kanban.$('.o_column_quick_create input').val('New Column 1');
- testUtils.dom.click(kanban.$('.o_column_quick_create .btn-primary'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .btn-primary'));
assert.containsN(kanban, '.o_kanban_group', 3,
"should now have three columns");
@@ -3283,14 +3325,14 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_column_quick_create .o_quick_create_unfolded:visible',
"the ColumnQuickCreate should still be unfolded");
kanban.$('.o_column_quick_create input').val('New Column 2');
- testUtils.dom.click(kanban.$('.o_column_quick_create .btn-primary'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .btn-primary'));
assert.containsN(kanban, '.o_kanban_group', 4,
"should now have four columns");
kanban.destroy();
});
- QUnit.test('quick create column and examples', function (assert) {
+ QUnit.test('quick create column and examples', async function (assert) {
assert.expect(12);
kanbanExamplesRegistry.add('test', [{
@@ -3302,7 +3344,7 @@ QUnit.module('Views', {
columns: ["Col 1", "Col 2"],
}]);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3319,13 +3361,13 @@ QUnit.module('Views', {
"should have a ColumnQuickCreate widget");
// open the quick create
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_quick_create_folded'));
assert.containsOnce(kanban, '.o_column_quick_create .o_kanban_examples:visible',
"should have a link to see examples");
// click to see the examples
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_kanban_examples'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_kanban_examples'));
assert.strictEqual($('.modal .o_kanban_examples_dialog').length, 1,
"should have open the examples dialog");
@@ -3355,10 +3397,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('if view was not grouped at start, it can be grouped and ungrouped', function (assert) {
+ QUnit.test('if view was not grouped at start, it can be grouped and ungrouped', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3371,22 +3413,22 @@ QUnit.module('Views', {
});
assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped');
- kanban.update({groupBy: ['product_id']});
+ await kanban.update({groupBy: ['product_id']});
assert.hasClass(kanban.$('.o_kanban_view'),'o_kanban_grouped');
- kanban.update({groupBy: []});
+ await kanban.update({groupBy: []});
assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped');
kanban.destroy();
});
- QUnit.test('no content helper when no data', function (assert) {
+ QUnit.test('no content helper when no data', async function (assert) {
assert.expect(3);
var records = this.data.partner.records;
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3410,17 +3452,17 @@ QUnit.module('Views', {
"should have rendered no content helper from action");
this.data.partner.records = records;
- kanban.reload();
+ await kanban.reload();
assert.containsNone(kanban, '.o_view_nocontent',
"should not display the no content helper");
kanban.destroy();
});
- QUnit.test('no nocontent helper for grouped kanban with empty groups', function (assert) {
+ QUnit.test('no nocontent helper for grouped kanban with empty groups', async function (assert) {
assert.expect(2);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3460,12 +3502,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('no nocontent helper for grouped kanban with no records', function (assert) {
+ QUnit.test('no nocontent helper for grouped kanban with no records', async function (assert) {
assert.expect(4);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3493,12 +3535,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('no nocontent helper is shown when no longer creating column', function (assert) {
+ QUnit.test('no nocontent helper is shown when no longer creating column', async function (assert) {
assert.expect(3);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3520,7 +3562,7 @@ QUnit.module('Views', {
// creating a new column
kanban.$('.o_column_quick_create .o_input').val('applejack');
- testUtils.dom.click(kanban.$('.o_column_quick_create .o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create .o_kanban_add'));
assert.containsNone(kanban, '.o_view_nocontent',
"there should be no nocontent helper (still in 'column creation mode')");
@@ -3537,12 +3579,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('no nocontent helper is hidden when quick creating a column', function (assert) {
+ QUnit.test('no nocontent helper is hidden when quick creating a column', async function (assert) {
assert.expect(2);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3557,7 +3599,7 @@ QUnit.module('Views', {
var result = [
{__domain: [['product_id', '=', 3]], product_id_count: 0, product_id: [3, 'hello']},
];
- return $.when(result);
+ return Promise.resolve(result);
}
return this._super.apply(this, arguments);
},
@@ -3571,7 +3613,7 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_view_nocontent',
"there should be a nocontent helper");
- testUtils.dom.click(kanban.$('.o_kanban_add_column'));
+ await testUtils.dom.click(kanban.$('.o_kanban_add_column'));
assert.containsNone(kanban, '.o_view_nocontent',
"there should be no nocontent helper (we are in 'column creation mode')");
@@ -3579,12 +3621,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('remove nocontent helper after adding a record', function (assert) {
+ QUnit.test('remove nocontent helper after adding a record', async function (assert) {
assert.expect(2);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3599,7 +3641,7 @@ QUnit.module('Views', {
var result = [
{__domain: [['product_id', '=', 3]], product_id_count: 0, product_id: [3, 'hello']},
];
- return $.when(result);
+ return Promise.resolve(result);
}
return this._super.apply(this, arguments);
},
@@ -3614,9 +3656,9 @@ QUnit.module('Views', {
"there should be a nocontent helper");
// add a record
- testUtils.dom.click(kanban.$('.o_kanban_quick_add'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create .o_input'), 'twilight sparkle');
- testUtils.dom.click(kanban.$('.o_kanban_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_add'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create .o_input'), 'twilight sparkle');
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_create button.o_kanban_add'));
assert.containsNone(kanban, '.o_view_nocontent',
"there should be no nocontent helper (there is now one record)");
@@ -3624,12 +3666,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('remove nocontent helper when adding a record', function (assert) {
+ QUnit.test('remove nocontent helper when adding a record', async function (assert) {
assert.expect(2);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3644,7 +3686,7 @@ QUnit.module('Views', {
var result = [
{__domain: [['product_id', '=', 3]], product_id_count: 0, product_id: [3, 'hello']},
];
- return $.when(result);
+ return Promise.resolve(result);
}
return this._super.apply(this, arguments);
},
@@ -3659,8 +3701,8 @@ QUnit.module('Views', {
"there should be a nocontent helper");
// add a record
- testUtils.dom.click(kanban.$('.o_kanban_quick_add'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create .o_input'), 'twilight sparkle');
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_add'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create .o_input'), 'twilight sparkle');
assert.containsNone(kanban, '.o_view_nocontent',
"there should be no nocontent helper (there is now one record)");
@@ -3668,12 +3710,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('nocontent helper is displayed again after canceling quick create', function (assert) {
+ QUnit.test('nocontent helper is displayed again after canceling quick create', async function (assert) {
assert.expect(1);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3688,7 +3730,7 @@ QUnit.module('Views', {
var result = [
{__domain: [['product_id', '=', 3]], product_id_count: 0, product_id: [3, 'hello']},
];
- return $.when(result);
+ return Promise.resolve(result);
}
return this._super.apply(this, arguments);
},
@@ -3700,9 +3742,9 @@ QUnit.module('Views', {
});
// add a record
- testUtils.dom.click(kanban.$('.o_kanban_quick_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_add'));
- testUtils.dom.click(kanban.$('.o_kanban_view'));
+ await testUtils.dom.click(kanban.$('.o_kanban_view'));
assert.containsOnce(kanban, '.o_view_nocontent',
"there should be again a nocontent helper");
@@ -3710,12 +3752,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('nocontent helper for grouped kanban with no records with no group_create', function (assert) {
+ QUnit.test('nocontent helper for grouped kanban with no records with no group_create', async function (assert) {
assert.expect(4);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3743,12 +3785,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('buttons with modifiers', function (assert) {
+ QUnit.test('buttons with modifiers', async function (assert) {
assert.expect(2);
this.data.partner.records[1].bar = false; // so that test is more complete
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: "partner",
data: this.data,
@@ -3774,10 +3816,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('button executes action and reloads', function (assert) {
+ QUnit.test('button executes action and reloads', async function (assert) {
assert.expect(6);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: "partner",
data: this.data,
@@ -3802,10 +3844,10 @@ QUnit.module('Views', {
count++;
event.data.on_closed();
});
- testUtils.dom.click($('button[data-name="a1"]').first());
+ await testUtils.dom.click($('button[data-name="a1"]').first());
assert.strictEqual(count, 1, "should have triggered a execute action");
- testUtils.dom.click($('button[data-name="a1"]').first());
+ await testUtils.dom.click($('button[data-name="a1"]').first());
assert.strictEqual(count, 1, "double-click on kanban actions should be debounced");
assert.verifySteps([
@@ -3816,7 +3858,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('button executes action and check domain', function (assert) {
+ QUnit.test('button executes action and check domain', async function (assert) {
assert.expect(2);
var data = this.data;
@@ -3825,7 +3867,7 @@ QUnit.module('Views', {
data.partner.records[k].active = true;
}
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: "partner",
data: data,
@@ -3846,16 +3888,16 @@ QUnit.module('Views', {
});
assert.strictEqual(kanban.$('.o_kanban_record:contains(yop)').length, 1, "should display 'yop' record");
- testUtils.dom.click(kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_active"]'));
+ await testUtils.dom.click(kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_active"]'));
assert.strictEqual(kanban.$('.o_kanban_record:contains(yop)').length, 0, "should remove 'yop' record from the view");
kanban.destroy();
});
- QUnit.test('button executes action with domain field not in view', function (assert) {
+ QUnit.test('button executes action with domain field not in view', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: "partner",
data: this.data,
@@ -3875,7 +3917,7 @@ QUnit.module('Views', {
});
try {
- testUtils.dom.click(kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_action"]'));
+ await testUtils.dom.click(kanban.$('.o_kanban_record:contains(yop) button[data-name="toggle_action"]'));
assert.strictEqual(true, true, 'Everything went fine');
} catch (e) {
assert.strictEqual(true, false, 'Error triggered at action execution');
@@ -3883,13 +3925,13 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('rendering date and datetime', function (assert) {
+ QUnit.test('rendering date and datetime', async function (assert) {
assert.expect(2);
this.data.partner.records[0].date = "2017-01-25";
this.data.partner.records[1].datetime= "2016-12-12 10:55:05";
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3913,12 +3955,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('evaluate conditions on relational fields', function (assert) {
+ QUnit.test('evaluate conditions on relational fields', async function (assert) {
assert.expect(3);
this.data.partner.records[0].product_id = false;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3944,12 +3986,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('resequence columns in grouped by m2o', function (assert) {
+ QUnit.test('resequence columns in grouped by m2o', async function (assert) {
assert.expect(6);
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({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -3975,7 +4017,8 @@ QUnit.module('Views', {
// 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
+ await nextTick(); // wait for resequencing before re-rendering
+ await kanban.update({}, {reload: false}); // re-render without reloading
assert.strictEqual(kanban.$('.o_kanban_group:first').data('id'), 5,
"first column should be id 5 after resequencing");
@@ -3984,10 +4027,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('properly evaluate more complex domains', function (assert) {
+ QUnit.test('properly evaluate more complex domains', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4011,14 +4054,14 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('edit the kanban color with the colorpicker', function (assert) {
+ QUnit.test('edit the kanban color with the colorpicker', async function (assert) {
assert.expect(5);
var writeOnColor;
this.data.category.records[0].color = 12;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'category',
data: this.data,
@@ -4061,7 +4104,7 @@ QUnit.module('Views', {
// Set a color
testUtils.kanban.toggleRecordDropdown($firstRecord);
- testUtils.dom.click($firstRecord.find('.oe_kanban_colorpicker a.oe_kanban_color_9'));
+ await testUtils.dom.click($firstRecord.find('.oe_kanban_colorpicker a.oe_kanban_color_9'));
assert.ok(writeOnColor, "should write on the color field");
$firstRecord = kanban.$('.o_kanban_record:first()'); // First record is reloaded here
assert.ok($firstRecord.is('.oe_kanban_color_9'),
@@ -4070,11 +4113,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('load more records in column', function (assert) {
- assert.expect(12);
+ QUnit.test('load more records in column', async function (assert) {
+ assert.expect(13);
var envIDs = [1, 2, 4]; // the ids that should be in the environment during this test
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4089,7 +4132,7 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (route === '/web/dataset/search_read') {
- assert.step([args.limit, args.offset]);
+ assert.step(args.limit + ' - ' + args.offset);
}
return this._super.apply(this, arguments);
},
@@ -4101,24 +4144,25 @@ QUnit.module('Views', {
// load more
envIDs = [1, 2, 3, 4]; // id 3 will be loaded
- testUtils.dom.click(kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more'));
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3,
"there should now be 3 records in the column");
- assert.verifySteps([[2, undefined], [2, undefined], [2, 2]],
+ assert.verifySteps(['2 - undefined', '2 - undefined', '2 - 2'],
"the records should be correctly fetched");
assert.deepEqual(kanban.exportState().resIds, envIDs);
// reload
- kanban.reload();
+ await kanban.reload();
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3,
"there should still be 3 records in the column after reload");
assert.deepEqual(kanban.exportState().resIds, envIDs);
+ assert.verifySteps(['4 - undefined', '2 - undefined']);
kanban.destroy();
});
- QUnit.test('load more records in column with x2many', function (assert) {
+ QUnit.test('load more records in column with x2many', async function (assert) {
assert.expect(10);
this.data.partner.records[0].category_ids = [7];
@@ -4128,7 +4172,7 @@ QUnit.module('Views', {
// record [2] will be loaded after
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4146,7 +4190,7 @@ QUnit.module('Views', {
},
mockRPC: function (route, args) {
if (args.model === 'category' && args.method === 'read') {
- assert.step(args.args[0]);
+ assert.step(String(args.args[0]));
}
if (route === '/web/dataset/search_read') {
if (args.limit) {
@@ -4165,25 +4209,25 @@ QUnit.module('Views', {
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 2,
"there should be 2 records in the column");
- assert.verifySteps([[7]], "only the appearing category should be fetched");
+ assert.verifySteps(['7'], "only the appearing category should be fetched");
// load more
- testUtils.dom.click(kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:eq(1)').find('.o_kanban_load_more'));
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_record').length, 3,
"there should now be 3 records in the column");
- assert.verifySteps([[7], [6]], "the other categories should not be fetched");
+ assert.verifySteps(['6'], "the other categories should not be fetched");
kanban.destroy();
});
- QUnit.test('update buttons after column creation', function (assert) {
+ QUnit.test('update buttons after column creation', async function (assert) {
assert.expect(2);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4197,19 +4241,19 @@ QUnit.module('Views', {
assert.isNotVisible(kanban.$buttons.find('.o-kanban-button-new'),
"Create button should be hidden");
- testUtils.dom.click(kanban.$('.o_column_quick_create'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create'));
kanban.$('.o_column_quick_create input').val('new column');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
assert.isVisible(kanban.$buttons.find('.o-kanban-button-new'),
"Create button should now be visible");
kanban.destroy();
});
- QUnit.test('group_by_tooltip option when grouping on a many2one', function (assert) {
+ QUnit.test('group_by_tooltip option when grouping on a many2one', async function (assert) {
assert.expect(12);
delete this.data.partner.records[3].product_id;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4236,7 +4280,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_group', 2, "should have " + 2 + " columns");
// simulate an update coming from the searchview, with another groupby given
- kanban.update({groupBy: ['product_id']});
+ await kanban.update({groupBy: ['product_id']});
assert.containsN(kanban, '.o_kanban_group', 3, "should have " + 3 + " columns");
assert.strictEqual(kanban.$('.o_kanban_group:nth-child(1) .o_kanban_record').length, 1,
"column should contain 1 record(s)");
@@ -4257,12 +4301,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('move a record then put it again in the same column', function (assert) {
+ QUnit.test('move a record then put it again in the same column', async function (assert) {
assert.expect(6);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4274,18 +4318,18 @@ QUnit.module('Views', {
groupBy: ['product_id'],
});
- testUtils.dom.click(kanban.$('.o_column_quick_create'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create'));
kanban.$('.o_column_quick_create input').val('column1');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
- testUtils.dom.click(kanban.$('.o_column_quick_create'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create'));
kanban.$('.o_column_quick_create input').val('column2');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
- testUtils.dom.click(kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_add i'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_add i'));
var $quickCreate = kanban.$('.o_kanban_group:eq(1) .o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('input'), 'new partner');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 0,
"column should contain 0 record");
@@ -4294,7 +4338,8 @@ QUnit.module('Views', {
var $record = kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(0)');
var $group = kanban.$('.o_kanban_group:eq(0)');
- testUtils.dom.dragAndDrop($record, $group);
+ await testUtils.dom.dragAndDrop($record, $group);
+ await nextTick(); // wait for resequencing after drag and drop
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 1,
"column should contain 1 records");
@@ -4304,7 +4349,8 @@ QUnit.module('Views', {
$record = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)');
$group = kanban.$('.o_kanban_group:eq(1)');
- testUtils.dom.dragAndDrop($record, $group);
+ await testUtils.dom.dragAndDrop($record, $group);
+ await nextTick(); // wait for resequencing after drag and drop
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 0,
"column should contain 0 records");
@@ -4313,13 +4359,13 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('resequence a record twice', function (assert) {
+ QUnit.test('resequence a record twice', async function (assert) {
assert.expect(10);
this.data.partner.records = [];
var nbResequence = 0;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4332,25 +4378,25 @@ QUnit.module('Views', {
mockRPC: function (route) {
if (route === '/web/dataset/resequence') {
nbResequence++;
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
});
- testUtils.dom.click(kanban.$('.o_column_quick_create'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create'));
kanban.$('.o_column_quick_create input').val('column1');
- testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_column_quick_create button.o_kanban_add'));
- testUtils.dom.click(kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i'));
var $quickCreate = kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'record1');
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('input'), 'record1');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
- testUtils.dom.click(kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_add i'));
$quickCreate = kanban.$('.o_kanban_group:eq(0) .o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('input'), 'record2');
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('input'), 'record2');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2,
"column should contain 2 records");
@@ -4361,7 +4407,7 @@ QUnit.module('Views', {
var $record1 = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)');
var $record2 = kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)');
- testUtils.dom.dragAndDrop($record1, $record2, {position: 'top'});
+ await testUtils.dom.dragAndDrop($record1, $record2, {position: 'top'});
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2,
"column should contain 2 records");
@@ -4370,7 +4416,7 @@ QUnit.module('Views', {
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(1)').text(), "record2",
"records should be correctly ordered");
- testUtils.dom.dragAndDrop($record2, $record1, {position: 'top'});
+ await testUtils.dom.dragAndDrop($record2, $record1, {position: 'top'});
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_record').length, 2,
"column should contain 2 records");
@@ -4382,7 +4428,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('basic support for widgets', function (assert) {
+ QUnit.test('basic support for widgets', async function (assert) {
assert.expect(1);
var MyWidget = Widget.extend({
@@ -4395,7 +4441,7 @@ QUnit.module('Views', {
});
widgetRegistry.add('test', MyWidget);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4415,10 +4461,10 @@ QUnit.module('Views', {
delete widgetRegistry.map.test;
});
- QUnit.test('column progressbars properly work', function (assert) {
+ QUnit.test('column progressbars properly work', async function (assert) {
assert.expect(2);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4444,10 +4490,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('column progressbars should not crash in non grouped views', function (assert) {
+ QUnit.test('column progressbars should not crash in non grouped views', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4475,10 +4521,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('column progressbars: creating a new column should create a new progressbar', function (assert) {
+ QUnit.test('column progressbars: creating a new column should create a new progressbar', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4499,9 +4545,9 @@ QUnit.module('Views', {
// Create a new column: this should create an empty progressbar
var $columnQuickCreate = kanban.$('.o_column_quick_create');
- testUtils.dom.click($columnQuickCreate.find('.o_quick_create_folded'));
+ await testUtils.dom.click($columnQuickCreate.find('.o_quick_create_folded'));
$columnQuickCreate.find('input').val('test');
- testUtils.dom.click($columnQuickCreate.find('.btn-primary'));
+ await testUtils.dom.click($columnQuickCreate.find('.btn-primary'));
assert.containsN(kanban, '.o_kanban_counter', nbProgressBars + 1,
"a new column with a new column progressbar should have been created");
@@ -4509,10 +4555,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('column progressbars on quick create properly update counter', function (assert) {
+ QUnit.test('column progressbars on quick create properly update counter', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4529,20 +4575,22 @@ QUnit.module('Views', {
});
var initialCount = parseInt(kanban.$('.o_kanban_counter_side:first').text());
- testUtils.dom.click(kanban.$('.o_kanban_quick_add:first'));
- testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'Test');
- testUtils.dom.click(kanban.$('.o_kanban_add'));
+ await testUtils.dom.click(kanban.$('.o_kanban_quick_add:first'));
+ await testUtils.fields.editInput(kanban.$('.o_kanban_quick_create input'), 'Test');
+ await testUtils.dom.click(kanban.$('.o_kanban_add'));
var lastCount = parseInt(kanban.$('.o_kanban_counter_side:first').text());
+ await nextTick(); // await update
+ await nextTick(); // await read
assert.strictEqual(lastCount, initialCount + 1,
"kanban counters should have updated on quick create");
kanban.destroy();
});
- QUnit.test('column progressbars are working with load more', function (assert) {
+ QUnit.test('column progressbars are working with load more', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4560,8 +4608,8 @@ QUnit.module('Views', {
});
// we have 1 record shown, load 2 more and check it worked
- testUtils.dom.click(kanban.$('.o_kanban_group').find('.o_kanban_load_more'));
- testUtils.dom.click(kanban.$('.o_kanban_group').find('.o_kanban_load_more'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group').find('.o_kanban_load_more'));
+ await testUtils.dom.click(kanban.$('.o_kanban_group').find('.o_kanban_load_more'));
var shownIDs = _.map(kanban.$('.o_kanban_record'), function(record) {
return parseInt(record.innerText);
});
@@ -4570,13 +4618,13 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('column progressbars on archiving records update counter', function (assert) {
+ QUnit.test('column progressbars on archiving records update counter', async function (assert) {
assert.expect(4);
// add active field on partner model and make all records active
this.data.partner.fields.active = {string: 'Active', type: 'char', default: true};
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4602,8 +4650,8 @@ QUnit.module('Views', {
// archive all records of the second columns
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:eq(1)'));
- testUtils.dom.click(kanban.$('.o_column_archive_records:visible'));
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.dom.click(kanban.$('.o_column_archive_records:visible'));
+ await testUtils.dom.click($('.modal-footer button:first'));
assert.strictEqual(kanban.$('.o_kanban_group:eq(1) .o_kanban_counter_side').text(), "0",
"counter should contain the correct value");
@@ -4613,13 +4661,13 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('kanban with progressbars: correctly update env when archiving records', function (assert) {
+ QUnit.test('kanban with progressbars: correctly update env when archiving records', async function (assert) {
assert.expect(2);
// add active field on partner model and make all records active
this.data.partner.fields.active = {string: 'Active', type: 'char', default: true};
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4642,18 +4690,18 @@ QUnit.module('Views', {
// archive all records of the first column
testUtils.kanban.toggleGroupSettings(kanban.$('.o_kanban_group:first'));
- testUtils.dom.click(kanban.$('.o_column_archive_records:visible'));
- testUtils.dom.click($('.modal-footer button:first'));
+ await testUtils.dom.click(kanban.$('.o_column_archive_records:visible'));
+ await testUtils.dom.click($('.modal-footer button:first'));
assert.deepEqual(kanban.exportState().resIds, [1, 2, 3]);
kanban.destroy();
});
- QUnit.test('RPCs when (re)loading kanban view progressbars', function (assert) {
+ QUnit.test('RPCs when (re)loading kanban view progressbars', async function (assert) {
assert.expect(9);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4675,30 +4723,30 @@ QUnit.module('Views', {
},
});
- kanban.reload();
+ await kanban.reload();
assert.verifySteps([
// initial load
'read_group',
+ 'read_progress_bar',
'/web/dataset/search_read',
'/web/dataset/search_read',
- 'read_progress_bar',
// reload
'read_group',
+ 'read_progress_bar',
'/web/dataset/search_read',
'/web/dataset/search_read',
- 'read_progress_bar',
]);
kanban.destroy();
});
- QUnit.test('drag & drop records grouped by m2o with progressbar', function (assert) {
+ QUnit.test('drag & drop records grouped by m2o with progressbar', async function (assert) {
assert.expect(4);
this.data.partner.records[0].product_id = false;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4714,7 +4762,7 @@ QUnit.module('Views', {
groupBy: ['product_id'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
- return $.when(true);
+ return Promise.resolve(true);
}
return this._super(route, args);
},
@@ -4723,25 +4771,28 @@ QUnit.module('Views', {
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "1",
"counter should contain the correct value");
- testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)'));
+ await testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)'));
+ await nextTick(); // wait for update resulting from drag and drop
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "0",
"counter should contain the correct value");
- testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(2)'), kanban.$('.o_kanban_group:eq(0)'));
+ await testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(1) .o_kanban_record:eq(2)'), kanban.$('.o_kanban_group:eq(0)'));
+ await nextTick(); // wait for update resulting from drag and drop
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "1",
"counter should contain the correct value");
- testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)'));
+ await testUtils.dom.dragAndDrop(kanban.$('.o_kanban_group:eq(0) .o_kanban_record:eq(0)'), kanban.$('.o_kanban_group:eq(1)'));
+ await nextTick(); // wait for update resulting from drag and drop
assert.strictEqual(kanban.$('.o_kanban_group:eq(0) .o_kanban_counter_side').text(), "0",
"counter should contain the correct value");
kanban.destroy();
});
- QUnit.test('progress bar subgroup count recompute', function (assert) {
+ QUnit.test('progress bar subgroup count recompute', async function (assert) {
assert.expect(2);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4761,7 +4812,7 @@ QUnit.module('Views', {
var initialCount = parseInt($secondGroup.find('.o_kanban_counter_side').text());
assert.strictEqual(initialCount, 3,
"Initial count should be Three");
- testUtils.dom.click($secondGroup.find('.bg-success-full'));
+ await testUtils.dom.click($secondGroup.find('.bg-success-full'));
var lastCount = parseInt($secondGroup.find('.o_kanban_counter_side').text());
assert.strictEqual(lastCount, 1,
"kanban counters should vary according to what subgroup is selected");
@@ -4769,10 +4820,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('column progressbars on quick create with quick_create_view are updated', function (assert) {
+ QUnit.test('column progressbars on quick create with quick_create_view are updated', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4795,11 +4846,11 @@ QUnit.module('Views', {
var initialCount = parseInt(kanban.$('.o_kanban_counter_side:first').text());
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
// fill the quick create and validate
var $quickCreate = kanban.$('.o_kanban_group:first .o_kanban_quick_create');
- testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '44');
- testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
+ await testUtils.fields.editInput($quickCreate.find('.o_field_widget[name=int_field]'), '44');
+ await testUtils.dom.click($quickCreate.find('button.o_kanban_add'));
var lastCount = parseInt(kanban.$('.o_kanban_counter_side:first').text());
assert.strictEqual(lastCount, initialCount + 44,
@@ -4808,10 +4859,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('keep adding quickcreate in first column after a record from this column was moved', function (assert) {
+ QUnit.test('keep adding quickcreate in first column after a record from this column was moved', async function (assert) {
assert.expect(2);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4825,7 +4876,7 @@ QUnit.module('Views', {
groupBy: ['foo'],
mockRPC: function (route, args) {
if (route === '/web/dataset/resequence') {
- return $.when(true);
+ return Promise.resolve(true);
}
return this._super(route, args);
},
@@ -4833,13 +4884,13 @@ QUnit.module('Views', {
var $quickCreateGroup;
var $groups;
- _quickCreateAndTest();
- testUtils.dom.dragAndDrop($groups.first().find('.o_kanban_record:first'), $groups.eq(1));
- _quickCreateAndTest();
+ await _quickCreateAndTest();
+ await testUtils.dom.dragAndDrop($groups.first().find('.o_kanban_record:first'), $groups.eq(1));
+ await _quickCreateAndTest();
kanban.destroy();
- function _quickCreateAndTest() {
- testUtils.kanban.clickCreate(kanban);
+ async function _quickCreateAndTest() {
+ await testUtils.kanban.clickCreate(kanban);
$quickCreateGroup = kanban.$('.o_kanban_quick_create').closest('.o_kanban_group');
$groups = kanban.$('.o_kanban_group');
assert.strictEqual($quickCreateGroup[0], $groups[0],
@@ -4847,10 +4898,10 @@ QUnit.module('Views', {
}
});
- QUnit.test('test displaying image (URL)', function (assert) {
+ QUnit.test('test displaying image (URL)', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4869,10 +4920,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('test displaying image (binary & placeholder)', function (assert) {
+ QUnit.test('test displaying image (binary & placeholder)', async function (assert) {
assert.expect(2);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4886,7 +4937,7 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
if (route === 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACAA==') {
assert.ok("The view's image should have been fetched.");
- return $.when();
+ return Promise.resolve();
}
return this._super.apply(this, arguments);
},
@@ -4899,7 +4950,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
assert.expect(1);
var instanceNumber = 0;
@@ -4936,13 +4987,13 @@ QUnit.module('Views', {
'</kanban>',
};
- var kanban = createView(params);
+ var kanban = await createView(params);
kanban.destroy();
var initialInstanceNumber = instanceNumber;
instanceNumber = 0;
- kanban = createView(params);
+ kanban = await createView(params);
// call destroy function of controller to ensure that it correctly destroys everything
kanban.__destroy();
@@ -4956,15 +5007,15 @@ QUnit.module('Views', {
testUtils.mock.unpatch(mixins.ParentedMixin);
});
- QUnit.test('grouped kanban becomes ungrouped when clearing domain then clearing groupby', function (assert) {
+ QUnit.test('grouped kanban becomes ungrouped when clearing domain then clearing groupby', async function (assert) {
// in this test, we simulate that clearing the domain is slow, so that
// clearing the groupby does not corrupt the data handled while
// reloading the kanban view.
assert.expect(4);
- var def = $.Deferred();
+ var prom = makeTestPromise();
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -4982,7 +5033,9 @@ QUnit.module('Views', {
args.kwargs.groupby &&
args.kwargs.groupby[0] === 'bar';
if (isFirstUpdate) {
- return def.then(_.constant(result));
+ return prom.then(function () {
+ return result;
+ });
}
}
return result;
@@ -4996,8 +5049,9 @@ QUnit.module('Views', {
kanban.update({domain: []}); // 1st update on kanban view
kanban.update({groupBy: false}); // 2n update on kanban view
- def.resolve(); // simulate slow 1st update of kanban view
+ prom.resolve(); // simulate slow 1st update of kanban view
+ await nextTick();
assert.doesNotHaveClass(kanban.$('.o_kanban_view'), 'o_kanban_grouped',
"the kanban view should not longer be grouped");
assert.hasClass(kanban.$('.o_kanban_view'),'o_kanban_ungrouped',
@@ -5006,10 +5060,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('quick_create on grouped kanban without column', function (assert) {
+ QUnit.test('quick_create on grouped kanban without column', async function (assert) {
assert.expect(1);
this.data.partner.records = [];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -5027,14 +5081,14 @@ QUnit.module('Views', {
},
},
});
- testUtils.kanban.clickCreate(kanban);
+ await testUtils.kanban.clickCreate(kanban);
kanban.destroy();
});
- QUnit.test('keyboard navigation on kanban basic rendering', function (assert) {
+ QUnit.test('keyboard navigation on kanban basic rendering', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -5060,10 +5114,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('keyboard navigation on kanban grouped rendering', function (assert) {
+ QUnit.test('keyboard navigation on kanban grouped rendering', async function (assert) {
assert.expect(3);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -5096,13 +5150,13 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('keyboard navigation on kanban grouped rendering with empty columns', function (assert) {
+ QUnit.test('keyboard navigation on kanban grouped rendering with empty columns', async function (assert) {
assert.expect(2);
var data = this.data;
data.partner.records[1].state = "abc";
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: data,
@@ -5165,9 +5219,9 @@ QUnit.module('Views', {
});
QUnit.test('keyboard navigation on kanban when the focus is on a link that ' +
- 'has an action and the kanban has no oe_kanban_global_... class', function (assert) {
+ 'has an action and the kanban has no oe_kanban_global_... class', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -5188,18 +5242,19 @@ QUnit.module('Views', {
keyCode: $.ui.keyCode.ENTER,
which: $.ui.keyCode.ENTER,
}));
+ await testUtils.nextTick();
kanban.destroy();
});
- QUnit.test('asynchronous rendering of a field widget (ungrouped)', function (assert) {
- assert.expect(2);
+ QUnit.test('asynchronous rendering of a field widget (ungrouped)', async function (assert) {
+ assert.expect(4);
- var fooFieldDef = $.Deferred();
+ var fooFieldProm = makeTestPromise();
var FieldChar = fieldRegistry.get('char');
fieldRegistry.add('asyncwidget', FieldChar.extend({
willStart: function () {
- return fooFieldDef;
+ return fooFieldProm;
},
start: function () {
this.$el.html('LOADED');
@@ -5207,7 +5262,7 @@ QUnit.module('Views', {
}));
var kanbanController;
- testUtils.createAsyncView({
+ testUtils.createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -5220,21 +5275,33 @@ QUnit.module('Views', {
assert.strictEqual($('.o_kanban_record').length, 0, "kanban view is not ready yet");
- fooFieldDef.resolve();
+ fooFieldProm.resolve();
+ await nextTick();
+ assert.strictEqual($('.o_kanban_record').text(), "LOADEDLOADEDLOADEDLOADED");
+
+ // reload with a domain
+ fooFieldProm = makeTestPromise();
+ kanbanController.reload({domain: [['id', '=', 1]]});
+ await nextTick();
+
assert.strictEqual($('.o_kanban_record').text(), "LOADEDLOADEDLOADEDLOADED");
+ fooFieldProm.resolve();
+ await nextTick();
+ assert.strictEqual($('.o_kanban_record').text(), "LOADED");
+
kanbanController.destroy();
delete fieldRegistry.map.asyncWidget;
});
- QUnit.test('asynchronous rendering of a field widget (grouped)', function (assert) {
- assert.expect(2);
+ QUnit.test('asynchronous rendering of a field widget (grouped)', async function (assert) {
+ assert.expect(4);
- var fooFieldDef = $.Deferred();
+ var fooFieldProm = makeTestPromise();
var FieldChar = fieldRegistry.get('char');
fieldRegistry.add('asyncwidget', FieldChar.extend({
willStart: function () {
- return fooFieldDef;
+ return fooFieldProm;
},
start: function () {
this.$el.html('LOADED');
@@ -5242,7 +5309,7 @@ QUnit.module('Views', {
}));
var kanbanController;
- testUtils.createAsyncView({
+ testUtils.createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -5256,13 +5323,24 @@ QUnit.module('Views', {
assert.strictEqual($('.o_kanban_record').length, 0, "kanban view is not ready yet");
- fooFieldDef.resolve();
+ fooFieldProm.resolve();
+ await nextTick();
+ assert.strictEqual($('.o_kanban_record').text(), "LOADEDLOADEDLOADEDLOADED");
+
+ // reload with a domain
+ fooFieldProm = makeTestPromise();
+ kanbanController.reload({domain: [['id', '=', 1]]});
+ await nextTick();
+
assert.strictEqual($('.o_kanban_record').text(), "LOADEDLOADEDLOADEDLOADED");
+ fooFieldProm.resolve();
+ await nextTick();
+ assert.strictEqual($('.o_kanban_record').text(), "LOADED");
+
kanbanController.destroy();
delete fieldRegistry.map.asyncWidget;
});
-
});
});
diff --git a/addons/web/static/tests/views/list_tests.js b/addons/web/static/tests/views/list_tests.js
index f5e0088173b..3b9e5836cb5 100644
--- a/addons/web/static/tests/views/list_tests.js
+++ b/addons/web/static/tests/views/list_tests.js
@@ -15,6 +15,7 @@ var Widget = require('web.Widget');
var createView = testUtils.createView;
+
QUnit.module('Views', {
beforeEach: function () {
this.data = {
@@ -95,10 +96,10 @@ QUnit.module('Views', {
QUnit.module('ListView');
- QUnit.test('simple readonly list', function (assert) {
+ QUnit.test('simple readonly list', async function (assert) {
assert.expect(10);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -120,19 +121,16 @@ QUnit.module('Views', {
assert.strictEqual(list.$('tbody tr:first td:nth(2)').css('text-align'), 'right',
"integer cells should be right aligned");
- assert.ok(list.$buttons.find('.o_list_button_add').is(':visible'),
- "should have a visible Create button");
- assert.ok(!list.$buttons.find('.o_list_button_save').is(':visible'),
- "should not have a visible save button");
- assert.ok(!list.$buttons.find('.o_list_button_discard').is(':visible'),
- "should not have a visible save button");
+ assert.isVisible(list.$buttons.find('.o_list_button_add'));
+ assert.isNotVisible(list.$buttons.find('.o_list_button_save'));
+ assert.isNotVisible(list.$buttons.find('.o_list_button_discard'));
list.destroy();
});
- QUnit.test('list with create="0"', function (assert) {
+ QUnit.test('list with create="0"', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -141,16 +139,16 @@ QUnit.module('Views', {
assert.hasClass(list.$el,'o_cannot_create',
"should have className 'o_cannot_create'");
- assert.strictEqual(list.$buttons.find('.o_list_button_add').length, 0,
+ assert.containsNone(list.$buttons, '.o_list_button_add',
"should not have the 'Create' button");
list.destroy();
});
- QUnit.test('list with delete="0"', function (assert) {
+ QUnit.test('list with delete="0"', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -161,17 +159,17 @@ QUnit.module('Views', {
assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible');
assert.ok(list.$('tbody td.o_list_record_selector').length, 'should have at least one record');
- testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input'));
+ await testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input'));
assert.isVisible(list.sidebar.$el, 'sidebar should be visible');
assert.notOk(list.sidebar.$('a:contains(Delete)').length, 'sidebar should not have Delete button');
list.destroy();
});
- QUnit.test('simple editable rendering', function (assert) {
+ QUnit.test('simple editable rendering', async function (assert) {
assert.expect(12);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -180,39 +178,39 @@ QUnit.module('Views', {
assert.containsN(list, 'th', 3, "should have 2 th");
assert.containsN(list, 'th', 3, "should have 3 th");
- assert.strictEqual(list.$('td:contains(yop)').length, 1, "should contain yop");
+ assert.containsOnce(list, 'td:contains(yop)', "should contain yop");
- assert.ok(list.$buttons.find('.o_list_button_add').is(':visible'),
+ assert.isVisible(list.$buttons.find('.o_list_button_add'),
"should have a visible Create button");
- assert.ok(!list.$buttons.find('.o_list_button_save').is(':visible'),
+ assert.isNotVisible(list.$buttons.find('.o_list_button_save'),
"should not have a visible save button");
- assert.ok(!list.$buttons.find('.o_list_button_discard').is(':visible'),
+ assert.isNotVisible(list.$buttons.find('.o_list_button_discard'),
"should not have a visible discard button");
- testUtils.dom.click(list.$('td:not(.o_list_record_selector)').first());
+ await testUtils.dom.click(list.$('td:not(.o_list_record_selector)').first());
- assert.ok(!list.$buttons.find('.o_list_button_add').is(':visible'),
+ assert.isNotVisible(list.$buttons.find('.o_list_button_add'),
"should not have a visible Create button");
- assert.ok(list.$buttons.find('.o_list_button_save').is(':visible'),
+ assert.isVisible(list.$buttons.find('.o_list_button_save'),
"should have a visible save button");
- assert.ok(list.$buttons.find('.o_list_button_discard').is(':visible'),
+ assert.isVisible(list.$buttons.find('.o_list_button_discard'),
"should have a visible discard button");
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
- assert.ok(list.$buttons.find('.o_list_button_add').is(':visible'),
+ assert.isVisible(list.$buttons.find('.o_list_button_add'),
"should have a visible Create button");
- assert.ok(!list.$buttons.find('.o_list_button_save').is(':visible'),
+ assert.isNotVisible(list.$buttons.find('.o_list_button_save'),
"should not have a visible save button");
- assert.ok(!list.$buttons.find('.o_list_button_discard').is(':visible'),
+ assert.isNotVisible(list.$buttons.find('.o_list_button_discard'),
"should not have a visible discard button");
list.destroy();
});
- QUnit.test('invisible columns are not displayed', function (assert) {
+ QUnit.test('invisible columns are not displayed', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -227,10 +225,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('record-depending invisible lines are correctly aligned', function (assert) {
+ QUnit.test('record-depending invisible lines are correctly aligned', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -247,17 +245,17 @@ QUnit.module('Views', {
"there should be 1 invisible bar cell");
assert.hasClass(list.$('tbody tr:first td:eq(2)'),'o_invisible_modifier',
"the 3rd cell should be invisible");
- assert.strictEqual(list.$('tbody tr:eq(0) td:visible').length, list.$('tbody tr:eq(1) td:visible').length,
+ assert.containsN(list, 'tbody tr:eq(0) td:visible', list.$('tbody tr:eq(1) td:visible').length,
"there should be the same number of visible cells in different rows");
list.destroy();
});
- QUnit.test('do not perform extra RPC to read invisible many2one fields', function (assert) {
+ QUnit.test('do not perform extra RPC to read invisible many2one fields', async function (assert) {
assert.expect(3);
this.data.foo.fields.m2o.default = 2;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -271,16 +269,16 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.verifySteps(['search_read', 'default_get'], "no nameget should be done");
list.destroy();
});
- QUnit.test('at least 4 rows are rendered, even if less data', function (assert) {
+ QUnit.test('at least 4 rows are rendered, even if less data', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -292,10 +290,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('basic grouped list rendering', function (assert) {
+ QUnit.test('basic grouped list rendering', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -310,10 +308,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('basic grouped list rendering 1 col without selector', function (assert) {
+ QUnit.test('basic grouped list rendering 1 col without selector', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -327,10 +325,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('basic grouped list rendering 1 col with selector', function (assert) {
+ QUnit.test('basic grouped list rendering 1 col with selector', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -344,10 +342,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('basic grouped list rendering 2 col without selector', function (assert) {
+ QUnit.test('basic grouped list rendering 2 col without selector', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -361,10 +359,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('basic grouped list rendering 2 col with selector', function (assert) {
+ QUnit.test('basic grouped list rendering 2 col with selector', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -378,14 +376,14 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('ordered list, sort attribute in context', function (assert) {
+ QUnit.test('ordered list, sort attribute in context', async function (assert) {
assert.expect(1);
// Equivalent to saving a custom filter
this.data.foo.fields.foo.sortable = true;
this.data.foo.fields.date.sortable = true;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -396,11 +394,11 @@ QUnit.module('Views', {
});
// Descending order on Foo
- list.$('th.o_column_sortable:contains("Foo")').click();
- list.$('th.o_column_sortable:contains("Foo")').click();
+ await testUtils.dom.click(list.$('th.o_column_sortable:contains("Foo")'));
+ await testUtils.dom.click(list.$('th.o_column_sortable:contains("Foo")'));
// Ascending order on Date
- list.$('th.o_column_sortable:contains("Date")').click();
+ await testUtils.dom.click(list.$('th.o_column_sortable:contains("Date")'));
var listContext = list.getOwnedQueryParams();
assert.deepEqual(listContext,
@@ -416,14 +414,14 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('loading a filter with a sort attribute', function (assert) {
+ QUnit.test('Loading a filter with a sort attribute', async function (assert) {
assert.expect(2);
this.data.foo.fields.foo.sortable = true;
this.data.foo.fields.date.sortable = true;
var searchReads = 0;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -446,7 +444,7 @@ QUnit.module('Views', {
},
intercepts: {
load_filters: function (event) {
- return $.when([
+ return Promise.resolve([
{
context: "{}",
domain: "[]",
@@ -469,15 +467,15 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$('.o_control_panel .o_search_options button.o_favorites_menu_button'));
- testUtils.dom.click(list.$('.o_control_panel .o_search_options .o_favorites_menu .o_menu_item').eq(1));
+ await testUtils.dom.click(list.$('.o_control_panel .o_search_options button.o_favorites_menu_button'));
+ await testUtils.dom.click(list.$('.o_control_panel .o_search_options .o_favorites_menu .o_menu_item').eq(1));
list.destroy();
});
- QUnit.test('many2one field rendering', function (assert) {
+ QUnit.test('many2one field rendering', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -489,10 +487,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('grouped list view, with 1 open group', function (assert) {
+ QUnit.test('grouped list view, with 1 open group', async function (assert) {
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -500,20 +498,21 @@ QUnit.module('Views', {
groupBy: ['foo'],
});
- testUtils.dom.click(list.$('th.o_group_name:nth(1)'));
- assert.strictEqual(list.$('tbody:eq(1) tr').length, 2, "open group should contain 2 records");
+ await testUtils.dom.click(list.$('th.o_group_name:nth(1)'));
+ await testUtils.nextTick();
+ assert.containsN(list, 'tbody:eq(1) tr', 2, "open group should contain 2 records");
assert.containsN(list, 'tbody', 3, "should contain 3 tbody");
- assert.strictEqual(list.$('td:contains(9)').length, 1, "should contain 9");
- assert.strictEqual(list.$('td:contains(-4)').length, 1, "should contain -4");
- assert.strictEqual(list.$('td:contains(10)').length, 1, "should contain 10");
- assert.strictEqual(list.$('tr.o_group_header td:contains(10)').length, 1, "but 10 should be in a header");
+ assert.containsOnce(list, 'td:contains(9)', "should contain 9");
+ assert.containsOnce(list, 'td:contains(-4)', "should contain -4");
+ assert.containsOnce(list, 'td:contains(10)', "should contain 10");
+ assert.containsOnce(list, 'tr.o_group_header td:contains(10)', "but 10 should be in a header");
list.destroy();
});
- QUnit.test('opening records when clicking on record', function (assert) {
+ QUnit.test('opening records when clicking on record', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -526,19 +525,20 @@ QUnit.module('Views', {
testUtils.dom.click(list.$('tr td:not(.o_list_record_selector)').first());
list.update({groupBy: ['foo']});
+ await testUtils.nextTick();
assert.containsN(list, 'tr.o_group_header', 3, "list should be grouped");
- testUtils.dom.click(list.$('th.o_group_name').first());
+ await testUtils.dom.click(list.$('th.o_group_name').first());
testUtils.dom.click(list.$('tr:not(.o_group_header) td:not(.o_list_record_selector)').first());
list.destroy();
});
- QUnit.test('editable list view: readonly fields cannot be edited', function (assert) {
+ QUnit.test('editable list view: readonly fields cannot be edited', async function (assert) {
assert.expect(4);
this.data.foo.fields.foo.readonly = true;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -551,7 +551,7 @@ QUnit.module('Views', {
var $td = list.$('td:not(.o_list_record_selector)').first();
var $second_td = list.$('td:not(.o_list_record_selector)').eq(1);
var $third_td = list.$('td:not(.o_list_record_selector)').eq(2);
- testUtils.dom.click($td);
+ await testUtils.dom.click($td);
assert.hasClass($td.parent(),'o_selected_row',
"row should be in edit mode");
assert.hasClass($td,'o_readonly_modifier',
@@ -563,7 +563,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list view: line with no active element', function (assert) {
+ QUnit.test('editable list view: line with no active element', async function (assert) {
assert.expect(3);
this.data.bar = {
@@ -578,7 +578,7 @@ QUnit.module('Views', {
};
this.data.foo.records[0].o2m = [1, 2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'foo',
data: this.data,
@@ -606,18 +606,19 @@ QUnit.module('Views', {
var $td2 = form.$('.o_data_cell').eq(1);
assert.hasClass($td, 'o_readonly_modifier');
assert.hasClass($td2, 'o_boolean_toggle_cell');
- testUtils.dom.click($td);
- testUtils.dom.click($td2.find('.o_boolean_toggle input'));
-
- testUtils.form.clickSave(form);
+ await testUtils.dom.click($td);
+ await testUtils.dom.click($td2.find('.o_boolean_toggle input'));
+ await testUtils.nextTick();
+ await testUtils.form.clickSave(form);
+ await testUtils.nextTick();
form.destroy();
});
- QUnit.test('basic operations for editable list renderer', function (assert) {
+ QUnit.test('basic operations for editable list renderer', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -626,12 +627,12 @@ QUnit.module('Views', {
var $td = list.$('td:not(.o_list_record_selector)').first();
assert.doesNotHaveClass($td.parent(), 'o_selected_row', "td should not be in edit mode");
- testUtils.dom.click($td);
+ await testUtils.dom.click($td);
assert.hasClass($td.parent(),'o_selected_row', "td should be in edit mode");
list.destroy();
});
- QUnit.test('editable list: add a line and discard', function (assert) {
+ QUnit.test('editable list: add a line and discard', async function (assert) {
assert.expect(11);
testUtils.mock.patch(basicFields.FieldChar, {
@@ -641,7 +642,7 @@ QUnit.module('Views', {
},
});
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -656,7 +657,7 @@ QUnit.module('Views', {
assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-1',
"pager should be correct");
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.containsN(list, 'tbody tr', 4,
"list should still contain 4 rows");
@@ -665,7 +666,7 @@ QUnit.module('Views', {
assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-2',
"pager should be correct");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
assert.containsN(list, 'tbody tr', 4,
"list should still contain 4 rows");
@@ -680,10 +681,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('field changes are triggered correctly', function (assert) {
+ QUnit.test('field changes are triggered correctly', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -695,30 +696,31 @@ QUnit.module('Views', {
testUtils.mock.intercept(list, "field_changed", function () {
n += 1;
});
- testUtils.dom.click($td);
+ await testUtils.dom.click($td);
testUtils.fields.editInput($td.find('input'), 'abc');
assert.strictEqual(n, 1, "field_changed should have been triggered");
- testUtils.dom.click(list.$('td:not(.o_list_record_selector)').eq(2));
+ await testUtils.dom.click(list.$('td:not(.o_list_record_selector)').eq(2));
assert.strictEqual(n, 1, "field_changed should not have been triggered");
list.destroy();
});
- QUnit.test('editable list view: basic char field edition', function (assert) {
+ QUnit.test('editable list view: basic char field edition', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="bottom"><field name="foo"/><field name="bar"/></tree>',
});
+
var $td = list.$('td:not(.o_list_record_selector)').first();
- testUtils.dom.click($td);
- testUtils.fields.editInput($td.find('input'), 'abc');
+ await testUtils.dom.click($td);
+ await testUtils.fields.editInput($td.find('input'), 'abc');
assert.strictEqual($td.find('input').val(), 'abc', "char field has been edited correctly");
var $next_row_td = list.$('tbody tr:eq(1) td:not(.o_list_record_selector)').first();
- testUtils.dom.click($next_row_td);
+ await testUtils.dom.click($next_row_td);
assert.strictEqual(list.$('td:not(.o_list_record_selector)').first().text(), 'abc',
'changes should be saved correctly');
assert.doesNotHaveClass(list.$('tbody tr').first(), 'o_selected_row',
@@ -728,12 +730,12 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list view: save data when list sorting in edit mode', function (assert) {
+ QUnit.test('editable list view: save data when list sorting in edit mode', async function (assert) {
assert.expect(3);
this.data.foo.fields.foo.sortable = true;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -744,27 +746,27 @@ QUnit.module('Views', {
"should correctly save the edited record");
}
return this._super.apply(this, arguments);
- }
+ },
});
- testUtils.dom.click(list.$('.o_data_cell:first'));
- testUtils.fields.editInput(list.$('input[name="foo"]'), 'xyz');
- testUtils.dom.click(list.$('.o_column_sortable'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.fields.editInput(list.$('input[name="foo"]'), 'xyz');
+ await testUtils.dom.click(list.$('.o_column_sortable'));
assert.hasClass(list.$('.o_data_row:first'),'o_selected_row',
"first row should still be in edition");
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.doesNotHaveClass(list.$buttons, 'o-editing',
"list buttons should be back to their readonly mode");
list.destroy();
});
- QUnit.test('selection changes are triggered correctly', function (assert) {
+ QUnit.test('selection changes are triggered correctly', async function (assert) {
assert.expect(8);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -800,10 +802,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('selection is reset on reload', function (assert) {
+ QUnit.test('selection is reset on reload', async function (assert) {
assert.expect(5);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -824,7 +826,7 @@ QUnit.module('Views', {
"total should be 10 (first record selected)");
// reload
- list.reload();
+ await list.reload();
$firstRowSelector = list.$('tbody .o_list_record_selector input').first();
assert.notOk($firstRowSelector.is(':checked'),
"first row should no longer be selected");
@@ -834,10 +836,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('selection is kept on render without reload', function (assert) {
+ QUnit.test('selection is kept on render without reload', async function (assert) {
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -852,19 +854,19 @@ QUnit.module('Views', {
assert.isNotVisible(list.sidebar);
// open blip grouping and check all lines
- testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
- testUtils.dom.click(list.$('.o_data_row:first input'));
+ await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
+ await testUtils.dom.click(list.$('.o_data_row:first input'));
assert.isVisible(list.sidebar);
// open yop grouping and verify blip are still checked
- testUtils.dom.click(list.$('.o_group_header:contains("yop (1)")'));
+ await testUtils.dom.click(list.$('.o_group_header:contains("yop (1)")'));
assert.containsOnce(list, '.o_data_row input:checked',
"opening a grouping does not uncheck others");
assert.isVisible(list.sidebar);
// close and open blip grouping and verify blip are unchecked
- testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
- testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
+ await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
+ await testUtils.dom.click(list.$('.o_group_header:contains("blip (2)")'));
assert.containsNone(list, '.o_data_row input:checked',
"opening and closing a grouping uncheck its elements");
assert.isNotVisible(list.sidebar);
@@ -872,10 +874,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('aggregates are computed correctly', function (assert) {
+ QUnit.test('aggregates are computed correctly', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -896,16 +898,16 @@ QUnit.module('Views', {
"total should be 32 as all records are selected");
// Let's update the view to dislay NO records
- list.update({domain: ['&', ['bar', '=', false], ['int_field', '>', 0]]});
+ await list.update({domain: ['&', ['bar', '=', false], ['int_field', '>', 0]]});
assert.strictEqual(list.$('tfoot td:nth(2)').text(), "0", "total should have been recomputed to 0");
list.destroy();
});
- QUnit.test('aggregates are computed correctly in grouped lists', function (assert) {
+ QUnit.test('aggregates are computed correctly in grouped lists', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -923,17 +925,17 @@ QUnit.module('Views', {
assert.strictEqual($groupHeader2.find('td:last()').text(), "9", "second group total should be 9");
assert.strictEqual(list.$('tfoot td:last()').text(), "32", "total should be 32");
- testUtils.dom.click($groupHeader1);
- testUtils.dom.click(list.$('tbody .o_list_record_selector input').first());
+ await testUtils.dom.click($groupHeader1);
+ await testUtils.dom.click(list.$('tbody .o_list_record_selector input').first());
assert.strictEqual(list.$('tfoot td:last()').text(), "10",
"total should be 10 as first record of first group is selected");
list.destroy();
});
- QUnit.test('aggregates are updated when a line is edited', function (assert) {
+ QUnit.test('aggregates are updated when a line is edited', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -942,18 +944,18 @@ QUnit.module('Views', {
assert.strictEqual(list.$('td[title="Sum"]').text(), "32", "current total should be 32");
- testUtils.dom.click(list.$('tr.o_data_row td.o_data_cell').first());
- testUtils.fields.editInput(list.$('td.o_data_cell input'), "15");
+ await testUtils.dom.click(list.$('tr.o_data_row td.o_data_cell').first());
+ await testUtils.fields.editInput(list.$('td.o_data_cell input'), "15");
assert.strictEqual(list.$('td[title="Sum"]').text(), "37",
"current total should now be 37");
list.destroy();
});
- QUnit.test('aggregates are formatted according to field widget', function (assert) {
+ QUnit.test('aggregates are formatted according to field widget', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -969,9 +971,9 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('groups can be sorted on aggregates', function (assert) {
+ QUnit.test('groups can be sorted on aggregates', async function (assert) {
assert.expect(10);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -989,12 +991,12 @@ QUnit.module('Views', {
"initial order should be 10, 5, 17");
assert.strictEqual(list.$('tfoot td:last()').text(), '32', "total should be 32");
- testUtils.dom.click(list.$('.o_column_sortable'));
+ await testUtils.dom.click(list.$('.o_column_sortable'));
assert.strictEqual(list.$('tfoot td:last()').text(), '32', "total should still be 32");
assert.strictEqual(list.$('tbody .o_list_number').text(), '51017',
"order should be 5, 10, 17");
- testUtils.dom.click(list.$('.o_column_sortable'));
+ await testUtils.dom.click(list.$('.o_column_sortable'));
assert.strictEqual(list.$('tbody .o_list_number').text(), '17105',
"initial order should be 17, 10, 5");
assert.strictEqual(list.$('tfoot td:last()').text(), '32', "total should still be 32");
@@ -1004,14 +1006,14 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('groups cannot be sorted on non-aggregable fields', function (assert) {
+ QUnit.test('groups cannot be sorted on non-aggregable fields', async function (assert) {
assert.expect(6);
this.data.foo.fields.sort_field = {string: "sortable_field", type: "sting", sortable: true, default: "value"};
_.each(this.data.records, function(elem) {
elem.sort_field = "value" + elem.id;
});
this.data.foo.fields.foo.sortable= true;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1025,13 +1027,13 @@ QUnit.module('Views', {
},
});
//we cannot sort by sort_field since it doesn't have a group_operator
- testUtils.dom.click(list.$('.o_column_sortable:eq(2)'));
+ await testUtils.dom.click(list.$('.o_column_sortable:eq(2)'));
//we can sort by int_field since it has a group_operator
- testUtils.dom.click(list.$('.o_column_sortable:eq(1)'));
+ await testUtils.dom.click(list.$('.o_column_sortable:eq(1)'));
//we keep previous order
- testUtils.dom.click(list.$('.o_column_sortable:eq(2)'));
+ await testUtils.dom.click(list.$('.o_column_sortable:eq(2)'));
//we can sort on foo since we are groupped by foo + previous order
- testUtils.dom.click(list.$('.o_column_sortable:eq(0)'));
+ await testUtils.dom.click(list.$('.o_column_sortable:eq(0)'));
assert.verifySteps([
'default order',
@@ -1045,7 +1047,7 @@ QUnit.module('Views', {
});
- QUnit.test('properly apply onchange in simple case', function (assert) {
+ QUnit.test('properly apply onchange in simple case', async function (assert) {
assert.expect(2);
this.data.foo.onchanges = {
@@ -1053,7 +1055,7 @@ QUnit.module('Views', {
obj.int_field = obj.foo.length + 1000;
},
};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1065,19 +1067,19 @@ QUnit.module('Views', {
assert.strictEqual($int_field_td.text(), '10', "should contain initial value");
- testUtils.dom.click($foo_td);
- testUtils.fields.editInput($foo_td.find('input'), 'tralala');
+ await testUtils.dom.click($foo_td);
+ await testUtils.fields.editInput($foo_td.find('input'), 'tralala');
assert.strictEqual($int_field_td.find('input').val(), "1007",
"should contain input with onchange applied");
list.destroy();
});
- QUnit.test('column width should not change when switching mode', function (assert) {
+ QUnit.test('column width should not change when switching mode', async function (assert) {
assert.expect(4);
// Warning: this test is css dependant
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1093,13 +1095,13 @@ QUnit.module('Views', {
var startWidth = list.$('table').addBack('table').width();
// start edition of first row
- testUtils.dom.click(list.$('td:not(.o_list_record_selector)').first());
+ await testUtils.dom.click(list.$('td:not(.o_list_record_selector)').first());
var editionWidths = _.pluck(list.$('thead th'), 'offsetWidth');
var editionWidth = list.$('table').addBack('table').width();
// leave edition
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
var readonlyWidths = _.pluck(list.$('thead th'), 'offsetWidth');
var readonlyWidth = list.$('table').addBack('table').width();
@@ -1116,10 +1118,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('deleting one record', function (assert) {
+ QUnit.test('deleting one record', async function (assert) {
assert.expect(5);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1130,27 +1132,27 @@ QUnit.module('Views', {
assert.isNotVisible(list.sidebar.$el, 'sidebar should be invisible');
assert.containsN(list, 'tbody td.o_list_record_selector', 4, "should have 4 records");
- testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input'));
+ await testUtils.dom.click(list.$('tbody td.o_list_record_selector:first input'));
assert.isVisible(list.sidebar.$el, 'sidebar should be visible');
- testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(list.sidebar.$('a:contains(Delete)'));
+ await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(list.sidebar.$('a:contains(Delete)'));
assert.hasClass($('body'),'modal-open', 'body should have modal-open clsss');
- testUtils.dom.click($('body .modal button span:contains(Ok)'));
+ await testUtils.dom.click($('body .modal button span:contains(Ok)'));
assert.containsN(list, 'tbody td.o_list_record_selector', 3, "should have 3 records");
list.destroy();
});
- QUnit.test('archiving one record', function (assert) {
+ QUnit.test('archiving one record', async function (assert) {
assert.expect(12);
// add active field on foo model and make all records active
this.data.foo.fields.active = {string: 'Active', type: 'boolean', default: true};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1171,24 +1173,24 @@ QUnit.module('Views', {
assert.verifySteps(['/web/dataset/search_read']);
testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(list.sidebar.$('a:contains(Archive)'));
+ await testUtils.dom.click(list.sidebar.$('a:contains(Archive)'));
assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
testUtils.dom.click($('.modal-footer .btn-secondary'));
assert.containsN(list, 'tbody td.o_list_record_selector', 4, "still should have 4 records");
testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(list.sidebar.$('a:contains(Archive)'));
+ await testUtils.dom.click(list.sidebar.$('a:contains(Archive)'));
assert.strictEqual($('.modal').length, 1, 'a confirm modal should be displayed');
- testUtils.dom.click($('.modal-footer .btn-primary'));
+ await testUtils.dom.click($('.modal-footer .btn-primary'));
assert.containsN(list, 'tbody td.o_list_record_selector', 3, "should have 3 records");
- assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/write', '/web/dataset/search_read']);
+ assert.verifySteps(['/web/dataset/call_kw/foo/write', '/web/dataset/search_read']);
list.destroy();
});
- QUnit.test('pager (ungrouped and grouped mode), default limit', function (assert) {
+ QUnit.test('pager (ungrouped and grouped mode), default limit', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1203,18 +1205,18 @@ QUnit.module('Views', {
assert.isVisible(list.pager.$el, "pager should be visible");
assert.strictEqual(list.pager.state.size, 4, "pager's size should be 4");
- list.update({ groupBy: ['bar']});
+ await list.update({ groupBy: ['bar']});
assert.isNotVisible(list.pager.$el, "pager should be invisible");
list.destroy();
});
- QUnit.test('can sort records when clicking on header', function (assert) {
+ QUnit.test('can sort records when clicking on header', async function (assert) {
assert.expect(9);
this.data.foo.fields.foo.sortable = true;
var nbSearchRead = 0;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1234,7 +1236,7 @@ QUnit.module('Views', {
"record 3 should be first");
nbSearchRead = 0;
- testUtils.dom.click(list.$('thead th:contains(Foo)'));
+ await testUtils.dom.click(list.$('thead th:contains(Foo)'));
assert.strictEqual(nbSearchRead, 1, "should have done one search_read");
assert.ok(list.$('tbody tr:first td:contains(blip)').length,
"record 3 should be first");
@@ -1242,7 +1244,7 @@ QUnit.module('Views', {
"record 1 should be first");
nbSearchRead = 0;
- testUtils.dom.click(list.$('thead th:contains(Foo)'));
+ await testUtils.dom.click(list.$('thead th:contains(Foo)'));
assert.strictEqual(nbSearchRead, 1, "should have done one search_read");
assert.ok(list.$('tbody tr:first td:contains(yop)').length,
"record 3 should be first");
@@ -1252,10 +1254,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('use default_order', function (assert) {
+ QUnit.test('use default_order', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1277,10 +1279,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('use more complex default_order', function (assert) {
+ QUnit.test('use more complex default_order', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1304,12 +1306,12 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('use default_order on editable tree: sort on save', function (assert) {
+ QUnit.test('use default_order on editable tree: sort on save', async function (assert) {
assert.expect(8);
this.data.foo.records[0].o2m = [1, 3];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'foo',
data: this.data,
@@ -1325,15 +1327,15 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('tbody tr:first td:contains(Value 1)').length,
"Value 1 should be first");
assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length,
"Value 3 should be second");
var $o2m = form.$('.o_field_widget[name=o2m]');
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($o2m.find('.o_field_widget'), "Value 2");
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($o2m.find('.o_field_widget'), "Value 2");
assert.ok(form.$('tbody tr:first td:contains(Value 1)').length,
"Value 1 should be first");
assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length,
@@ -1341,7 +1343,7 @@ QUnit.module('Views', {
assert.ok(form.$('tbody tr:eq(2) td input').val(),
"Value 2 should be third (shouldn't be sorted)");
- testUtils.form.clickSave(form);
+ await testUtils.form.clickSave(form);
assert.ok(form.$('tbody tr:first td:contains(Value 1)').length,
"Value 1 should be first");
assert.ok(form.$('tbody tr:eq(1) td:contains(Value 2)').length,
@@ -1352,7 +1354,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('use default_order on editable tree: sort on demand', function (assert) {
+ QUnit.test('use default_order on editable tree: sort on demand', async function (assert) {
assert.expect(11);
this.data.foo.records[0].o2m = [1, 3];
@@ -1360,7 +1362,7 @@ QUnit.module('Views', {
this.data.bar.records[0].name = "Value 1";
this.data.bar.records[2].name = "Value 3";
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'foo',
data: this.data,
@@ -1376,15 +1378,15 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
assert.ok(form.$('tbody tr:first td:contains(Value 1)').length,
"Value 1 should be first");
assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length,
"Value 3 should be second");
var $o2m = form.$('.o_field_widget[name=o2m]');
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.fields.editInput($o2m.find('.o_field_widget'), "Value 2");
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.editInput($o2m.find('.o_field_widget'), "Value 2");
assert.ok(form.$('tbody tr:first td:contains(Value 1)').length,
"Value 1 should be first");
assert.ok(form.$('tbody tr:eq(1) td:contains(Value 3)').length,
@@ -1392,9 +1394,9 @@ QUnit.module('Views', {
assert.ok(form.$('tbody tr:eq(2) td input').val(),
"Value 2 should be third (shouldn't be sorted)");
- testUtils.dom.click(form.$('.o_form_sheet_bg'));
+ await testUtils.dom.click(form.$('.o_form_sheet_bg'));
- testUtils.dom.click($o2m.find('.o_column_sortable'));
+ await testUtils.dom.click($o2m.find('.o_column_sortable'));
assert.strictEqual(form.$('tbody tr:first').text(), 'Value 1',
"Value 1 should be first");
assert.strictEqual(form.$('tbody tr:eq(1)').text(), 'Value 2',
@@ -1402,7 +1404,7 @@ QUnit.module('Views', {
assert.strictEqual(form.$('tbody tr:eq(2)').text(), 'Value 3',
"Value 3 should be third");
- testUtils.dom.click($o2m.find('.o_column_sortable'));
+ await testUtils.dom.click($o2m.find('.o_column_sortable'));
assert.strictEqual(form.$('tbody tr:first').text(), 'Value 3',
"Value 3 should be first");
assert.strictEqual(form.$('tbody tr:eq(1)').text(), 'Value 2',
@@ -1413,7 +1415,7 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('use default_order on editable tree: sort on demand in page', function (assert) {
+ QUnit.test('use default_order on editable tree: sort on demand in page', async function (assert) {
assert.expect(4);
this.data.bar.fields = {name: {string: "Name", type: "char", sortable: true}};
@@ -1429,7 +1431,7 @@ QUnit.module('Views', {
}
this.data.foo.records[0].o2m = ids;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'foo',
data: this.data,
@@ -1446,13 +1448,13 @@ QUnit.module('Views', {
});
// Change page
- testUtils.dom.click(form.$('.o_field_widget[name=o2m] .o_pager_next'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=o2m] .o_pager_next'));
assert.strictEqual(form.$('tbody tr:first').text(), 'Value 44',
"record 44 should be first");
assert.strictEqual(form.$('tbody tr:eq(4)').text(), 'Value 48',
"record 48 should be last");
- testUtils.dom.click(form.$('.o_column_sortable'));
+ await testUtils.dom.click(form.$('.o_column_sortable'));
assert.strictEqual(form.$('tbody tr:first').text(), 'Value 08',
"record 48 should be first");
assert.strictEqual(form.$('tbody tr:eq(4)').text(), 'Value 04',
@@ -1461,10 +1463,10 @@ QUnit.module('Views', {
form.destroy();
});
- QUnit.test('can display button in edit mode', function (assert) {
+ QUnit.test('can display button in edit mode', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1478,10 +1480,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('can display a list with a many2many field', function (assert) {
+ QUnit.test('can display a list with a many2many field', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1499,10 +1501,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list without import button', function (assert) {
+ QUnit.test('list without import button', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1516,13 +1518,13 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('display a tooltip on a field', function (assert) {
+ QUnit.test('display a tooltip on a field', async function (assert) {
assert.expect(2);
var initialDebugMode = config.debug;
config.debug = false;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1538,7 +1540,7 @@ QUnit.module('Views', {
config.debug = true;
// it is necessary to rerender the list so tooltips can be properly created
- list.reload();
+ await list.reload();
list.$('th:not(.o_list_record_selector)').tooltip('show', false);
list.$('th:not(.o_list_record_selector)').trigger($.Event('mouseenter'));
@@ -1548,10 +1550,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('support row decoration', function (assert) {
+ QUnit.test('support row decoration', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1567,12 +1569,12 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('support row decoration (with unset numeric values)', function (assert) {
+ QUnit.test('support row decoration (with unset numeric values)', async function (assert) {
assert.expect(2);
this.data.foo.records = [];
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1581,22 +1583,22 @@ QUnit.module('Views', {
'</tree>',
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.containsNone(list, 'tr.o_data_row.text-danger',
"the data row should not have .text-danger decoration (int_field is unset)");
- testUtils.fields.editInput(list.$('input[name="int_field"]'), '-3');
+ await testUtils.fields.editInput(list.$('input[name="int_field"]'), '-3');
assert.containsOnce(list, 'tr.o_data_row.text-danger',
"the data row should have .text-danger decoration (int_field is negative)");
list.destroy();
});
- QUnit.test('support row decoration with date', function (assert) {
+ QUnit.test('support row decoration with date', async function (assert) {
assert.expect(3);
this.data.foo.records[0].datetime = '2017-02-27 12:51:35';
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1615,14 +1617,14 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('no content helper when no data', function (assert) {
+ QUnit.test('no content helper when no data', async function (assert) {
assert.expect(5);
var records = this.data.foo.records;
this.data.foo.records = [];
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1643,7 +1645,7 @@ QUnit.module('Views', {
"should have rendered no content helper from action");
this.data.foo.records = records;
- list.reload();
+ await list.reload();
assert.containsNone(list, '.o_view_nocontent',
"should not display the no content helper");
@@ -1651,12 +1653,12 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('no nocontent helper when no data and no help', function (assert) {
+ QUnit.test('no nocontent helper when no data and no help', async function (assert) {
assert.expect(3);
this.data.foo.records = [];
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1673,14 +1675,14 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list view, editable, without data', function (assert) {
+ QUnit.test('list view, editable, without data', async function (assert) {
assert.expect(13);
this.data.foo.records = [];
this.data.foo.fields.date.default = "2017-02-10";
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1710,7 +1712,7 @@ QUnit.module('Views', {
"should not have a div.table-responsive");
assert.containsNone(list, 'table', "should not have rendered a table");
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.containsNone(list, '.o_view_nocontent',
"should not have a no content helper displayed");
@@ -1728,7 +1730,7 @@ QUnit.module('Views', {
assert.strictEqual(list.$('.o_list_button button').prop('disabled'), true,
"buttons should be disabled while the record is not yet created");
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('tbody tr:eq(0) .o_list_record_selector input').prop('disabled'), false,
"record selector checkbox should not be disabled once the record is created");
@@ -1738,12 +1740,12 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list view, editable, with a button', function (assert) {
+ QUnit.test('list view, editable, with a button', async function (assert) {
assert.expect(1);
this.data.foo.records = [];
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1753,17 +1755,17 @@ QUnit.module('Views', {
'</tree>',
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.containsOnce(list, 'table button.o_icon_button i.fa-phone',
"should have rendered a button");
list.destroy();
});
- QUnit.test('list view with a button without icon', function (assert) {
+ QUnit.test('list view with a button without icon', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1778,10 +1780,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list view, editable, can discard', function (assert) {
+ QUnit.test('list view, editable, can discard', async function (assert) {
assert.expect(5);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1792,13 +1794,13 @@ QUnit.module('Views', {
assert.strictEqual(list.$('td:not(.o_list_record_selector) input').length, 0, "no input should be in the table");
- testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector):first'));
+ await testUtils.dom.click(list.$('tbody td:not(.o_list_record_selector):first'));
assert.strictEqual(list.$('td:not(.o_list_record_selector) input').length, 1, "first cell should be editable");
assert.ok(list.$buttons.find('.o_list_button_discard').is(':visible'),
"discard button should be visible");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
assert.strictEqual(list.$('td:not(.o_list_record_selector) input').length, 0, "no input should be in the table");
@@ -1807,7 +1809,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list view, click on the list to save', function (assert) {
+ QUnit.test('editable list view, click on the list to save', async function (assert) {
assert.expect(3);
this.data.foo.fields.date.default = "2017-02-10";
@@ -1815,7 +1817,7 @@ QUnit.module('Views', {
var createCount = 0;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1830,27 +1832,27 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
- testUtils.dom.click(list.$('div.table-responsive'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$('div.table-responsive'));
assert.strictEqual(createCount, 1, "should have created a record");
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
- testUtils.dom.click(list.$('tfoot'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$('tfoot'));
assert.strictEqual(createCount, 2, "should have created a record");
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
- testUtils.dom.click(list.$('tbody tr').last());
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$('tbody tr').last());
assert.strictEqual(createCount, 3, "should have created a record");
list.destroy();
});
- QUnit.test('click on a button in a list view', function (assert) {
+ QUnit.test('click on a button in a list view', async function (assert) {
assert.expect(9);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1882,16 +1884,16 @@ QUnit.module('Views', {
assert.containsOnce(list, '.o_list_button:first .o_icon_button .fa.fa-car',
'buttons should have correct icon');
- testUtils.dom.click(list.$('.o_list_button:first > button'));
+ await testUtils.dom.click(list.$('.o_list_button:first > button'));
assert.verifySteps(['/web/dataset/search_read', '/web/dataset/search_read'],
"should have reloaded the view (after the action is complete)");
list.destroy();
});
- QUnit.test('invisible attrs in readonly and editable list', function (assert) {
+ QUnit.test('invisible attrs in readonly and editable list', async function (assert) {
assert.expect(5);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1910,28 +1912,28 @@ QUnit.module('Views', {
"td that contains an invisible button should be empty");
// edit first row
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2)'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2)'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(4) input.o_invisible_modifier').length, 1,
"td that contains an invisible field should not be empty in edition");
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > button.o_invisible_modifier').length, 1,
"td that contains an invisible button should not be empty in edition");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
// click on the invisible field's cell to edit first row
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(4)'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(4)'));
assert.hasClass(list.$('tbody tr:nth(0)'),'o_selected_row',
"first row should be in edition");
list.destroy();
});
- QUnit.test('monetary fields are properly rendered', function (assert) {
+ QUnit.test('monetary fields are properly rendered', async function (assert) {
assert.expect(3);
var currencies = {};
_.each(this.data.res_currency.records, function (currency) {
currencies[currency.id] = currency;
});
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1955,10 +1957,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('simple list with date and datetime', function (assert) {
+ QUnit.test('simple list with date and datetime', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1977,12 +1979,12 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('edit a row by clicking on a readonly field', function (assert) {
+ QUnit.test('edit a row by clicking on a readonly field', async function (assert) {
assert.expect(9);
this.data.foo.fields.foo.readonly = true;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -1993,7 +1995,7 @@ QUnit.module('Views', {
"foo field cells should have class 'o_readonly_modifier'");
// edit the first row
- testUtils.dom.click(list.$('.o_data_row:first td:nth(1)'));
+ await testUtils.dom.click(list.$('.o_data_row:first td:nth(1)'));
assert.hasClass(list.$('.o_data_row:first'),'o_selected_row',
"first row should be selected");
var $cell = list.$('.o_data_row:first td:nth(1)');
@@ -2008,7 +2010,7 @@ QUnit.module('Views', {
"a widget for field 'int_field should have been rendered'");
// click again on readonly cell of first line: nothing should have changed
- testUtils.dom.click(list.$('.o_data_row:first td:nth(1)'));
+ await testUtils.dom.click(list.$('.o_data_row:first td:nth(1)'));
assert.hasClass(list.$('.o_data_row:first'),'o_selected_row',
"first row should be selected");
assert.strictEqual(list.$('.o_data_row:first td:nth(2) input').length, 1,
@@ -2017,7 +2019,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list view with nested groups', function (assert) {
+ QUnit.test('list view with nested groups', async function (assert) {
assert.expect(42);
this.data.foo.records.push({id: 5, foo: "blip", int_field: -7, m2o: 1});
@@ -2026,7 +2028,7 @@ QUnit.module('Views', {
var nbRPCs = {readGroup: 0, searchRead: 0};
var envIDs = []; // the ids that should be in the environment during this test
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2075,7 +2077,7 @@ QUnit.module('Views', {
// open the first group
nbRPCs = {readGroup: 0, searchRead: 0};
- testUtils.dom.click(list.$('.o_group_header:first'));
+ await testUtils.dom.click(list.$('.o_group_header:first'));
assert.strictEqual(nbRPCs.readGroup, 1, "should have done one read_group");
assert.strictEqual(nbRPCs.searchRead, 0, "should have done no search_read");
assert.deepEqual(list.exportState().resIds, envIDs);
@@ -2098,7 +2100,7 @@ QUnit.module('Views', {
// open subgroup
nbRPCs = {readGroup: 0, searchRead: 0};
envIDs = [4, 5]; // the opened subgroup contains these two records
- testUtils.dom.click($openGroup.find('.o_group_header:nth(2)'));
+ await testUtils.dom.click($openGroup.find('.o_group_header:nth(2)'));
assert.strictEqual(nbRPCs.readGroup, 0, "should have done no read_group");
assert.strictEqual(nbRPCs.searchRead, 1, "should have done one search_read");
assert.deepEqual(list.exportState().resIds, envIDs);
@@ -2111,12 +2113,12 @@ QUnit.module('Views', {
"first record in open subgroup should be res_id 4 (with int_field -4)");
// open a record (should trigger event 'open_record')
- testUtils.dom.click($openSubGroup.find('.o_data_row:first'));
+ await testUtils.dom.click($openSubGroup.find('.o_data_row:first'));
// 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
- testUtils.dom.click(list.$('thead th:last'));
+ await testUtils.dom.click(list.$('thead th:last'));
assert.strictEqual(nbRPCs.readGroup, 2, "should have done two read_groups");
assert.strictEqual(nbRPCs.searchRead, 1, "should have done one search_read");
assert.deepEqual(list.exportState().resIds, envIDs);
@@ -2131,7 +2133,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
- testUtils.dom.click(list.$('.o_group_header:nth(1)'));
+ await testUtils.dom.click(list.$('.o_group_header:nth(1)'));
assert.strictEqual(nbRPCs.readGroup, 0, "should have done no read_group");
assert.strictEqual(nbRPCs.searchRead, 0, "should have done no search_read");
assert.deepEqual(list.exportState().resIds, envIDs);
@@ -2145,7 +2147,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('grouped list on selection field at level 2', function (assert) {
+ QUnit.test('grouped list on selection field at level 2', async function (assert) {
assert.expect(4);
this.data.foo.fields.priority = {
@@ -2157,7 +2159,7 @@ QUnit.module('Views', {
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({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2169,7 +2171,7 @@ QUnit.module('Views', {
"should contain 2 groups at first level");
// open the first group
- testUtils.dom.click(list.$('.o_group_header:first'));
+ await testUtils.dom.click(list.$('.o_group_header:first'));
var $openGroup = list.$('tbody:nth(1)');
assert.strictEqual($openGroup.find('tr').length, 3,
@@ -2182,11 +2184,11 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('grouped list with a pager in a group', function (assert) {
+ QUnit.test('grouped list with a pager in a group', async function (assert) {
assert.expect(6);
this.data.foo.records[3].bar = true;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2200,7 +2202,7 @@ QUnit.module('Views', {
var headerHeight = list.$('.o_group_header').css('height');
// basic rendering checks
- testUtils.dom.click(list.$('.o_group_header'));
+ await testUtils.dom.click(list.$('.o_group_header'));
assert.strictEqual(list.$('.o_group_header').css('height'), headerHeight,
"height of group header shouldn't have changed");
assert.hasClass(list.$('.o_group_header td:last'),'o_group_pager',
@@ -2211,7 +2213,7 @@ QUnit.module('Views', {
"open group should display 3 records");
// go to next page
- testUtils.dom.click(list.$('.o_group_header .o_pager_next'));
+ await testUtils.dom.click(list.$('.o_group_header .o_pager_next'));
assert.strictEqual(list.$('.o_group_header .o_pager_value').text(), '4-4',
"pager's value should be correct");
assert.containsOnce(list, '.o_data_row',
@@ -2220,10 +2222,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('edition: create new line, then discard', function (assert) {
+ QUnit.test('edition: create new line, then discard', async function (assert) {
assert.expect(8);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2236,12 +2238,12 @@ QUnit.module('Views', {
"create button should be visible");
assert.strictEqual(list.$buttons.find('.o_list_button_discard:visible').length, 0,
"discard button should be hidden");
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.strictEqual(list.$buttons.find('.o_list_button_add:visible').length, 0,
"create button should be hidden");
assert.strictEqual(list.$buttons.find('.o_list_button_discard:visible').length, 1,
"discard button should be visible");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
assert.containsN(list, 'tr.o_data_row', 4,
"should still have 4 records");
assert.strictEqual(list.$buttons.find('.o_list_button_add:visible').length, 1,
@@ -2251,10 +2253,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('invisible attrs on fields are re-evaluated on field change', function (assert) {
+ QUnit.test('invisible attrs on fields are re-evaluated on field change', async function (assert) {
assert.expect(7);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2269,26 +2271,26 @@ QUnit.module('Views', {
"there should be 3 invisible foo cells in readonly mode");
// Make first line editable
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(1)'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(1)'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"].o_invisible_modifier').length, 1,
"the foo field widget should have been rendered as invisible");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"]:not(.o_invisible_modifier)').length, 1,
"the foo field widget should have been marked as non-invisible");
assert.containsN(list, 'tbody td.o_invisible_modifier', 2,
"the foo field widget parent cell should not be invisible anymore");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"].o_invisible_modifier').length, 1,
"the foo field widget should have been marked as invisible again");
assert.containsN(list, 'tbody td.o_invisible_modifier', 3,
"the foo field widget parent cell should now be invisible again");
// Reswitch the cell to editable and save the row
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
- testUtils.dom.click(list.$('thead'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('thead'));
assert.containsN(list, 'tbody td.o_invisible_modifier', 2,
"there should be 2 invisible foo cells in readonly mode");
@@ -2296,10 +2298,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('readonly attrs on fields are re-evaluated on field change', function (assert) {
+ QUnit.test('readonly attrs on fields are re-evaluated on field change', async function (assert) {
assert.expect(9);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2314,31 +2316,31 @@ QUnit.module('Views', {
"there should be 3 readonly foo cells in readonly mode");
// Make first line editable
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(1)'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(1)'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > span[name="foo"]').length, 1,
"the foo field widget should have been rendered as readonly");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"]').length, 1,
"the foo field widget should have been rerendered as editable");
assert.containsN(list, 'tbody td.o_readonly_modifier', 2,
"the foo field widget parent cell should not be readonly anymore");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > span[name="foo"]').length, 1,
"the foo field widget should have been rerendered as readonly");
assert.containsN(list, 'tbody td.o_readonly_modifier', 3,
"the foo field widget parent cell should now be readonly again");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"]').length, 1,
"the foo field widget should have been rerendered as editable again");
assert.containsN(list, 'tbody td.o_readonly_modifier', 2,
"the foo field widget parent cell should not be readonly again");
// Click outside to leave edition mode
- testUtils.dom.click(list.$el);
+ await testUtils.dom.click(list.$el);
assert.containsN(list, 'tbody td.o_readonly_modifier', 2,
"there should be 2 readonly foo cells in readonly mode");
@@ -2346,10 +2348,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('required attrs on fields are re-evaluated on field change', function (assert) {
+ QUnit.test('required attrs on fields are re-evaluated on field change', async function (assert) {
assert.expect(7);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2364,26 +2366,26 @@ QUnit.module('Views', {
"there should be 3 required foo cells in readonly mode");
// Make first line editable
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(1)'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(1)'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"].o_required_modifier').length, 1,
"the foo field widget should have been rendered as required");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"]:not(.o_required_modifier)').length, 1,
"the foo field widget should have been marked as non-required");
assert.containsN(list, 'tbody td.o_required_modifier', 2,
"the foo field widget parent cell should not be required anymore");
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
assert.strictEqual(list.$('tbody tr:nth(0) td:nth(1) > input[name="foo"].o_required_modifier').length, 1,
"the foo field widget should have been marked as required again");
assert.containsN(list, 'tbody td.o_required_modifier', 3,
"the foo field widget parent cell should now be required again");
// Reswitch the cell to editable and save the row
- testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
- testUtils.dom.click(list.$('thead'));
+ await testUtils.dom.click(list.$('tbody tr:nth(0) td:nth(2) input'));
+ await testUtils.dom.click(list.$('thead'));
assert.containsN(list, 'tbody td.o_required_modifier', 2,
"there should be 2 required foo cells in readonly mode");
@@ -2391,11 +2393,11 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('leaving unvalid rows in edition', function (assert) {
+ QUnit.test('leaving unvalid rows in edition', async function (assert) {
assert.expect(4);
var warnings = 0;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2417,14 +2419,15 @@ QUnit.module('Views', {
// Start first line edition
var $firstFooTd = list.$('tbody tr:nth(0) td:nth(1)');
- testUtils.dom.click($firstFooTd);
+ await testUtils.dom.click($firstFooTd);
// Remove required foo field value
- testUtils.fields.editInput($firstFooTd.find('input'), "")
+ await testUtils.fields.editInput($firstFooTd.find('input'), "");
// Try starting other line edition
var $secondFooTd = list.$('tbody tr:nth(1) td:nth(1)');
- testUtils.dom.click($secondFooTd);
+ await testUtils.dom.click($secondFooTd);
+ await testUtils.nextTick();
assert.strictEqual($firstFooTd.parent('.o_selected_row').length, 1,
"first line should still be in edition as invalid");
@@ -2438,10 +2441,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('open a virtual id', function (assert) {
+ QUnit.test('open a virtual id', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'event',
data: this.data,
@@ -2461,10 +2464,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('pressing enter on last line of editable list view', function (assert) {
+ QUnit.test('pressing enter on last line of editable list view', async function (assert) {
assert.expect(7);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2476,29 +2479,29 @@ QUnit.module('Views', {
});
// click on 3rd line
- testUtils.dom.click(list.$('td:contains(gnap)'));
+ await testUtils.dom.click(list.$('td:contains(gnap)'));
assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row',
"3rd row should be selected");
// press enter in input
- list.$('tr.o_selected_row input').trigger({type: 'keydown', which: 13}); // enter
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter');
assert.hasClass(list.$('tr.o_data_row:eq(3)'),'o_selected_row',
"4rd row should be selected");
assert.doesNotHaveClass(list.$('tr.o_data_row:eq(2)'), 'o_selected_row',
"3rd row should no longer be selected");
// press enter on last row
- list.$('tr.o_selected_row input').trigger({type: 'keydown', which: 13}); // enter
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input'), 'enter');
assert.containsN(list, 'tr.o_data_row', 5, "should have created a 5th row");
assert.verifySteps(['/web/dataset/search_read', '/web/dataset/call_kw/foo/default_get']);
list.destroy();
});
- QUnit.test('pressing tab on last cell of editable list view', function (assert) {
+ QUnit.test('pressing tab on last cell of editable list view', async function (assert) {
assert.expect(9);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2509,7 +2512,7 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$('td:contains(blip)').last());
+ await testUtils.dom.click(list.$('td:contains(blip)').last());
assert.strictEqual(document.activeElement.name, "foo",
"focus should be on an input with name = foo");
@@ -2517,12 +2520,11 @@ QUnit.module('Views', {
document.activeElement.value = "blip-changed";
$(document.activeElement).trigger({type: 'change'});
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: 9}); // tab
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.strictEqual(document.activeElement.name, "int_field",
"focus should be on an input with name = int_field");
- list.$('tr.o_selected_row input[name="int_field"]').trigger({type: 'keydown', which: 9}); // tab
-
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.hasClass(list.$('tr.o_data_row:eq(4)'),'o_selected_row',
"5th row should be selected");
assert.strictEqual(document.activeElement.name, "foo",
@@ -2535,13 +2537,13 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('navigation with tab and read completes after default_get', function (assert) {
+ QUnit.test('navigation with tab and read completes after default_get', async function (assert) {
assert.expect(8);
- var defaultGetDef = $.Deferred();
- var readDef = $.Deferred();
+ var defaultGetPromise = testUtils.makeTestPromise();
+ var readPromise = testUtils.makeTestPromise();
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2552,24 +2554,30 @@ QUnit.module('Views', {
}
var result = this._super.apply(this, arguments);
if (args.method === 'read') {
- return readDef.then(_.constant(result));
+ return readPromise.then(function () {
+ return result;
+ });
}
if (args.method === 'default_get') {
- return defaultGetDef.then(_.constant(result));
+ return defaultGetPromise.then(function () {
+ return result;
+ });
}
return result;
},
});
- testUtils.dom.click(list.$('td:contains(-4)').last());
+ await testUtils.dom.click(list.$('td:contains(-4)').last());
- testUtils.fields.editInput(list.$('tr.o_selected_row input[name="int_field"]'), '1234');
- list.$('tr.o_selected_row input[name="int_field"]').trigger({type: 'keydown', which: 9}); // tab
+ await testUtils.fields.editInput(list.$('tr.o_selected_row input[name="int_field"]'), '1234');
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="int_field"]'), 'tab');
- defaultGetDef.resolve();
+ defaultGetPromise.resolve();
assert.containsN(list, 'tbody tr.o_data_row', 4,
"should have 4 data rows");
- readDef.resolve();
+
+ readPromise.resolve();
+ await testUtils.nextTick();
assert.containsN(list, 'tbody tr.o_data_row', 5,
"should have 5 data rows");
assert.strictEqual(list.$('td:contains(1234)').length, 1,
@@ -2578,7 +2586,7 @@ QUnit.module('Views', {
// we trigger a tab to move to the second cell in the current row. this
// operation requires that this.currentRow is properly set in the
// list editable renderer.
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: 9}); // tab
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.hasClass(list.$('tr.o_data_row:eq(4)'),'o_selected_row',
"5th row should be selected");
@@ -2586,10 +2594,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('display toolbar', function (assert) {
+ QUnit.test('display toolbar', async function (assert) {
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'event',
data: this.data,
@@ -2628,27 +2636,27 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('edit list line after line deletion', function (assert) {
+ QUnit.test('edit list line after line deletion', async function (assert) {
assert.expect(5);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="top"><field name="foo"/><field name="int_field"/></tree>',
});
- testUtils.dom.click(list.$('.o_data_row:nth(2) > td:not(.o_list_record_selector)').first());
+ await testUtils.dom.click(list.$('.o_data_row:nth(2) > td:not(.o_list_record_selector)').first());
assert.ok(list.$('.o_data_row:nth(2)').is('.o_selected_row'),
"third row should be in edition");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.ok(list.$('.o_data_row:nth(0)').is('.o_selected_row'),
"first row should be in edition (creation)");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
assert.containsNone(list, '.o_selected_row',
"no row should be selected");
- testUtils.dom.click(list.$('.o_data_row:nth(2) > td:not(.o_list_record_selector)').first());
+ await testUtils.dom.click(list.$('.o_data_row:nth(2) > td:not(.o_list_record_selector)').first());
assert.ok(list.$('.o_data_row:nth(2)').is('.o_selected_row'),
"third row should be in edition");
assert.containsOnce(list, '.o_selected_row',
@@ -2657,14 +2665,14 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('navigation with tab and readonly field (no modification)', function (assert) {
+ QUnit.test('navigation with tab and readonly field (no modification)', async function (assert) {
// This test makes sure that if we have 2 cells in a row, the first in
// edit mode, and the second one readonly, then if we press TAB when the
// focus is on the first, then the focus skip the readonly cells and
// directly goes to the next line instead.
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2672,31 +2680,30 @@ QUnit.module('Views', {
});
// click on first td and press TAB
- testUtils.dom.click(list.$('td:contains(yop)').last());
+ await testUtils.dom.click(list.$('td:contains(yop)').last());
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.TAB});
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.hasClass(list.$('tr.o_data_row:eq(1)'),'o_selected_row',
"2nd row should be selected");
// we do it again. This was broken because the this.currentRow variable
// was not properly set, and the second TAB could cause a crash.
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.TAB});
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row',
"3rd row should be selected");
list.destroy();
});
-
- QUnit.test('navigation with tab and readonly field (with modification)', function (assert) {
+ QUnit.test('navigation with tab and readonly field (with modification)', async function (assert) {
// This test makes sure that if we have 2 cells in a row, the first in
// edit mode, and the second one readonly, then if we press TAB when the
// focus is on the first, then the focus skips the readonly cells and
// directly goes to the next line instead.
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2704,30 +2711,30 @@ QUnit.module('Views', {
});
// click on first td and press TAB
- testUtils.dom.click(list.$('td:contains(yop)').last());
+ await testUtils.dom.click(list.$('td:contains(yop)'));
//modity the cell content
- document.activeElement.value = "blip-changed";
- $(document.activeElement).trigger({type: 'change'});
+ testUtils.fields.editAndTrigger($(document.activeElement),
+ 'blip-changed', ['change']);
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.TAB});
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.hasClass(list.$('tr.o_data_row:eq(1)'),'o_selected_row',
"2nd row should be selected");
// we do it again. This was broken because the this.currentRow variable
// was not properly set, and the second TAB could cause a crash.
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.TAB});
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.hasClass(list.$('tr.o_data_row:eq(2)'),'o_selected_row',
"3rd row should be selected");
list.destroy();
});
- QUnit.test('navigation with tab on a list with create="0"', function (assert) {
+ QUnit.test('navigation with tab on a list with create="0"', async function (assert) {
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2739,31 +2746,31 @@ QUnit.module('Views', {
assert.containsN(list, '.o_data_row', 4,
"the list should contain 4 rows");
- testUtils.dom.click(list.$('.o_data_row:nth(2) .o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_data_row:nth(2) .o_data_cell:first'));
assert.hasClass(list.$('.o_data_row:nth(2)'),'o_selected_row',
"third row should be in edition");
// Press 'Tab' -> should go to next line
// add a value in the cell because the Tab on an empty first cell would activate the next widget in the view
- testUtils.fields.editInput(list.$('.o_selected_row input').eq(1), 11);
- list.$('.o_selected_row input').trigger({type: 'keydown', which: 9});
+ await testUtils.fields.editInput(list.$('.o_selected_row input').eq(1), 11);
+ await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab');
assert.hasClass(list.$('.o_data_row:nth(3)'),'o_selected_row',
"fourth row should be in edition");
// Press 'Tab' -> should go back to first line as the create action isn't available
- testUtils.fields.editInput(list.$('.o_selected_row input').eq(1), 11);
- list.$('.o_selected_row input').trigger({type: 'keydown', which: 9});
+ await testUtils.fields.editInput(list.$('.o_selected_row input').eq(1), 11);
+ await testUtils.fields.triggerKeydown(list.$('.o_selected_row input'), 'tab');
assert.hasClass(list.$('.o_data_row:first'),'o_selected_row',
"first row should be in edition");
list.destroy();
});
- QUnit.test('navigation with tab on a one2many list with create="0"', function (assert) {
+ QUnit.test('navigation with tab on a one2many list with create="0"', async function (assert) {
assert.expect(4);
this.data.foo.records[0].o2m = [1, 2];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'foo',
data: this.data,
@@ -2784,31 +2791,31 @@ QUnit.module('Views', {
assert.containsN(form, '.o_field_widget[name=o2m] .o_data_row', 2,
"there should be two records in the many2many");
- testUtils.dom.click(form.$('.o_field_widget[name=o2m] .o_data_cell:first'));
+ await testUtils.dom.click(form.$('.o_field_widget[name=o2m] .o_data_cell:first'));
assert.hasClass(form.$('.o_field_widget[name=o2m] .o_data_row:first'),'o_selected_row',
"first row should be in edition");
// Press 'Tab' -> should go to next line
- form.$('.o_field_widget[name=o2m] .o_selected_row input').trigger({type: 'keydown', which: 9});
+ await testUtils.fields.triggerKeydown(form.$('.o_field_widget[name=o2m] .o_selected_row input'), 'tab');
assert.hasClass(form.$('.o_field_widget[name=o2m] .o_data_row:nth(1)'),'o_selected_row',
"second row should be in edition");
// Press 'Tab' -> should get out of the one to many and go to the next field of the form
- form.$('.o_field_widget[name=o2m] .o_selected_row input').trigger({type: 'keydown', which: 9});
+ await testUtils.fields.triggerKeydown(form.$('.o_field_widget[name=o2m] .o_selected_row input'), 'tab');
assert.strictEqual(document.activeElement, form.$('input[name="foo"]')[0],
"the next field should be selected");
form.destroy();
});
- QUnit.test('edition, then navigation with tab (with a readonly field)', function (assert) {
+ QUnit.test('edition, then navigation with tab (with a readonly field)', async function (assert) {
// This test makes sure that if we have 2 cells in a row, the first in
// edit mode, and the second one readonly, then if we edit and press TAB,
// (before debounce), the save operation is properly done (before
// selecting the next row)
assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2823,9 +2830,9 @@ QUnit.module('Views', {
});
// click on first td and press TAB
- testUtils.dom.click(list.$('td:contains(yop)'));
- testUtils.fields.editSelect(list.$('tr.o_selected_row input[name="foo"]'), 'new value');
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.TAB});
+ await testUtils.dom.click(list.$('td:contains(yop)'));
+ await testUtils.fields.editSelect(list.$('tr.o_selected_row input[name="foo"]'), 'new value');
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'tab');
assert.strictEqual(list.$('tbody tr:first td:contains(new value)').length, 1,
"should have the new value visible in dom");
@@ -2833,10 +2840,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('skip invisible fields when navigating list view with TAB', function (assert) {
+ QUnit.test('skip invisible fields when navigating list view with TAB', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2848,20 +2855,20 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.dom.click(list.$('td:contains(gnap)'));
+ await testUtils.dom.click(list.$('td:contains(gnap)'));
assert.strictEqual(list.$('input[name="foo"]')[0], document.activeElement,
"foo should be focused");
- list.$('input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
+ await testUtils.fields.triggerKeydown(list.$('input[name="foo"]'), 'tab');
assert.strictEqual(list.$('input[name="int_field"]')[0], document.activeElement,
"int_field should be focused");
list.destroy();
});
- QUnit.test('skip buttons when navigating list view with TAB (end)', function (assert) {
+ QUnit.test('skip buttons when navigating list view with TAB (end)', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2872,20 +2879,20 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.dom.click(list.$('tbody tr:eq(2) td:eq(1)'));
+ await testUtils.dom.click(list.$('tbody tr:eq(2) td:eq(1)'));
assert.strictEqual(list.$('tbody tr:eq(2) input[name="foo"]')[0], document.activeElement,
"foo should be focused");
- list.$('tbody tr:eq(2) input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
+ await testUtils.fields.triggerKeydown(list.$('tbody tr:eq(2) input[name="foo"]'), 'tab');
assert.strictEqual(list.$('tbody tr:eq(3) input[name="foo"]')[0], document.activeElement,
"next line should be selected");
list.destroy();
});
- QUnit.test('skip buttons when navigating list view with TAB (middle)', function (assert) {
+ QUnit.test('skip buttons when navigating list view with TAB (middle)', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2899,40 +2906,40 @@ QUnit.module('Views', {
res_id: 1,
});
- testUtils.dom.click(list.$('tbody tr:eq(2) td:eq(2)'));
+ await testUtils.dom.click(list.$('tbody tr:eq(2) td:eq(2)'));
assert.strictEqual(list.$('tbody tr:eq(2) input[name="foo"]')[0], document.activeElement,
"foo should be focused");
- list.$('tbody tr:eq(2) input[name="foo"]').trigger($.Event('keydown', {which: $.ui.keyCode.TAB}));
+ await testUtils.fields.triggerKeydown(list.$('tbody tr:eq(2) input[name="foo"]'), 'tab');
assert.strictEqual(list.$('tbody tr:eq(2) input[name="int_field"]')[0], document.activeElement,
"int_field should be focused");
list.destroy();
});
- QUnit.test('navigation: not moving down with keydown', function (assert) {
+ QUnit.test('navigation: not moving down with keydown', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="bottom"><field name="foo"/></tree>',
});
- testUtils.dom.click(list.$('td:contains(yop)'));
+ await testUtils.dom.click(list.$('td:contains(yop)'));
assert.hasClass(list.$('tr.o_data_row:eq(0)'),'o_selected_row',
"1st row should be selected");
- list.$('tr.o_selected_row input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.DOWN});
+ await testUtils.fields.triggerKeydown(list.$('tr.o_selected_row input[name="foo"]'), 'down');
assert.hasClass(list.$('tr.o_data_row:eq(0)'),'o_selected_row',
"1st row should still be selected");
list.destroy();
});
- QUnit.test('navigation: moving right with keydown from text field does not move the focus', function (assert) {
+ QUnit.test('navigation: moving right with keydown from text field does not move the focus', async function (assert) {
assert.expect(6);
this.data.foo.fields.foo.type = 'text';
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2943,7 +2950,7 @@ QUnit.module('Views', {
'</tree>',
});
- testUtils.dom.click(list.$('td:contains(yop)'));
+ await testUtils.dom.click(list.$('td:contains(yop)'));
var textarea = list.$('textarea[name="foo"]')[0];
assert.strictEqual(document.activeElement, textarea,
"textarea should be focused");
@@ -2956,16 +2963,16 @@ QUnit.module('Views', {
"textarea should still be focused");
assert.ok(textarea.selectionStart === 3 && textarea.selectionEnd === 3,
"textarea value ('yop') should not be selected and cursor should be at the end");
- $(textarea).trigger({type: 'keydown', which: $.ui.keyCode.RIGHT});
+ await testUtils.fields.triggerKeydown($(textarea), 'right');
assert.strictEqual(document.activeElement, list.$('textarea[name="foo"]')[0],
"next field (checkbox) should now be focused");
list.destroy();
});
- QUnit.test('discarding changes in a row properly updates the rendering', function (assert) {
+ QUnit.test('discarding changes in a row properly updates the rendering', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -2978,27 +2985,27 @@ QUnit.module('Views', {
assert.strictEqual(list.$('.o_data_cell:first').text(), "yop",
"first cell should contain 'yop'");
- testUtils.dom.click(list.$('.o_data_cell:first'));
- testUtils.fields.editInput(list.$('input[name="foo"]'), "hello");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.fields.editInput(list.$('input[name="foo"]'), "hello");
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
assert.strictEqual($('.modal:visible').length, 1,
"a modal to ask for discard should be visible");
- testUtils.dom.click($('.modal:visible .btn-primary'));
+ await testUtils.dom.click($('.modal:visible .btn-primary'));
assert.strictEqual(list.$('.o_data_cell:first').text(), "yop",
"first cell should still contain 'yop'");
list.destroy();
});
- QUnit.test('numbers in list are right-aligned', function (assert) {
+ QUnit.test('numbers in list are right-aligned', async function (assert) {
assert.expect(2);
var currencies = {};
_.each(this.data.res_currency.records, function (currency) {
currencies[currency.id] = currency;
});
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3021,7 +3028,7 @@ QUnit.module('Views', {
assert.strictEqual(nbCellRight, 2,
"there should be two right-aligned cells");
- testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
var nbInputRight = _.filter(list.$('.o_data_row:first > .o_data_cell input'), function (el) {
var style = window.getComputedStyle(el);
@@ -3033,7 +3040,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('grouped list are not editable (ungrouped first)', function (assert) {
+ QUnit.test('grouped list are not editable (ungrouped first)', async function (assert) {
// Editable grouped list views are not supported, so the purpose of this
// test is to check that when a list view is grouped, its editable
// attribute is ignored
@@ -3042,7 +3049,7 @@ QUnit.module('Views', {
// editable
assert.expect(5);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3055,28 +3062,28 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
assert.verifySteps([], 'no switch view should have been requested');
assert.containsOnce(list, '.o_selected_row',
"a row should be in edition");
- testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_discard'));
// reload with groupBy
- list.reload({groupBy: ['bar']});
+ await list.reload({groupBy: ['bar']});
// clicking on record should open the form view
- testUtils.dom.click(list.$('.o_group_header:first'));
- testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_group_header:first'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
// clicking on create button should open the form view
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.verifySteps(['switch view form 1', 'switch view form false'],
'two switch view to form should have been requested');
list.destroy();
});
- QUnit.test('grouped list are not editable (grouped first)', function (assert) {
+ QUnit.test('grouped list are not editable (grouped first)', async function (assert) {
// Editable grouped list views are not supported, so the purpose of this
// test is to check that when a list view is grouped, its editable
// attribute is ignored
@@ -3084,7 +3091,7 @@ QUnit.module('Views', {
// editable, and then it is reloaded with no groupBy and becomes editable
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3100,42 +3107,40 @@ QUnit.module('Views', {
// the view being grouped, it is not editable, so clicking on a record
// should open the form view
- testUtils.dom.click(list.$('.o_group_header:first'));
- testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_group_header:first'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
// for the same reason, clicking on 'Create' should open the form view
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
assert.verifySteps(['switch view form 1', 'switch view form false'],
"two switch view to form should have been requested");
// reload without groupBy
- list.reload({groupBy: []});
+ await list.reload({groupBy: []});
// as the view is no longer grouped, it is editable, so clicking on a
// row should switch it in edition
- testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
- assert.verifySteps(['switch view form 1', 'switch view form false'],
- "no more switch view should have been requested");
- assert.containsOnce(list, '.o_selected_row',
- "a row should be in edition");
+ assert.verifySteps([], "no more switch view should have been requested");
+ assert.containsOnce(list, '.o_selected_row', "a row should be in edition");
// clicking on the body should leave the edition
- testUtils.dom.click($('body'));
+ await testUtils.dom.click($('body'));
assert.containsNone(list, '.o_selected_row',
"the row should no longer be in edition");
list.destroy();
});
- QUnit.test('field values are escaped', function (assert) {
+ QUnit.test('field values are escaped', async function (assert) {
assert.expect(1);
var value = '<script>throw Error();</script>';
this.data.foo.records[0].foo = value;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3148,21 +3153,23 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('pressing ESC discard the current line changes', function (assert) {
- assert.expect(3);
+ QUnit.test('pressing ESC discard the current line changes', async function (assert) {
+ assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="top"><field name="foo"/></tree>',
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ assert.containsN(list, 'tr.o_data_row', 5,
+ "should currently adding a 5th data row");
- list.$('input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.ESCAPE});
+ await testUtils.fields.triggerKeydown(list.$('input[name="foo"]'), 'escape');
assert.containsN(list, 'tr.o_data_row', 4,
- "should have 4 data row in list");
+ "should have only 4 data row after escape");
assert.containsNone(list, 'tr.o_data_row.o_selected_row',
"no rows should be selected");
assert.ok(!list.$buttons.find('.o_list_button_save').is(':visible'),
@@ -3170,21 +3177,23 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('pressing ESC discard the current line changes (with required)', function (assert) {
- assert.expect(3);
+ QUnit.test('pressing ESC discard the current line changes (with required)', async function (assert) {
+ assert.expect(4);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
arch: '<tree editable="top"><field name="foo" required="1"/></tree>',
});
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ assert.containsN(list, 'tr.o_data_row', 5,
+ "should currently adding a 5th data row");
- list.$('input[name="foo"]').trigger({type: 'keydown', which: $.ui.keyCode.ESCAPE});
+ await testUtils.fields.triggerKeydown(list.$('input[name="foo"]'), 'escape');
assert.containsN(list, 'tr.o_data_row', 4,
- "should have 4 data row in list");
+ "should have only 4 data row after escape");
assert.containsNone(list, 'tr.o_data_row.o_selected_row',
"no rows should be selected");
assert.ok(!list.$buttons.find('.o_list_button_save').is(':visible'),
@@ -3192,10 +3201,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('field with password attribute', function (assert) {
+ QUnit.test('field with password attribute', async function (assert) {
assert.expect(2);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3210,10 +3219,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('list with handle widget', function (assert) {
+ QUnit.test('list with handle widget', async function (assert) {
assert.expect(11);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3229,7 +3238,7 @@ 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 Promise.resolve();
}
return this._super.apply(this, arguments);
},
@@ -3245,7 +3254,7 @@ QUnit.module('Views', {
"default fourth record should have amount 0");
// Drag and drop the fourth line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').first(),
{position: 'bottom'}
@@ -3263,7 +3272,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('result of consecutive resequences is correctly sorted', function (assert) {
+ QUnit.test('result of consecutive resequences is correctly sorted', async function (assert) {
assert.expect(9);
this.data = { // we want the data to be minimal to have a minimal test
foo: {
@@ -3277,7 +3286,7 @@ QUnit.module('Views', {
}
};
var moves = 0;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3326,28 +3335,31 @@ QUnit.module('Views', {
});
assert.strictEqual(list.$('tbody tr td.o_list_number').text(), '1234',
"default should be sorted by id");
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').eq(2),
{position: 'top'}
);
assert.strictEqual(list.$('tbody tr td.o_list_number').text(), '1243',
"the int_field (sequence) should have been correctly updated");
- testUtils.dom.dragAndDrop(
+
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(2),
list.$('tbody tr').eq(1),
{position: 'top'}
);
assert.deepEqual(list.$('tbody tr td.o_list_number').text(), '1423',
"the int_field (sequence) should have been correctly updated");
- testUtils.dom.dragAndDrop(
+
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(1),
list.$('tbody tr').eq(3),
{position: 'top'}
);
assert.deepEqual(list.$('tbody tr td.o_list_number').text(), '1243',
"the int_field (sequence) should have been correctly updated");
- testUtils.dom.dragAndDrop(
+
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(2),
list.$('tbody tr').eq(1),
{position: 'top'}
@@ -3357,7 +3369,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list with handle widget', function (assert) {
+ QUnit.test('editable list with handle widget', async function (assert) {
assert.expect(12);
// resequence makes sense on a sequence field, not on arbitrary fields
@@ -3366,7 +3378,7 @@ QUnit.module('Views', {
this.data.foo.records[2].int_field = 2;
this.data.foo.records[3].int_field = 3;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3397,7 +3409,7 @@ QUnit.module('Views', {
"default fourth record should have amount 0");
// Drag and drop the fourth line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').first(),
{position: 'bottom'}
@@ -3412,7 +3424,7 @@ QUnit.module('Views', {
assert.strictEqual(list.$('tbody tr:eq(3) td:last').text(), '300',
"new fourth record should have amount 300");
- testUtils.dom.click(list.$('tbody tr:eq(1) td:last'));
+ await testUtils.dom.click(list.$('tbody tr:eq(1) td:last'));
assert.strictEqual(list.$('tbody tr:eq(1) td:last input').val(), '0',
"the edited record should be the good one");
@@ -3420,7 +3432,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list, handle widget locks and unlocks on sort', function (assert) {
+ QUnit.test('editable list, handle widget locks and unlocks on sort', async function (assert) {
assert.expect(6);
// we need another sortable field to lock/unlock the handle
@@ -3431,7 +3443,7 @@ QUnit.module('Views', {
this.data.foo.records[2].int_field = 2;
this.data.foo.records[3].int_field = 3;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3445,7 +3457,7 @@ QUnit.module('Views', {
"default should be sorted by int_field");
// Drag and drop the fourth line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').first(),
{position: 'bottom'}
@@ -3456,13 +3468,13 @@ QUnit.module('Views', {
"drag and drop should have succeeded, as the handle is unlocked");
// Sorting by a field different for int_field should lock the handle
- testUtils.dom.click(list.$('.o_column_sortable').eq(1));
+ await testUtils.dom.click(list.$('.o_column_sortable').eq(1));
assert.strictEqual(list.$('tbody span[name="amount"]').text(), '0.00300.00500.001200.00',
"should have been sorted by amount");
// Drag and drop the fourth line in second position (not)
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').first(),
{position: 'bottom'}
@@ -3472,13 +3484,13 @@ QUnit.module('Views', {
"drag and drop should have failed as the handle is locked");
// Sorting by int_field should unlock the handle
- testUtils.dom.click(list.$('.o_column_sortable').eq(0));
+ await testUtils.dom.click(list.$('.o_column_sortable').eq(0));
assert.strictEqual(list.$('tbody span[name="amount"]').text(), '1200.000.00500.00300.00',
"records should be ordered as per the previous resequence");
// Drag and drop the fourth line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').first(),
{position: 'bottom'}
@@ -3490,7 +3502,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list with handle widget with slow network', function (assert) {
+ QUnit.test('editable list with handle widget with slow network', async function (assert) {
assert.expect(15);
// resequence makes sense on a sequence field, not on arbitrary fields
@@ -3499,9 +3511,9 @@ QUnit.module('Views', {
this.data.foo.records[2].int_field = 2;
this.data.foo.records[3].int_field = 3;
- var def = $.Deferred();
+ var prom = testUtils.makeTestPromise();
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3518,14 +3530,13 @@ 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(def).then(function () {
+ return prom.then(function () {
return _super(route, args);
});
}
return this._super.apply(this, arguments);
},
});
-
assert.strictEqual(list.$('tbody tr:eq(0) td:last').text(), '1200',
"default first record should have amount 1200");
assert.strictEqual(list.$('tbody tr:eq(1) td:last').text(), '500',
@@ -3536,19 +3547,21 @@ QUnit.module('Views', {
"default fourth record should have amount 0");
// drag and drop the fourth line in second position
- testUtils.dom.dragAndDrop(
+ await testUtils.dom.dragAndDrop(
list.$('.ui-sortable-handle').eq(3),
list.$('tbody tr').first(),
{position: 'bottom'}
);
// edit moved row before the end of resequence
- testUtils.dom.click(list.$('tbody tr:eq(3) td:last'));
+ await testUtils.dom.click(list.$('tbody tr:eq(3) td:last'));
+ await testUtils.nextTick();
assert.strictEqual(list.$('tbody tr:eq(3) td:last input').length, 0,
"shouldn't edit the line before resequence");
- def.resolve();
+ prom.resolve();
+ await testUtils.nextTick();
assert.strictEqual(list.$('tbody tr:eq(3) td:last input').length, 1,
"should edit the line after resequence");
@@ -3556,10 +3569,10 @@ QUnit.module('Views', {
assert.strictEqual(list.$('tbody tr:eq(3) td:last input').val(), '300',
"fourth record should have amount 300");
- testUtils.fields.editInput(list.$('tbody tr:eq(3) td:last input'), 301);
- testUtils.dom.click(list.$('tbody tr:eq(0) td:last'));
+ await testUtils.fields.editInput(list.$('tbody tr:eq(3) td:last input'), 301);
+ await testUtils.dom.click(list.$('tbody tr:eq(0) td:last'));
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
assert.strictEqual(list.$('tbody tr:eq(0) td:last').text(), '1200',
"first record should have amount 1200");
@@ -3570,22 +3583,22 @@ QUnit.module('Views', {
assert.strictEqual(list.$('tbody tr:eq(3) td:last').text(), '301',
"fourth record should have amount 301");
- testUtils.dom.click(list.$('tbody tr:eq(3) td:last'));
+ await testUtils.dom.click(list.$('tbody tr:eq(3) td:last'));
assert.strictEqual(list.$('tbody tr:eq(3) td:last input').val(), '301',
"fourth record should have amount 301");
list.destroy();
});
- QUnit.test('multiple clicks on Add do not create invalid rows', function (assert) {
+ QUnit.test('multiple clicks on Add do not create invalid rows', async function (assert) {
assert.expect(2);
this.data.foo.onchanges = {
m2o: function () {},
};
- var def = $.Deferred();
- var list = createView({
+ var prom = testUtils.makeTestPromise();
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3593,7 +3606,9 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'onchange') {
- return $.when(def).then(_.constant(result));
+ return prom.then(function () {
+ return result;
+ });
}
return result;
},
@@ -3606,7 +3621,8 @@ QUnit.module('Views', {
testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
- def.resolve();
+ prom.resolve();
+ await testUtils.nextTick();
assert.containsN(list, '.o_data_row', 5,
"only one record should have been created");
@@ -3614,7 +3630,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('reference field rendering', function (assert) {
+ QUnit.test('reference field rendering', async function (assert) {
assert.expect(4);
this.data.foo.records.push({
@@ -3622,7 +3638,7 @@ QUnit.module('Views', {
reference: 'res_currency,2',
});
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3641,10 +3657,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('editable list view: contexts are correctly sent', function (assert) {
+ QUnit.test('editable list view: contexts are correctly sent', async function (assert) {
assert.expect(6);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3670,17 +3686,17 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$('.o_data_cell:first'));
- testUtils.fields.editInput(list.$('.o_field_widget[name=foo]'), 'abc');
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.fields.editInput(list.$('.o_field_widget[name=foo]'), 'abc');
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
list.destroy();
});
- QUnit.test('list grouped by date:month', function (assert) {
+ QUnit.test('list grouped by date:month', async function (assert) {
assert.expect(1);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3694,10 +3710,10 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('grouped list edition with toggle_button widget', function (assert) {
+ QUnit.test('grouped list edition with toggle_button widget', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3712,17 +3728,17 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(list.$('.o_group_header:first'));
+ await testUtils.dom.click(list.$('.o_group_header:first'));
assert.containsOnce(list, '.o_data_row:first .o_toggle_button_success',
"boolean value of the first record should be true");
- testUtils.dom.click(list.$('.o_data_row:first .o_icon_button'));
+ await testUtils.dom.click(list.$('.o_data_row:first .o_icon_button'));
assert.strictEqual(list.$('.o_data_row:first .text-muted:not(.o_toggle_button_success)').length, 1,
"boolean button should have been updated");
list.destroy();
});
- QUnit.test('grouped list view, indentation for empty group', function (assert) {
+ QUnit.test('grouped list view, indentation for empty group', async function (assert) {
assert.expect(3);
this.data.foo.fields.priority = {
@@ -3734,7 +3750,7 @@ QUnit.module('Views', {
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({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3744,7 +3760,7 @@ QUnit.module('Views', {
// 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([
+ return Promise.resolve([
{
id: 8,
m2o:[1,"Value 1"],
@@ -3761,7 +3777,7 @@ QUnit.module('Views', {
});
// open the first group
- testUtils.dom.click(list.$('.o_group_header:first'));
+ await testUtils.dom.click(list.$('.o_group_header:first'));
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.hasClass(list.$('th.o_group_name').eq(1).children().eq(0), 'fa',
@@ -3771,7 +3787,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('basic support for widgets', function (assert) {
+ QUnit.test('basic support for widgets', async function (assert) {
assert.expect(1);
var MyWidget = Widget.extend({
@@ -3784,7 +3800,7 @@ QUnit.module('Views', {
});
widgetRegistry.add('test', MyWidget);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3798,10 +3814,10 @@ QUnit.module('Views', {
delete widgetRegistry.map.test;
});
- QUnit.test('use the limit attribute in arch', function (assert) {
+ QUnit.test('use the limit attribute in arch', async function (assert) {
assert.expect(3);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3821,7 +3837,7 @@ QUnit.module('Views', {
list.destroy();
});
- QUnit.test('check if the view destroys all widgets and instances', function (assert) {
+ QUnit.test('check if the view destroys all widgets and instances', async function (assert) {
assert.expect(1);
var instanceNumber = 0;
@@ -3858,13 +3874,13 @@ QUnit.module('Views', {
'</tree>',
};
- var list = createView(params);
+ var list = await createView(params);
list.destroy();
var initialInstanceNumber = instanceNumber;
instanceNumber = 0;
- list = createView(params);
+ list = await createView(params);
// call destroy function of controller to ensure that it correctly destroys everything
list.__destroy();
@@ -3878,12 +3894,12 @@ QUnit.module('Views', {
testUtils.mock.unpatch(mixins.ParentedMixin);
});
- QUnit.test('concurrent reloads finishing in inverse order', function (assert) {
- assert.expect(3);
+ QUnit.test('concurrent reloads finishing in inverse order', async function (assert) {
+ assert.expect(4);
var blockSearchRead = false;
- var def = $.Deferred();
- var list = createView({
+ var prom = testUtils.makeTestPromise();
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3891,7 +3907,7 @@ QUnit.module('Views', {
mockRPC: function (route) {
var result = this._super.apply(this, arguments);
if (route === '/web/dataset/search_read' && blockSearchRead) {
- return $.when(def).then(_.constant(result));
+ return prom.then(_.constant(result));
}
return result;
},
@@ -3903,6 +3919,7 @@ QUnit.module('Views', {
// reload with a domain (this request is blocked)
blockSearchRead = true;
list.reload({domain: [['foo', '=', 'yop']]});
+ await testUtils.nextTick();
assert.containsN(list, '.o_list_view .o_data_row', 4,
"list view should still contain 4 records (search_read being blocked)");
@@ -3910,23 +3927,29 @@ QUnit.module('Views', {
// reload without the domain
blockSearchRead = false;
list.reload({domain: []});
+ await testUtils.nextTick();
+
+ assert.containsN(list, '.o_list_view .o_data_row', 4,
+ "list view should still contain 4 records");
// unblock the RPC
- def.resolve();
+ prom.resolve();
+ await testUtils.nextTick();
+
assert.containsN(list, '.o_list_view .o_data_row', 4,
"list view should still contain 4 records");
list.destroy();
});
- QUnit.test('list view on a "noCache" model', function (assert) {
- assert.expect(8);
+ QUnit.test('list view on a "noCache" model', async function (assert) {
+ assert.expect(9);
testUtils.mock.patch(BasicModel, {
noCacheModels: BasicModel.prototype.noCacheModels.concat(['foo']),
});
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3946,20 +3969,20 @@ QUnit.module('Views', {
core.bus.on('clear_cache', list, assert.step.bind(assert, 'clear_cache'));
// create a new record
- testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
- testUtils.fields.editInput(list.$('.o_selected_row .o_field_widget'), 'some value');
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_add'));
+ await testUtils.fields.editInput(list.$('.o_selected_row .o_field_widget'), 'some value');
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
// edit an existing record
- testUtils.dom.click(list.$('.o_data_cell:first'));
- testUtils.fields.editInput(list.$('.o_selected_row .o_field_widget'), 'new value');
- testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
+ await testUtils.dom.click(list.$('.o_data_cell:first'));
+ await testUtils.fields.editInput(list.$('.o_selected_row .o_field_widget'), 'new value');
+ await testUtils.dom.click(list.$buttons.find('.o_list_button_save'));
// delete a record
- testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input'));
- testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(list.sidebar.$('a:contains(Delete)'));
- testUtils.dom.click($('.modal-footer .btn-primary'));
+ await testUtils.dom.click(list.$('.o_data_row:first .o_list_record_selector input'));
+ await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(list.sidebar.$('a:contains(Delete)'));
+ await testUtils.dom.click($('.modal-footer .btn-primary'));
assert.verifySteps([
'create',
@@ -3972,12 +3995,14 @@ QUnit.module('Views', {
list.destroy();
testUtils.mock.unpatch(BasicModel);
+
+ assert.verifySteps(['clear_cache']); // triggered by the test environment on destroy
});
- QUnit.test('list should ask to scroll to top on page changes', function (assert) {
+ QUnit.test('list should ask to scroll to top on page changes', async function (assert) {
assert.expect(10);
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -3994,36 +4019,34 @@ QUnit.module('Views', {
});
// switch pages (should ask to scroll)
- testUtils.dom.click(list.pager.$('.o_pager_next'));
- testUtils.dom.click(list.pager.$('.o_pager_previous'));
-
+ await testUtils.dom.click(list.pager.$('.o_pager_next'));
+ await testUtils.dom.click(list.pager.$('.o_pager_previous'));
assert.verifySteps(['scroll', 'scroll'],
"should ask to scroll when switching pages");
// change the limit (should not ask to scroll)
- testUtils.dom.click(list.pager.$('.o_pager_value'));
- list.pager.$('.o_pager_value input').val('1-2').blur();
+ await testUtils.dom.click(list.pager.$('.o_pager_value'));
+ await testUtils.fields.editAndTrigger(list.pager.$('.o_pager_value input'),
+ '1-2', ['blur']);
assert.strictEqual(list.pager.$('.o_pager_value').text(), '1-2',
"should have changed the limit");
- assert.verifySteps(['scroll', 'scroll'],
- "should not ask to scroll when changing the limit");
+ assert.verifySteps([], "should not ask to scroll when changing the limit");
// switch pages again (should still ask to scroll)
- testUtils.dom.click(list.pager.$('.o_pager_next'));
+ await testUtils.dom.click(list.pager.$('.o_pager_next'));
- assert.verifySteps(['scroll', 'scroll', 'scroll'],
- "this is still working after a limit change");
+ assert.verifySteps(['scroll'], "this is still working after a limit change");
list.destroy();
});
- QUnit.test('list with handle field, override default_get, bottom when inline', function (assert) {
+ QUnit.test('list with handle field, override default_get, bottom when inline', async function (assert) {
assert.expect(2);
this.data.foo.fields.int_field.default = 10;
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'foo',
data: this.data,
@@ -4042,15 +4065,55 @@ QUnit.module('Views', {
// check line is at the correct place
var inputText = 'ninja';
- testUtils.dom.click($('.o_list_button_add'));
- testUtils.fields.editInput(list.$('.o_input[name="foo"]'), inputText);
- testUtils.dom.click($('.o_list_button_save'));
- testUtils.dom.click($('.o_list_button_add'));
+ await testUtils.dom.click($('.o_list_button_add'));
+ await testUtils.fields.editInput(list.$('.o_input[name="foo"]'), inputText);
+ await testUtils.dom.click($('.o_list_button_save'));
+ await testUtils.dom.click($('.o_list_button_add'));
assert.strictEqual($('.o_data_cell').text(), "blipblipyopgnap" + inputText);
list.destroy();
});
+
+ QUnit.test('grouped list with async widget', async function (assert) {
+ assert.expect(4);
+
+ var prom = testUtils.makeTestPromise();
+ var AsyncWidget = Widget.extend({
+ willStart: function () {
+ return prom;
+ },
+ start: function () {
+ this.$el.text('ready');
+ },
+ });
+ widgetRegistry.add('asyncWidget', AsyncWidget);
+
+ var list = await createView({
+ View: ListView,
+ model: 'foo',
+ data: this.data,
+ arch: '<tree><widget name="asyncWidget"/></tree>',
+ groupBy: ['int_field'],
+ });
+
+ assert.containsNone(list, '.o_data_row', "no group should be open");
+
+ await testUtils.dom.click(list.$('.o_group_header:first'));
+
+ assert.containsNone(list, '.o_data_row',
+ "should wait for async widgets before opening the group");
+
+ prom.resolve();
+ await testUtils.nextTick();
+
+ assert.containsN(list, '.o_data_row', 1, "group should be open");
+ assert.strictEqual(list.$('.o_data_row .o_data_cell').text(), 'ready',
+ "async widget should be correctly displayed");
+
+ list.destroy();
+ delete widgetRegistry.map.asyncWidget;
+ });
});
});
diff --git a/addons/web/static/tests/views/mobile_control_panel_tests.js b/addons/web/static/tests/views/mobile_control_panel_tests.js
index 05e2cd09a73..19226741474 100644
--- a/addons/web/static/tests/views/mobile_control_panel_tests.js
+++ b/addons/web/static/tests/views/mobile_control_panel_tests.js
@@ -39,12 +39,12 @@ QUnit.module('Mobile Search view Screen', {
};
},
}, function () {
- QUnit.test('can activate a filter with mobile search view', function (assert) {
+ QUnit.test('can activate a filter with mobile search view', async function (assert) {
assert.expect(3);
var filterActiveFlag = false;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -57,23 +57,23 @@ QUnit.module('Mobile Search view Screen', {
},
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.ok(!$('.o_mobile_search').is(':visible'),
'mobile search view is not visible');
// open the search view
- testUtils.dom.click($('button.o_enable_searchview'));
+ await testUtils.dom.click($('button.o_enable_searchview'));
assert.ok($('.o_mobile_search').is(':visible'),
'mobile search view is visible');
// open filter sub menu
- testUtils.dom.click($('button.o_dropdown_toggler_btn').first());
+ await testUtils.dom.click($('button.o_dropdown_toggler_btn').first());
filterActiveFlag = true;
// click on Active filter
- testUtils.dom.click($('.o_filters_menu a:contains(Active)'));
+ await testUtils.dom.click($('.o_filters_menu a:contains(Active)'));
actionManager.destroy();
});
diff --git a/addons/web/static/tests/views/pivot_tests.js b/addons/web/static/tests/views/pivot_tests.js
index 0e7e7ff0a2d..c098ecd7867 100644
--- a/addons/web/static/tests/views/pivot_tests.js
+++ b/addons/web/static/tests/views/pivot_tests.js
@@ -89,10 +89,10 @@ QUnit.module('Views', {
}, function () {
QUnit.module('PivotView');
- QUnit.test('simple pivot rendering', function (assert) {
+ QUnit.test('simple pivot rendering', async function (assert) {
assert.expect(3);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -113,10 +113,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot rendering with widget', function (assert) {
+ QUnit.test('pivot rendering with widget', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -130,12 +130,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot rendering with string attribute on field', function (assert) {
+ QUnit.test('pivot rendering with string attribute on field', async function (assert) {
assert.expect(1);
this.data.partner.fields.foo = {string: "Foo", type: "integer", store: true};
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -149,12 +149,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot rendering with string attribute on non stored field', function (assert) {
+ QUnit.test('pivot rendering with string attribute on non stored field', async function (assert) {
assert.expect(1);
this.data.partner.fields.fubar = {string: "Fubar", type: "integer", store:false};
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -166,7 +166,7 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot rendering with invisible attribute on field', function (assert) {
+ QUnit.test('pivot rendering with invisible attribute on field', async function (assert) {
assert.expect(2);
// when invisible, a field should neither be an active measure,
// nor be a selectable measure.
@@ -175,7 +175,7 @@ QUnit.module('Views', {
foo2: {string: "Foo2", type: "integer", store: true}
});
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -193,10 +193,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot view without "string" attribute', function (assert) {
+ QUnit.test('pivot view without "string" attribute', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -210,10 +210,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot view add computed fields explicitly defined as measure', function (assert) {
+ QUnit.test('pivot view add computed fields explicitly defined as measure', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -226,10 +226,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('clicking on a cell triggers a do_action', function (assert) {
+ QUnit.test('clicking on a cell triggers a do_action', async function (assert) {
assert.expect(2);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -271,15 +271,15 @@ QUnit.module('Views', {
assert.hasClass(pivot.$el,'o_enable_linking',
"root node should have classname 'o_enable_linking'");
- testUtils.dom.click(pivot.$('.o_pivot_cell_value:contains(12)')); // should trigger a do_action
+ await testUtils.dom.click(pivot.$('.o_pivot_cell_value:contains(12)')); // should trigger a do_action
pivot.destroy();
});
- QUnit.test('pivot view with disable_linking="True"', function (assert) {
+ QUnit.test('pivot view with disable_linking="True"', async function (assert) {
assert.expect(2);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -297,16 +297,16 @@ QUnit.module('Views', {
"root node should not have classname 'o_enable_linking'");
assert.containsOnce(pivot, '.o_pivot_cell_value',
"should have one cell");
- testUtils.dom.click(pivot.$('.o_pivot_cell_value')); // should not trigger a do_action
+ await testUtils.dom.click(pivot.$('.o_pivot_cell_value')); // should not trigger a do_action
pivot.destroy();
});
- QUnit.test('pivot view grouped by date field', function (assert) {
+ QUnit.test('pivot view grouped by date field', async function (assert) {
assert.expect(2);
var data = this.data;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -325,10 +325,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('without measures, pivot view uses __count by default', function (assert) {
+ QUnit.test('without measures, pivot view uses __count by default', async function (assert) {
assert.expect(2);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -347,11 +347,11 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot view can be reloaded', function (assert) {
+ QUnit.test('pivot view can be reloaded', async function (assert) {
assert.expect(4);
var readGroupCount = 0;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -368,17 +368,17 @@ QUnit.module('Views', {
"should contain a pivot cell with the number of all records");
assert.strictEqual(readGroupCount, 1, "should have done 1 rpc");
- testUtils.pivot.reload(pivot, {domain: [['foo', '>', 10]]});
+ await testUtils.pivot.reload(pivot, {domain: [['foo', '>', 10]]});
assert.strictEqual(pivot.$('td.o_pivot_cell_value:contains(2)').length, 1,
"should contain a pivot cell with the number of remaining records");
assert.strictEqual(readGroupCount, 2, "should have done 2 rpcs");
pivot.destroy();
});
- QUnit.test('pivot view grouped by many2one field', function (assert) {
+ QUnit.test('pivot view grouped by many2one field', async function (assert) {
assert.expect(3);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -397,12 +397,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('basic folding/unfolding', function (assert) {
+ QUnit.test('basic folding/unfolding', async function (assert) {
assert.expect(7);
var rpcCount = 0;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -420,12 +420,12 @@ QUnit.module('Views', {
"should have 3 rows: 1 for the opened header, and 2 for data");
// click on the opened header to close it
- testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened'));
+ await testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened'));
assert.containsOnce(pivot, 'tbody tr', "should have 1 row");
// click on closed header to open dropdown
- testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
assert.containsOnce(pivot, '.o_pivot_field_menu .dropdown-item[data-field="date"]:first',
"should have the date field as proposition");
@@ -434,8 +434,7 @@ QUnit.module('Views', {
assert.containsNone(pivot, '.o_field_selection .dropdown-item[data-field="non_stored_m2o"]:first',
"should not have the non_stored_m2o field as proposition");
-
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"]:first'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"]:first'));
assert.containsN(pivot, 'tbody tr', 4,
"should have 4 rows: one for header, 3 for data");
@@ -444,10 +443,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('more folding/unfolding', function (assert) {
+ QUnit.test('more folding/unfolding', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -458,25 +457,26 @@ QUnit.module('Views', {
});
// open dropdown to zoom into first row
- testUtils.dom.clickFirst(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.clickFirst(pivot.$('tbody .o_pivot_header_cell_closed'));
// click on date by day
pivot.$('.dropdown-menu.show .o_inline_dropdown .dropdown-menu').toggle(); // unfold inline dropdown
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="day"]'));
+ await testUtils.nextTick();
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="day"]'));
// open dropdown to zoom into second row
- testUtils.dom.clickLast(pivot.$('tbody td.o_pivot_header_cell_closed'));
+ await testUtils.dom.clickLast(pivot.$('tbody td.o_pivot_header_cell_closed'));
assert.containsN(pivot, 'tbody tr', 7,
"should have 7 rows (1 for total, 1 for xphone, 1 for xpad, 4 for data)");
pivot.destroy();
});
- QUnit.test('pivot view can be flipped', function (assert) {
+ QUnit.test('pivot view can be flipped', async function (assert) {
assert.expect(3);
var rpcCount = 0;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -493,7 +493,7 @@ QUnit.module('Views', {
"should have 3 rows: 1 for the open header, and 2 for data");
rpcCount = 0;
- testUtils.dom.click(pivot.$buttons.find('.o_pivot_flip_button'));
+ await testUtils.dom.click(pivot.$buttons.find('.o_pivot_flip_button'));
assert.strictEqual(rpcCount, 0, "should not have done any rpc");
assert.containsOnce(pivot, 'tbody tr',
@@ -501,12 +501,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('can toggle extra measure', function (assert) {
+ QUnit.test('can toggle extra measure', async function (assert) {
assert.expect(8);
var rpcCount = 0;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -526,8 +526,8 @@ QUnit.module('Views', {
"the __count measure should not be selected");
rpcCount = 0;
- testUtils.pivot.toggleMeasuresDropdown(pivot);
- testUtils.pivot.clickMeasure(pivot, '__count');
+ await testUtils.pivot.toggleMeasuresDropdown(pivot);
+ await testUtils.pivot.clickMeasure(pivot, '__count');
assert.hasClass(pivot.$buttons.find('.dropdown-item[data-field=__count]:first'),'selected',
"the __count measure should be selected");
@@ -536,7 +536,7 @@ QUnit.module('Views', {
assert.strictEqual(rpcCount, 2,
"should have done 2 rpcs to reload data");
- testUtils.pivot.clickMeasure(pivot, '__count');
+ await testUtils.pivot.clickMeasure(pivot, '__count');
assert.doesNotHaveClass(pivot.$buttons.find('.dropdown-item[data-field=__count]:first'), 'selected',
"the __count measure should not be selected");
@@ -548,10 +548,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('no content helper when no active measure', function (assert) {
+ QUnit.test('no content helper when no active measure', async function (assert) {
assert.expect(4);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -564,8 +564,8 @@ QUnit.module('Views', {
assert.containsOnce(pivot, 'table',
"should have a table in DOM");
- testUtils.pivot.toggleMeasuresDropdown(pivot);
- testUtils.pivot.clickMeasure(pivot, '__count');
+ await testUtils.pivot.toggleMeasuresDropdown(pivot);
+ await testUtils.pivot.clickMeasure(pivot, '__count');
assert.containsOnce(pivot, '.o_view_nocontent',
"should have a no_content_helper");
@@ -574,10 +574,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('no content helper when no data', function (assert) {
+ QUnit.test('no content helper when no data', async function (assert) {
assert.expect(4);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -590,7 +590,7 @@ QUnit.module('Views', {
assert.containsOnce(pivot, 'table',
"should have a table in DOM");
- testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
+ await testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
assert.containsOnce(pivot, '.o_view_nocontent',
"should have a no_content_helper");
@@ -599,12 +599,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('no content helper when no data, part 2', function (assert) {
+ QUnit.test('no content helper when no data, part 2', async function (assert) {
assert.expect(1);
this.data.partner.records = [];
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -616,10 +616,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('no content helper when no data, part 3', function (assert) {
+ QUnit.test('no content helper when no data, part 3', async function (assert) {
assert.expect(4);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -631,27 +631,27 @@ QUnit.module('Views', {
assert.containsOnce(pivot, '.o_view_nocontent',
"should have a no_content_helper");
- testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
+ await testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
assert.containsOnce(pivot, '.o_view_nocontent',
"should still have a no_content_helper");
- testUtils.pivot.reload(pivot, {domain: []});
+ await testUtils.pivot.reload(pivot, {domain: []});
assert.containsNone(pivot, '.o_view_nocontent',
"should not have a no_content_helper");
// tries to open a field selection menu, to make sure it was not
// removed from the dom.
- testUtils.dom.clickFirst(pivot.$('.o_pivot_header_cell_closed'));
+ await testUtils.dom.clickFirst(pivot.$('.o_pivot_header_cell_closed'));
assert.containsOnce(pivot, '.o_pivot_field_menu',
"the field selector menu exists");
pivot.destroy();
});
- QUnit.test('tries to restore previous state after domain change', function (assert) {
+ QUnit.test('tries to restore previous state after domain change', async function (assert) {
assert.expect(5);
var rpcCount = 0;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -670,10 +670,10 @@ QUnit.module('Views', {
assert.strictEqual(pivot.$('.o_pivot_measure_row:contains(Foo)').length, 1,
"should have 1 row for measure Foo");
- testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
+ await testUtils.pivot.reload(pivot, {domain: [['foo', '=', 12345]]});
rpcCount = 0;
- testUtils.pivot.reload(pivot, {domain: []});
+ await testUtils.pivot.reload(pivot, {domain: []});
assert.equal(rpcCount, 2, "should have reloaded data");
assert.containsN(pivot, '.o_pivot_cell_value', 3,
@@ -683,10 +683,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('can be grouped with the update function', function (assert) {
+ QUnit.test('can be grouped with the update function', async function (assert) {
assert.expect(4);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -700,7 +700,7 @@ QUnit.module('Views', {
assert.containsOnce(pivot, 'tbody tr',
"should have 1 rows");
- testUtils.pivot.reload(pivot, {groupBy: ['product_id']});
+ await testUtils.pivot.reload(pivot, {groupBy: ['product_id']});
assert.containsN(pivot, '.o_pivot_cell_value', 3,
"should have 3 cells");
@@ -709,10 +709,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('can sort data in a column by clicking on header', function (assert) {
+ QUnit.test('can sort data in a column by clicking on header', async function (assert) {
assert.expect(3);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -725,12 +725,12 @@ QUnit.module('Views', {
assert.strictEqual($('td.o_pivot_cell_value').text(), "321220",
"should have proper values in cells (total, result 1, result 2");
- testUtils.dom.click(pivot.$('th.o_pivot_measure_row'));
+ await testUtils.dom.click(pivot.$('th.o_pivot_measure_row'));
assert.strictEqual($('td.o_pivot_cell_value').text(), "322012",
"should have proper values in cells (total, result 2, result 1");
- testUtils.dom.click(pivot.$('th.o_pivot_measure_row'));
+ await testUtils.dom.click(pivot.$('th.o_pivot_measure_row'));
assert.strictEqual($('td.o_pivot_cell_value').text(), "321220",
"should have proper values in cells (total, result 1, result 2");
@@ -738,11 +738,11 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('can expand all rows', function (assert) {
+ QUnit.test('can expand all rows', async function (assert) {
assert.expect(7);
var nbReadGroups = 0;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -764,22 +764,22 @@ QUnit.module('Views', {
// expand on date:days, product
nbReadGroups = 0;
- testUtils.pivot.reload(pivot, {groupBy: ['date:days', 'product_id']});
+ await testUtils.pivot.reload(pivot, {groupBy: ['date:days', 'product_id']});
assert.strictEqual(nbReadGroups, 3, "should have done 3 read_group RPCS");
assert.containsN(pivot, 'tbody tr', 8,
"should have 7 rows (total + 3 for December and 2 for October and April)");
// collapse the last two rows
- testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
- testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
+ await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
+ await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
assert.containsN(pivot, 'tbody tr', 6,
"should have 6 rows now");
// expand all
nbReadGroups = 0;
- testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button'));
+ await testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button'));
assert.strictEqual(nbReadGroups, 3, "should have done 3 read_group RPCS");
assert.containsN(pivot, 'tbody tr', 8,
@@ -788,11 +788,11 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('expand all with a delay', function (assert) {
+ QUnit.test('expand all with a delay', async function (assert) {
assert.expect(3);
var def;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -803,40 +803,40 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'read_group') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
// expand on date:days, product
- testUtils.pivot.reload(pivot, {groupBy: ['date:days', 'product_id']});
+ await testUtils.pivot.reload(pivot, {groupBy: ['date:days', 'product_id']});
assert.containsN(pivot, 'tbody tr', 8,
"should have 7 rows (total + 3 for December and 2 for October and April)");
// collapse the last two rows
- testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
- testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
+ await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
+ await testUtils.dom.clickLast(pivot.$('.o_pivot_header_cell_opened'));
assert.containsN(pivot, 'tbody tr', 6,
"should have 6 rows now");
// expand all
- def = $.Deferred();
- testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button'));
+ def = testUtils.makeTestPromise();
+ await testUtils.dom.click(pivot.$buttons.find('.o_pivot_expand_button'));
def.resolve();
-
+ await testUtils.nextTick();
assert.containsN(pivot, 'tbody tr', 8,
"should have 8 rows again");
pivot.destroy();
});
- QUnit.test('can download a file', function (assert) {
+ QUnit.test('can download a file', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -853,16 +853,16 @@ QUnit.module('Views', {
},
});
- testUtils.dom.click(pivot.$buttons.find('.o_pivot_download'));
+ await testUtils.dom.click(pivot.$buttons.find('.o_pivot_download'));
pivot.destroy();
});
- QUnit.test('download button is disabled when there is no data', function (assert) {
+ QUnit.test('download button is disabled when there is no data', async function (assert) {
assert.expect(1);
this.data.partner.records = [];
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -877,10 +877,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('getOwnedQueryParams correctly returns measures and groupbys', function (assert) {
+ QUnit.test('getOwnedQueryParams correctly returns measures and groupbys', async function (assert) {
assert.expect(3);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -899,8 +899,8 @@ QUnit.module('Views', {
}, "context should be correct");
// expand header on field customer
- testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed:nth(1)'));
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first'));
+ await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed:nth(1)'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first'));
assert.deepEqual(pivot.getOwnedQueryParams(), {
context: {
pivot_column_groupby: ['date:day', 'customer'],
@@ -910,8 +910,8 @@ QUnit.module('Views', {
}, "context should be correct");
// expand row on field product_id
- testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
assert.deepEqual(pivot.getOwnedQueryParams(), {
context: {
pivot_column_groupby: ['date:day', 'customer'],
@@ -923,13 +923,13 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('correctly remove pivot_ keys from the context', function (assert) {
+ QUnit.test('correctly remove pivot_ keys from the context', async function (assert) {
assert.expect(5);
this.data.partner.fields.amount = {string: "Amount", type: "float"};
// Equivalent to loading with default filter
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -961,7 +961,7 @@ QUnit.module('Views', {
}, "context should be correct");
// Let's get rid of the rows groupBy
- pivot.$('tbody .o_pivot_header_cell_opened').click();
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_opened'));
assert.deepEqual(pivot.getOwnedQueryParams(), {
context: {
@@ -972,7 +972,7 @@ QUnit.module('Views', {
}, "context should be correct");
// And now, get rid of the col groupby
- pivot.$('thead .o_pivot_header_cell_opened').click();
+ await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_opened'));
assert.deepEqual(pivot.getOwnedQueryParams(), {
context: {
@@ -982,8 +982,8 @@ QUnit.module('Views', {
},
}, "context should be correct");
- pivot.$('tbody .o_pivot_header_cell_closed').click();
- pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first').click();
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.click( pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
assert.deepEqual(pivot.getOwnedQueryParams(), {
context: {
@@ -993,8 +993,8 @@ QUnit.module('Views', {
},
}, "context should be correct");
- pivot.$('thead .o_pivot_header_cell_closed').click();
- pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first').click();
+ await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="customer"]:first'));
assert.deepEqual(pivot.getOwnedQueryParams(), {
context: {
@@ -1007,10 +1007,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('Unload Filter, reset display, load another filter', function (assert) {
+ QUnit.test('Unload Filter, reset display, load another filter', async function (assert) {
assert.expect(18);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1046,10 +1046,10 @@ QUnit.module('Views', {
var reloadParams = {
context: {},
};
- pivot.reload(reloadParams);
+ await pivot.reload(reloadParams);
// collapse all headers
- pivot.$('.o_pivot_header_cell_opened').click();
- pivot.$('.o_pivot_header_cell_opened').click();
+ await testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened:first'));
+ await testUtils.dom.click(pivot.$('.o_pivot_header_cell_opened'));
// Check Columns
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_closed').length, 1,
@@ -1075,7 +1075,7 @@ QUnit.module('Views', {
pivot_row_groupby: ['product_id'],
},
};
- pivot.reload(reloadParams);
+ await pivot.reload(reloadParams);
// Check Columns
assert.strictEqual(pivot.$('thead .o_pivot_header_cell_opened').length, 1,
@@ -1096,12 +1096,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('correctly uses pivot_ keys from the context', function (assert) {
+ QUnit.test('correctly uses pivot_ keys from the context', async function (assert) {
assert.expect(7);
this.data.partner.fields.amount = {string: "Amount", type: "float"};
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1138,12 +1138,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('correctly uses pivot_ keys from the context (at reload)', function (assert) {
+ QUnit.test('correctly uses pivot_ keys from the context (at reload)', async function (assert) {
assert.expect(8);
this.data.partner.fields.amount = {string: "Amount", type: "float"};
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1163,7 +1163,7 @@ QUnit.module('Views', {
pivot_row_groupby: ['product_id'],
},
};
- testUtils.pivot.reload(pivot, reloadParams);
+ await testUtils.pivot.reload(pivot, reloadParams);
assert.containsOnce(pivot, 'thead .o_pivot_header_cell_opened',
"column: should have one opened header");
@@ -1185,10 +1185,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('correctly use group_by key from the context', function (assert) {
+ QUnit.test('correctly use group_by key from the context', async function (assert) {
assert.expect(7);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: 'partner',
data: this.data,
@@ -1219,12 +1219,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot still handles __count__ measure', function (assert) {
+ QUnit.test('pivot still handles __count__ measure', async function (assert) {
// for retro-compatibility reasons, the pivot view still handles
// '__count__' measure.
assert.expect(2);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1249,10 +1249,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('not use a many2one as a measure by default', function (assert) {
+ QUnit.test('not use a many2one as a measure by default', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1266,10 +1266,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('use a many2one as a measure with specified additional measure', function (assert) {
+ QUnit.test('use a many2one as a measure with specified additional measure', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1286,10 +1286,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot view with many2one field as a measure', function (assert) {
+ QUnit.test('pivot view with many2one field as a measure', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1304,10 +1304,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('m2o as measure, drilling down into data', function (assert) {
+ QUnit.test('m2o as measure, drilling down into data', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1315,20 +1315,20 @@ QUnit.module('Views', {
'<field name="product_id" type="measure"/>' +
'</pivot>',
});
- testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
// click on date by month
pivot.$('.dropdown-menu.show .o_inline_dropdown .dropdown-menu').toggle(); // unfold inline dropdown
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="month"]'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="date"][data-interval="month"]'));
assert.strictEqual(pivot.$('.o_pivot_cell_value').text(), '2211',
'should have loaded the proper data');
pivot.destroy();
});
- QUnit.test('pivot view with same many2one field as a measure and grouped by', function (assert) {
+ QUnit.test('pivot view with same many2one field as a measure and grouped by', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1340,17 +1340,17 @@ QUnit.module('Views', {
},
});
- testUtils.pivot.toggleMeasuresDropdown(pivot);
- testUtils.pivot.clickMeasure(pivot, 'product_id');
+ await testUtils.pivot.toggleMeasuresDropdown(pivot);
+ await testUtils.pivot.clickMeasure(pivot, 'product_id');
assert.strictEqual(pivot.$('.o_pivot_cell_value').text(), '421131',
'should have loaded the proper data');
pivot.destroy();
});
- QUnit.test('pivot view with same many2one field as a measure and grouped by (and drill down)', function (assert) {
+ QUnit.test('pivot view with same many2one field as a measure and grouped by (and drill down)', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1359,19 +1359,19 @@ QUnit.module('Views', {
'</pivot>',
});
- testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field="product_id"]:first'));
assert.strictEqual(pivot.$('.o_pivot_cell_value').text(), '211',
'should have loaded the proper data');
pivot.destroy();
});
- QUnit.test('Row and column groupbys plus a domain', function (assert) {
+ QUnit.test('Row and column groupbys plus a domain', async function (assert) {
assert.expect(3);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1381,15 +1381,15 @@ QUnit.module('Views', {
});
// Set a column groupby
- testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed'));
- testUtils.dom.click(pivot.$('.o_field_selection .dropdown-item[data-field=customer]:first'));
+ await testUtils.dom.click(pivot.$('thead .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('.o_field_selection .dropdown-item[data-field=customer]:first'));
// Set a Row groupby
- testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
- testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field=product_id]:first'));
+ await testUtils.dom.click(pivot.$('tbody .o_pivot_header_cell_closed'));
+ await testUtils.dom.click(pivot.$('.o_pivot_field_menu .dropdown-item[data-field=product_id]:first'));
// Set a domain
- testUtils.pivot.reload(pivot, {domain: [['product_id', '=', 41]]});
+ await testUtils.pivot.reload(pivot, {domain: [['product_id', '=', 41]]});
var expectedContext = {
context: {
@@ -1413,12 +1413,12 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('parallel data loading should discard all but the last one', function (assert) {
+ QUnit.test('parallel data loading should discard all but the last one', async function (assert) {
assert.expect(2);
var def;
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1428,17 +1428,17 @@ QUnit.module('Views', {
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'read_group') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
});
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
testUtils.pivot.reload(pivot, {groupBy: ['product_id']});
testUtils.pivot.reload(pivot, {groupBy: ['product_id', 'customer']});
- def.resolve();
-
+ await def.resolve();
+ await testUtils.nextTick();
assert.containsN(pivot, '.o_pivot_cell_value', 6,
"should have 6 cells");
assert.containsN(pivot, 'tbody tr', 6,
@@ -1446,7 +1446,7 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot measures should be alphabetically sorted', function (assert) {
+ QUnit.test('pivot measures should be alphabetically sorted', async function (assert) {
assert.expect(2);
var data = this.data;
@@ -1456,7 +1456,7 @@ QUnit.module('Views', {
data.partner.fields.modd = {string: "modd", type: "integer"};
data.partner.fields.zip = {string: "Zip", type: "integer"};
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: data,
@@ -1475,10 +1475,10 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('pivot view should use default order for auto sorting', function (assert) {
+ QUnit.test('pivot view should use default order for auto sorting', async function (assert) {
assert.expect(1);
- var pivot = createView({
+ var pivot = await createView({
View: PivotView,
model: "partner",
data: this.data,
@@ -1493,7 +1493,7 @@ QUnit.module('Views', {
pivot.destroy();
});
- QUnit.test('rendering of pivot view with comparison', function (assert) {
+ QUnit.test('rendering of pivot view with comparison', async function (assert) {
assert.expect(91);
this.data.partner.records[0].date = '2016-12-15';
@@ -1522,7 +1522,7 @@ QUnit.module('Views', {
}
// create an action manager to test the interactions with the search view
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,pivot': '<pivot>' +
@@ -1533,7 +1533,7 @@ QUnit.module('Views', {
}
});
- actionManager.doAction({
+ await actionManager.doAction({
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'pivot']],
@@ -1547,17 +1547,17 @@ QUnit.module('Views', {
// with no data
- testUtils.dom.click($('.o_time_range_menu_button'));
- testUtils.dom.click($('.o_time_range_menu .o_comparison_checkbox'));
+ await testUtils.dom.click($('.o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_time_range_menu .o_comparison_checkbox'));
$('.o_time_range_selector').val('today');
- testUtils.dom.click($('.o_time_range_menu .o_apply_range'));
+ await testUtils.dom.click($('.o_time_range_menu .o_apply_range'));
assert.strictEqual($('.o_pivot p.o_view_nocontent_empty_folder').length, 1);
// with data, no row groupby
- testUtils.dom.click($('.o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_time_range_menu_button'));
$('.o_time_range_selector').val('this_month');
- testUtils.dom.click($('.o_time_range_menu .o_apply_range'));
+ await testUtils.dom.click($('.o_time_range_menu .o_apply_range'));
results = [
"13", "0", "100%", "0", "19", "-100%", "13", "19", "-31.58%"
];
@@ -1565,8 +1565,8 @@ QUnit.module('Views', {
// with data, with row groupby
- testUtils.dom.click($('.o_pivot .o_pivot_header_cell_closed').eq(2));
- testUtils.dom.click($('.o_pivot .o_field_selection a[data-field="product_id"]'));
+ await testUtils.dom.click($('.o_pivot .o_pivot_header_cell_closed').eq(2));
+ await testUtils.dom.click($('.o_pivot .o_field_selection a[data-field="product_id"]'));
results = [
"13", "0", "100%", "0", "19", "-100%", "13", "19", "-31.58%" ,
"12", "0", "100%", "12", "0" , "100%" ,
@@ -1574,9 +1574,9 @@ QUnit.module('Views', {
];
checkCellValues(results);
- testUtils.pivot.toggleMeasuresDropdown(actionManager.getCurrentController().widget);
- testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="foo"]'));
- testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="product_id"]'));
+ await testUtils.pivot.toggleMeasuresDropdown(actionManager.getCurrentController().widget);
+ await testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="foo"]'));
+ await testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="product_id"]'));
results = [
"2", "0", "100%", "0", "1", "-100%", "2", "1", "100%" ,
"1", "0", "100%", "1", "0" , "100%" ,
@@ -1584,8 +1584,8 @@ QUnit.module('Views', {
];
checkCellValues(results);
- testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="__count"]'));
- testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="product_id"]'));
+ await testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="__count"]'));
+ await testUtils.dom.click($('.o_control_panel div.o_pivot_measures_list a[data-field="product_id"]'));
results = [
"2", "0", "100%", "0", "2", "-100%", "2", "2", "0%" ,
"1", "0", "100%", "1", "0" , "100%" ,
@@ -1593,7 +1593,7 @@ QUnit.module('Views', {
];
checkCellValues(results);
- testUtils.dom.clickFirst($('.o_pivot .o_pivot_header_cell_opened'));
+ await testUtils.dom.clickFirst($('.o_pivot .o_pivot_header_cell_opened'));
results = [
"2", "2", "0%" ,
"1", "0", "100%" ,
@@ -1611,7 +1611,7 @@ QUnit.module('Views', {
actionManager.destroy();
});
- QUnit.test('export data in excel with comparison', function (assert) {
+ QUnit.test('export data in excel with comparison', async function (assert) {
assert.expect(10);
this.data.partner.records[0].date = '2016-12-15';
@@ -1622,7 +1622,7 @@ QUnit.module('Views', {
var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0);
// create an action manager to test the interactions with the search view
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,pivot': '<pivot>' +
@@ -1635,11 +1635,14 @@ QUnit.module('Views', {
get_file: function (args) {
var data = JSON.parse(args.data.data);
_.each(data.headers, function (l) {
- assert.step(l.map(function (o) {return o.title;}));
+ var titles = l.map(function (o) {return o.title;});
+ assert.step(JSON.stringify(titles));
});
- assert.step(data.measure_row.map(function (o) {return o.measure;}));
- assert.step(data.nbr_measures);
- assert.step(data.rows.map(function (o) {return o.values.length;}));
+ var measures = data.measure_row.map(function (o) {return o.measure;});
+ assert.step(JSON.stringify(measures));
+ assert.step(String(data.nbr_measures));
+ var valuesLength = data.rows.map(function (o) {return o.values.length;});
+ assert.step(JSON.stringify(valuesLength));
assert.strictEqual(args.url, '/web/pivot/export_xls',
"should call get_file with correct parameters");
args.complete();
@@ -1647,20 +1650,20 @@ QUnit.module('Views', {
},
});
- actionManager.doAction({
+ await actionManager.doAction({
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'pivot']],
});
// open time range menu
- testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
// select 'Today' as range
$('.o_control_panel .o_time_range_selector').val('today');
// check checkbox 'Compare To'
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
// Click on 'Apply' button
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
// the time range menu configuration is by now: Date, Today, checkbox checked, Previous Period
// With the data above, the time ranges contain no record.
@@ -1670,38 +1673,35 @@ QUnit.module('Views', {
assert.ok($('.o_control_panel button.o_pivot_download').prop('disabled'));
// open time range menu
- testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
// select 'This Month' as date range
$('.o_control_panel .o_time_range_selector').val('this_month');
// Click on 'Apply' button
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
// the time range menu configuration is by now: Date, This Month, checkbox checked, Previous Period
// With the data above, the time ranges contain some records.
// export data. Should execute 'get_file'
- testUtils.dom.click($('.o_control_panel button.o_pivot_download'));
+ await testUtils.dom.click($('.o_control_panel button.o_pivot_download'));
assert.verifySteps([
// Headers
- ["Total", ""],
- ["December 2016" , "November 2016"],
- ["Foo", "Foo", "Foo"],
- [
- "This Month", "Previous Period", "Variation",
- "This Month", "Previous Period", "Variation",
- "This Month", "Previous Period", "Variation"
- ],
+ '["Total",""]',
+ '["December 2016","November 2016"]',
+ '["Foo","Foo","Foo"]',
+ '["This Month","Previous Period","Variation","This Month","Previous Period"' +
+ ',"Variation","This Month","Previous Period","Variation"]',
// number of 'measures'
- 3,
+ '3',
// rows values length
- [9]
+ '[9]',
]);
unpatchDate();
actionManager.destroy();
});
- QUnit.test('rendering of pivot view with comparison and count measure', function (assert) {
+ QUnit.test('rendering of pivot view with comparison and count measure', async function (assert) {
assert.expect(10);
var mockMock = false;
@@ -1715,7 +1715,7 @@ QUnit.module('Views', {
var unpatchDate = patchDate(2016, 11, 20, 1, 0, 0);
// create an action manager to test the interactions with the search view
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,pivot': '<pivot>' +
@@ -1731,14 +1731,14 @@ QUnit.module('Views', {
// this modification is necessary because mockReadGroup does not
// properly reflect the server response when there is no record
// and a groupby list of length at least one.
- return $.when([{}]);
+ return Promise.resolve([{}]);
}
}
return result;
},
});
- actionManager.doAction({
+ await actionManager.doAction({
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'pivot']],
@@ -1747,10 +1747,10 @@ QUnit.module('Views', {
mockMock = true;
// activate 'This Month' and 'Previous Period' in time range menu
- testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
$('.o_control_panel .o_time_range_selector').val('this_month');
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
var results = [
"4", "0", "100%",
@@ -1768,7 +1768,7 @@ QUnit.module('Views', {
});
QUnit.module('Sort in comparison mode', {
- beforeEach: function () {
+ beforeEach: async function () {
this.data.partner.records[0].date = '2016-12-15';
this.data.partner.records[1].date = '2016-12-17';
this.data.partner.records[2].date = '2016-11-22';
@@ -1792,7 +1792,7 @@ QUnit.module('Views', {
};
// create an action manager to test the interactions with the search view
- this.actionManager = createActionManager({
+ this.actionManager = await createActionManager({
data: this.data,
archs: {
'partner,false,pivot': '<pivot>' +
@@ -1802,10 +1802,9 @@ QUnit.module('Views', {
'</pivot>',
'partner,false,search': '<search></search>',
},
- debug: 1,
});
- this.actionManager.doAction({
+ await this.actionManager.doAction({
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'pivot']],
@@ -1817,13 +1816,13 @@ QUnit.module('Views', {
});
// open time range menu
- testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu_button'));
// select 'Today' as range
- testUtils.fields.editInput($('.o_control_panel .o_time_range_selector'), 'this_month');
+ await testUtils.fields.editInput($('.o_control_panel .o_time_range_selector'), 'this_month');
// check checkbox 'Compare To'
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_comparison_checkbox'));
// Click on 'Apply' button
- testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
+ await testUtils.dom.click($('.o_control_panel .o_time_range_menu .o_apply_range'));
// We are in comparison mode
},
afterEach: function () {
@@ -1831,11 +1830,11 @@ QUnit.module('Views', {
this.actionManager.destroy();
},
}, function () {
- QUnit.test('when clicking on measure, sort by "This Month" (period of interest)', function (assert) {
+ QUnit.test('when clicking on measure, sort by "This Month" (period of interest)', async function (assert) {
assert.expect(1);
// click on 'Foo' in column Total/Company
- testUtils.dom.click($('.o_pivot_measure_row').eq(0));
+ await testUtils.dom.click($('.o_pivot_measure_row').eq(0));
var results = [
"12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
"12", "0", "100%", "12", "0" , "100%",
@@ -1849,11 +1848,11 @@ QUnit.module('Views', {
QUnit.test(
'click on a period of interest header sort according to the appropriate column ' +
'first in ascending order then in descending order',
- function (assert) {
+ async function (assert) {
assert.expect(2);
// click on 'This Month' in column Total/Individual/Foo
- testUtils.dom.click($('.o_pivot_measure_row').eq(6));
+ await testUtils.dom.click($('.o_pivot_measure_row').eq(6));
var results = [
"12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
"1", "0", "100%", "1" , "0", "100%",
@@ -1865,7 +1864,7 @@ QUnit.module('Views', {
assert.strictEqual(actualResult, results.join(''));
// click once again on 'This Month' in column Total/Individual/Foo
- testUtils.dom.click($('.o_pivot_measure_row').eq(6));
+ await testUtils.dom.click($('.o_pivot_measure_row').eq(6));
results = [
"12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
"12", "0", "100%", "12", "0" , "100%",
@@ -1877,11 +1876,11 @@ QUnit.module('Views', {
});
QUnit.test('click on a period of comparison header sort according to appropriate column',
- function (assert) {
+ async function (assert) {
assert.expect(1);
// click on 'Previous Period' in column Total/Individual/Foo
- testUtils.dom.click($('.o_pivot_measure_row').eq(7));
+ await testUtils.dom.click($('.o_pivot_measure_row').eq(7));
var results = [
"12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
"0", "2", "-100%", "0" , "2" , "-100%",
@@ -1893,11 +1892,11 @@ QUnit.module('Views', {
});
QUnit.test('click on a variation header sort according to appropriate column',
- function (assert) {
+ async function (assert) {
assert.expect(1);
// click on 'Variation' in column Total/Individual/Foo
- testUtils.dom.click($('.o_pivot_measure_row').eq(11));
+ await testUtils.dom.click($('.o_pivot_measure_row').eq(11));
var results = [
"12", "17", "-29.41%", "1", "2", "-50%", "13", "19", "-31.58%",
"12", "0", "100%", "12", "0" , "100%",
diff --git a/addons/web/static/tests/views/qweb_tests.js b/addons/web/static/tests/views/qweb_tests.js
index e9b7398fd09..c7872690e49 100644
--- a/addons/web/static/tests/views/qweb_tests.js
+++ b/addons/web/static/tests/views/qweb_tests.js
@@ -8,9 +8,9 @@ QUnit.module("Views", {
}, function () {
QUnit.module("QWeb");
- QUnit.test("basic", function (assert) {
- assert.expect(13);
- var am = utils.createActionManager({
+ QUnit.test("basic", async function (assert) {
+ assert.expect(14);
+ var am = await utils.createActionManager({
data: {
test: {
fields: {},
@@ -27,7 +27,7 @@ QUnit.module("Views", {
case 'test.qweb_render_view':
assert.step('fetch');
assert.equal(args.kwargs.view_id, 5);
- return $.when(
+ return Promise.resolve(
'<div>foo' +
'<div data-model="test" data-method="wheee" data-id="42" data-other="5">' +
'<a type="toggle" class="fa fa-caret-right">Unfold</a>' +
@@ -38,7 +38,7 @@ QUnit.module("Views", {
assert.step('unfold');
assert.deepEqual(args.args, [42]);
assert.deepEqual(args.kwargs, {other: 5});
- return $.when('<div id="sub">ok</div>');
+ return Promise.resolve('<div id="sub">ok</div>');
}
}
return this._super.apply(this, arguments);
@@ -51,15 +51,18 @@ QUnit.module("Views", {
views: [[false, 'qweb']],
res_model: 'test',
}).then(function () { resolved = true; });
- assert.ok(resolved, "Action should have resolved synchronously");
+ assert.ok(!resolved, "Action cannot be resolved synchronously");
+
+ await utils.nextTick();
+ assert.ok(resolved, "Action is resolved asynchronously");
var $content = am.$('.o_content');
assert.ok(/^\s*foo/.test($content.text()));
- utils.dom.click($content.find('[type=toggle]'));
+ await utils.dom.click($content.find('[type=toggle]'));
assert.equal($content.find('div#sub').text(), 'ok', 'should have unfolded the sub-item');
- utils.dom.click($content.find('[type=toggle]'));
+ await utils.dom.click($content.find('[type=toggle]'));
assert.equal($content.find('div#sub').length, 0, "should have removed the sub-item");
- utils.dom.click($content.find('[type=toggle]'));
+ await utils.dom.click($content.find('[type=toggle]'));
assert.verifySteps(['fetch', 'unfold', 'unfold']);
} finally {
diff --git a/addons/web/static/tests/views/search_filter_menu_tests.js b/addons/web/static/tests/views/search_filter_menu_tests.js
index 92d49cc23ae..62cfaccdc93 100644
--- a/addons/web/static/tests/views/search_filter_menu_tests.js
+++ b/addons/web/static/tests/views/search_filter_menu_tests.js
@@ -11,8 +11,9 @@ function createFilterMenu(filters, fields, params) {
var target = params.debug ? document.body : $('#qunit-fixture');
var menu = new FilterMenu(null, filters, fields);
testUtils.mock.addMockEnvironment(menu, params);
- menu.appendTo(target);
- return menu;
+ return menu.appendTo(target).then(function() {
+ return menu;
+ });
}
QUnit.module('FilterMenu', {
@@ -33,11 +34,11 @@ QUnit.module('FilterMenu', {
},
}, function () {
- QUnit.test('simple rendering with no filter', function (assert) {
+ QUnit.test('simple rendering with no filter', async function (assert) {
assert.expect(3);
- var filterMenu = createFilterMenu([], this.fields);
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
+ var filterMenu = await createFilterMenu([], this.fields);
+ await testUtils.dom.click(filterMenu.$('span.fa-filter'));
assert.containsNone(filterMenu, '.dropdown-divider');
assert.containsNone(filterMenu, '.o_add_filter_menu');
assert.containsOnce(filterMenu, '.o_add_custom_filter',
@@ -45,24 +46,24 @@ QUnit.module('FilterMenu', {
filterMenu.destroy();
});
- QUnit.test('simple rendering with a filter', function (assert) {
+ QUnit.test('simple rendering with a filter', async function (assert) {
assert.expect(2);
- var filterMenu = createFilterMenu(this.filters, this.fields);
+ var filterMenu = await createFilterMenu(this.filters, this.fields);
assert.containsN(filterMenu, '.dropdown-divider, .dropdown-item, .o_add_custom_filter', 4,
'should have 4 elements: a hidden separator, a filter, a separator, a add custom filter item');
assert.containsOnce(filterMenu, '.o_add_custom_filter');
filterMenu.destroy();
});
- QUnit.test('click on add custom filter opens the submenu', function (assert) {
+ QUnit.test('click on add custom filter opens the submenu', async function (assert) {
assert.expect(3);
- var filterMenu = createFilterMenu([], this.fields);
+ var filterMenu = await createFilterMenu([], this.fields);
// open menu dropdown
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
+ await testUtils.dom.click(filterMenu.$('span.fa-filter'));
// open add custom filter submenu
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
assert.containsNone(filterMenu, '.dropdown-divider');
assert.isVisible(filterMenu.$('.o_add_filter_menu'));
assert.containsN(filterMenu, '.dropdown-item, .dropdown-item-text', 3,
@@ -71,16 +72,16 @@ QUnit.module('FilterMenu', {
filterMenu.destroy();
});
- QUnit.test('removing last prop disable the apply button', function (assert) {
+ QUnit.test('removing last prop disable the apply button', async function (assert) {
assert.expect(2);
- var filterMenu = createFilterMenu([], this.fields);
+ var filterMenu = await createFilterMenu([], this.fields);
// open menu dropdown and custom filter submenu
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.dom.click(filterMenu.$('span.fa-filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
// remove the current unique proposition
- testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop'));
+ await testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop'));
assert.containsNone(filterMenu, '.dropdown-divider');
assert.containsN(filterMenu, '.dropdown-item, .dropdown-item-text', 2,
@@ -89,26 +90,26 @@ QUnit.module('FilterMenu', {
filterMenu.destroy();
});
- QUnit.test('readding a proposition reenable apply button', function (assert) {
+ QUnit.test('readding a proposition reenable apply button', async function (assert) {
assert.expect(1);
- var filterMenu = createFilterMenu([], this.fields);
+ var filterMenu = await createFilterMenu([], this.fields);
// open menu dropdown and custom filter submenu, remove existing prop
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop'));
+ await testUtils.dom.click(filterMenu.$('span.fa-filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_searchview_extended_delete_prop'));
// read a proposition
- testUtils.dom.click(filterMenu.$('.o_add_condition'));
+ await testUtils.dom.click(filterMenu.$('.o_add_condition'));
assert.ok(!filterMenu.$('.o_apply_filter').attr('disabled'));
filterMenu.destroy();
});
- QUnit.test('adding a simple filter works', function (assert) {
+ QUnit.test('adding a simple filter works', async function (assert) {
assert.expect(6);
delete this.fields.date_field;
- var filterMenu = createFilterMenu([], this.fields, {
+ var filterMenu = await createFilterMenu([], this.fields, {
intercepts: {
new_filters: function (ev) {
var filter = ev.data.filters[0];
@@ -125,17 +126,17 @@ QUnit.module('FilterMenu', {
},
});
// open menu dropdown and custom filter submenu, remove existing prop
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.dom.click(filterMenu.$('span.fa-filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
// click on apply to activate filter
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
assert.containsNone(filterMenu, '.o_filter_condition');
assert.containsN(filterMenu, '.dropdown-divider', 2);
assert.isNotVisible(filterMenu.$('.dropdown-divider').eq(0));
filterMenu.destroy();
});
- QUnit.test('commit search with an extended proposition with field char does not cause a crash', function (assert) {
+ QUnit.test('commit search with an extended proposition with field char does not cause a crash', async function (assert) {
assert.expect(6);
this.fields = {many2one_field: {string: "Trululu", type: "many2one", relation: 'partner', selectable: true, searchable: true}};
@@ -149,7 +150,7 @@ QUnit.module('FilterMenu', {
[['many2one_field','ilike', `\\`]],
];
- var filterMenu = createFilterMenu([], this.fields, {
+ var filterMenu = await createFilterMenu([], this.fields, {
intercepts: {
new_filters: function (ev) {
var filter = ev.data.filters[0];
@@ -162,42 +163,42 @@ QUnit.module('FilterMenu', {
});
// open menu dropdown and custom filter submenu, select trululu field and enter string `a`, then click apply
- testUtils.dom.click(filterMenu.$('span.fa-filter'));
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
- testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `a`);
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('span.fa-filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
+ await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `a`);
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
// open custom filter submenu, select trululu field and enter string `"a"`, then click apply
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
- testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `"a"`);
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
+ await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `"a"`);
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
// open custom filter submenu, select trululu field and enter string `'a'`, then click apply
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
- testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `'a'`);
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
+ await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `'a'`);
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
// open custom filter submenu, select trululu field and enter string `'`, then click apply
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
- testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `'`);
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
+ await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `'`);
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
// open custom filter submenu, select trululu field and enter string `"`, then click apply
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
- testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `"`);
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
+ await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `"`);
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
// open custom filter submenu, select trululu field and enter string `\`, then click apply
- testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
- testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
- testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `\\`);
- testUtils.dom.click(filterMenu.$('.o_apply_filter'));
+ await testUtils.dom.click(filterMenu.$('.o_add_custom_filter'));
+ await testUtils.fields.editSelect(filterMenu.$('.o_filter_condition select.o_input.o_searchview_extended_prop_field'), 'many2one_field');
+ await testUtils.fields.editInput(filterMenu.$('.o_filter_condition .o_searchview_extended_prop_value input'), `\\`);
+ await testUtils.dom.click(filterMenu.$('.o_apply_filter'));
filterMenu.destroy();
});
diff --git a/addons/web/static/tests/views/search_groupby_menu_tests.js b/addons/web/static/tests/views/search_groupby_menu_tests.js
index efeb74103d5..b25eae37e8f 100644
--- a/addons/web/static/tests/views/search_groupby_menu_tests.js
+++ b/addons/web/static/tests/views/search_groupby_menu_tests.js
@@ -11,8 +11,9 @@ function createGroupByMenu(groupBys, fields, params) {
var target = params.debug ? document.body : $('#qunit-fixture');
var menu = new GroupByMenu(null, groupBys, fields);
testUtils.mock.addMockEnvironment(menu, params);
- menu.appendTo(target);
- return menu;
+ return menu.appendTo(target).then(function() {
+ return menu;
+ });
}
QUnit.module('GroupByMenu', {
@@ -30,10 +31,10 @@ QUnit.module('GroupByMenu', {
},
}, function () {
- QUnit.test('simple rendering with no filter and no field', function (assert) {
+ QUnit.test('simple rendering with no filter and no field', async function (assert) {
assert.expect(1);
- var groupByMenu = createGroupByMenu([], {});
+ var groupByMenu = await createGroupByMenu([], {});
// open groupBy menu
testUtils.dom.click(groupByMenu.$('button:first'));
assert.containsNone(groupByMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text',
@@ -42,13 +43,12 @@ QUnit.module('GroupByMenu', {
groupByMenu.destroy();
});
- QUnit.test('simple rendering', function (assert) {
+ QUnit.test('simple rendering', async function (assert) {
assert.expect(2);
- var groupByMenu = createGroupByMenu(this.groupBys, this.fields);
+ var groupByMenu = await createGroupByMenu(this.groupBys, this.fields);
// open groupBy menu
- testUtils.dom.click(groupByMenu.$('button:first'));
- groupByMenu.$('button:first').click();
+ await testUtils.dom.click(groupByMenu.$('button:first'));
assert.containsN(groupByMenu, '.dropdown-divider, .dropdown-item', 4);
assert.strictEqual(groupByMenu.$('.o_menu_item').text().trim(), 'some group by',
'should have proper filter name');
@@ -56,39 +56,40 @@ QUnit.module('GroupByMenu', {
groupByMenu.destroy();
});
- QUnit.test('simple rendering with no filter but fields', function (assert) {
+ QUnit.test('simple rendering with no filter but fields', async function (assert) {
assert.expect(1);
- var groupByMenu = createGroupByMenu(
+ var groupByMenu = await createGroupByMenu(
[],
{fieldName: {sortable: true, string: 'Super Date', type: 'date'}}
);
- testUtils.dom.click(groupByMenu.$('button:first'));
+ await testUtils.nextTick();
+ await testUtils.dom.click(groupByMenu.$('button:first'));
assert.containsOnce(groupByMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 'should have 1 element');
groupByMenu.destroy();
});
- QUnit.test('click on add custom group toggle group selector', function (assert) {
+ QUnit.test('click on add custom group toggle group selector', async function (assert) {
assert.expect(2);
- var groupByMenu = createGroupByMenu([],
+ var groupByMenu = await createGroupByMenu([],
{fieldName: {sortable: true, string: 'Super Date', type: 'date'}}
);
- testUtils.dom.click(groupByMenu.$('button:first'));
+ await testUtils.dom.click(groupByMenu.$('button:first'));
var selector = groupByMenu.$('select.o_group_selector');
assert.ok(!selector.is(":visible"), 'should be invisible');
- testUtils.dom.click(groupByMenu.$('.o_add_custom_group'));
+ await testUtils.dom.click(groupByMenu.$('.o_add_custom_group'));
selector = groupByMenu.$('select.o_group_selector');
assert.ok(selector.is(":visible"), 'should be visible');
groupByMenu.destroy();
});
- QUnit.test('select a groupBy of no date type in Add Custom Group menu add properly that groupBy to menu', function (assert) {
+ QUnit.test('select a groupBy of no date type in Add Custom Group menu add properly that groupBy to menu', async function (assert) {
assert.expect(6);
- var groupByMenu = createGroupByMenu(
+ var groupByMenu = await createGroupByMenu(
[],
{
fieldName: {sortable: true, name: 'candlelight', string: 'Candlelight', type: 'boolean'},
@@ -109,23 +110,24 @@ QUnit.module('GroupByMenu', {
},
}
);
- testUtils.dom.click(groupByMenu.$('button:first'));
- testUtils.dom.click(groupByMenu.$('.o_add_custom_group'));
+ await testUtils.nextTick();
+ await testUtils.dom.click(groupByMenu.$('button:first'));
+ await testUtils.dom.click(groupByMenu.$('.o_add_custom_group'));
assert.strictEqual(groupByMenu.$('select').val(), 'fieldName',
'the select value should be "fieldName"');
- testUtils.dom.click(groupByMenu.$('button.o_apply_group'));
+ await testUtils.dom.click(groupByMenu.$('button.o_apply_group'));
assert.containsOnce(groupByMenu, '.o_menu_item > .dropdown-item.selected', 'there should be a groupby selected');
groupByMenu.destroy();
});
- QUnit.test('select a groupBy of date type in Add Custom Group menu add properly that groupBy to menu', function (assert) {
+ QUnit.test('select a groupBy of date type in Add Custom Group menu add properly that groupBy to menu', async function (assert) {
assert.expect(13);
INTERVAL_OPTIONS = INTERVAL_OPTIONS.map(function (option) {
return _.extend(option, {description: option.description.toString()});
});
- var groupByMenu = createGroupByMenu(
+ var groupByMenu = await createGroupByMenu(
[],
this.fields,
{
@@ -153,20 +155,20 @@ QUnit.module('GroupByMenu', {
}
);
// open groupBy menu
- testUtils.dom.click(groupByMenu.$('button:first'));
+ await testUtils.dom.click(groupByMenu.$('button:first'));
// open Add Custom Group submenu
- testUtils.dom.click(groupByMenu.$('.o_add_custom_group'));
+ await testUtils.dom.click(groupByMenu.$('.o_add_custom_group'));
// select fieldName
assert.strictEqual(groupByMenu.$('select').val(), 'fieldName',
'the select value should be "fieldName"');
// create new groupBy of type date
- groupByMenu.$('button.o_apply_group').click();
+ await testUtils.dom.click(groupByMenu.$('button.o_apply_group'));
assert.strictEqual(groupByMenu.$('.o_menu_item > .dropdown-item.selected').length, 1,
'there should be a groupby selected');
assert.strictEqual(groupByMenu.$('.o_menu_item .o_submenu_switcher').length, 1,
'there should be options available');
// open options submenu
- groupByMenu.$('.o_menu_item .o_submenu_switcher').click();
+ await testUtils.dom.click(groupByMenu.$('.o_menu_item .o_submenu_switcher'));
assert.strictEqual(groupByMenu.$('.o_item_option').length, 5,
'there should be five options available');
assert.strictEqual(groupByMenu.$('.o_add_custom_group').length, 0,
diff --git a/addons/web/static/tests/views/search_panel_tests.js b/addons/web/static/tests/views/search_panel_tests.js
index 9814a887b39..f564ccc0d6b 100644
--- a/addons/web/static/tests/views/search_panel_tests.js
+++ b/addons/web/static/tests/views/search_panel_tests.js
@@ -59,10 +59,10 @@ QUnit.module('Views', {
QUnit.module('SearchPanel in Kanban views');
- QUnit.test('basic rendering', function (assert) {
+ QUnit.test('basic rendering', async function (assert) {
assert.expect(17);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -115,10 +115,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('sections with custom icon and color', function (assert) {
+ QUnit.test('sections with custom icon and color', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -144,12 +144,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('sections with attr invisible="1" are ignored', function (assert) {
+ QUnit.test('sections with attr invisible="1" are ignored', async function (assert) {
// 'groups' attributes are converted server-side into invisible="1" when the user doesn't
// belong to the given group
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -181,10 +181,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('categories and filters order is kept', function (assert) {
+ QUnit.test('categories and filters order is kept', async function (assert) {
assert.expect(4);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -214,10 +214,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('specify active category value in context', function (assert) {
+ QUnit.test('specify active category value in context', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -248,10 +248,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('use category (on many2one) to refine search', function (assert) {
+ QUnit.test('use category (on many2one) to refine search', async function (assert) {
assert.expect(14);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -276,21 +276,21 @@ QUnit.module('Views', {
});
// select 'asustek'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(1) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
// select 'agrolait'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(2) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
// select 'All'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:first header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:first header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:first .active');
@@ -306,10 +306,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('use category (on selection) to refine search', function (assert) {
+ QUnit.test('use category (on selection) to refine search', async function (assert) {
assert.expect(14);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -333,21 +333,21 @@ QUnit.module('Views', {
});
// select 'abc'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(1) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
// select 'ghi'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(3) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(3) header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(3) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
// select 'All' again
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:first header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:first header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:first .active');
@@ -363,7 +363,7 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('store and retrieve active category value', function (assert) {
+ QUnit.test('store and retrieve active category value', async function (assert) {
assert.expect(8);
var Storage = RamStorage.extend({
@@ -380,7 +380,7 @@ QUnit.module('Views', {
});
var expectedActiveId = 3;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -412,7 +412,7 @@ QUnit.module('Views', {
// select 'agrolait'
expectedActiveId = 5;
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
assert.verifySteps([
'getItem searchpanel_partner_company_id',
@@ -422,8 +422,8 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('retrieved category value does not exist', function (assert) {
- assert.expect(5);
+ QUnit.test('retrieved category value does not exist', async function (assert) {
+ assert.expect(6);
var Storage = RamStorage.extend({
getItem: function (key) {
@@ -435,7 +435,7 @@ QUnit.module('Views', {
storage: new Storage(),
});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -465,13 +465,15 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_search_panel_category_value:first .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4);
+ assert.verifySteps(['getItem searchpanel_partner_company_id']);
+
kanban.destroy();
});
- QUnit.test('use two categories to refine search', function (assert) {
+ QUnit.test('use two categories to refine search', async function (assert) {
assert.expect(14);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -500,23 +502,23 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 3);
// select 'asustek'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value[data-id=3] header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value[data-id=3] header'));
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
// select 'abc'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value[data-id=abc] header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value[data-id=abc] header'));
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
// select 'ghi'
- testUtils.dom.click(kanban.$('.o_search_panel_category_value[data-id=ghi] header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value[data-id=ghi] header'));
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
// select 'All' in first category (company_id)
- testUtils.dom.click(kanban.$('.o_search_panel_section:first .o_search_panel_category_value:first header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_section:first .o_search_panel_category_value:first header'));
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
// select 'All' in second category (state)
- testUtils.dom.click(kanban.$('.o_search_panel_section:nth(1) .o_search_panel_category_value:first header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_section:nth(1) .o_search_panel_category_value:first header'));
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 3);
assert.verifySteps([
@@ -531,14 +533,14 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('category with parent_field', function (assert) {
+ QUnit.test('category with parent_field', async function (assert) {
assert.expect(24);
this.data.company.records.push({id: 40, name: 'child company 1', parent_id: 5});
this.data.company.records.push({id: 41, name: 'child company 2', parent_id: 5});
this.data.partner.records[1].company_id = 40;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -569,7 +571,7 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_search_panel_category_value .o_toggle_fold');
// unfold parent category
- testUtils.dom.click(kanban.$('.o_search_panel_category_value .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value .o_toggle_fold'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:first .active');
@@ -578,21 +580,21 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_search_panel_category_value .o_search_panel_category_value', 2);
// click on first child company
- testUtils.dom.click(kanban.$('.o_search_panel_category_value .o_search_panel_category_value:first header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value .o_search_panel_category_value:first header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value .o_search_panel_category_value:first .active');
assert.containsOnce(kanban, '.o_kanban_record:not(.o_kanban_ghost)');
// click on parent company
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) > header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) > header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(2) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
// fold category with children
- testUtils.dom.click(kanban.$('.o_search_panel_category_value .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value .o_toggle_fold'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(2) .active');
@@ -608,14 +610,14 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('can (un)fold parent category values', function (assert) {
+ QUnit.test('can (un)fold parent category values', async function (assert) {
assert.expect(7);
this.data.company.records.push({id: 40, name: 'child company 1', parent_id: 5});
this.data.company.records.push({id: 41, name: 'child company 2', parent_id: 5});
this.data.partner.records[1].company_id = 40;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -639,13 +641,13 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_search_panel_category_value', 3);
// unfold agrolait
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'));
assert.hasClass(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'), 'fa-caret-down',
"'agrolait' should be open");
assert.containsN(kanban, '.o_search_panel_category_value', 5);
// fold agrolait
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'));
assert.hasClass(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'), 'fa-caret-left',
"'agrolait' should be folded");
assert.containsN(kanban, '.o_search_panel_category_value', 3);
@@ -653,14 +655,14 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('fold status is kept at reload', function (assert) {
+ QUnit.test('fold status is kept at reload', async function (assert) {
assert.expect(4);
this.data.company.records.push({id: 40, name: 'child company 1', parent_id: 5});
this.data.company.records.push({id: 41, name: 'child company 2', parent_id: 5});
this.data.partner.records[1].company_id = 40;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -678,12 +680,12 @@ QUnit.module('Views', {
});
// unfold agrolait
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'));
assert.hasClass(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'), 'fa-caret-down',
"'agrolait' should be open");
assert.containsN(kanban, '.o_search_panel_category_value', 5);
- kanban.reload({});
+ await kanban.reload({});
assert.hasClass(kanban.$('.o_search_panel_category_value:contains(agrolait) .o_toggle_fold'), 'fa-caret-down',
"'agrolait' should be open");
@@ -692,11 +694,11 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('concurrency: delayed search_reads', function (assert) {
+ QUnit.test('concurrency: delayed search_reads', async function (assert) {
assert.expect(19);
var def;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -704,7 +706,7 @@ QUnit.module('Views', {
var result = this._super.apply(this, arguments);
if (route === '/web/dataset/search_read') {
assert.step(JSON.stringify(args.domain));
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
@@ -728,9 +730,9 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 3);
// select 'asustek' (delay the reload)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
var asustekDef = def;
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
// 'asustek' should be selected, but there should still be 3 records
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
@@ -738,9 +740,9 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 3);
// select 'agrolait' (delay the reload)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
var agrolaitDef = def;
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
// 'agrolait' should be selected, but there should still be 3 records
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
@@ -749,12 +751,14 @@ QUnit.module('Views', {
// unlock asustek search (should be ignored, so there should still be 3 records)
asustekDef.resolve();
+ await testUtils.nextTick();
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(2) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 3);
// unlock agrolait search, there should now be 1 record
agrolaitDef.resolve();
+ await testUtils.nextTick();
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(2) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 1);
@@ -768,18 +772,18 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('concurrency: misordered get_filters', function (assert) {
+ QUnit.test('concurrency: misordered get_filters', async function (assert) {
assert.expect(15);
var def;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'search_panel_select_multi_range') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
@@ -803,9 +807,9 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4);
// select 'abc' (delay the reload)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
var abcDef = def;
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
// 'All' should still be selected, and there should still be 4 records
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
@@ -813,9 +817,9 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 4);
// select 'ghi' (delay the reload)
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
var ghiDef = def;
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(3) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(3) header'));
// 'All' should still be selected, and there should still be 4 records
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
@@ -824,12 +828,14 @@ QUnit.module('Views', {
// unlock ghi search
ghiDef.resolve();
+ await testUtils.nextTick();
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(3) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
// unlock abc search (should be ignored)
abcDef.resolve();
+ await testUtils.nextTick();
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(3) .active');
assert.containsN(kanban, '.o_kanban_record:not(.o_kanban_ghost)', 2);
@@ -837,18 +843,18 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('concurrency: delayed get_filter', function (assert) {
+ QUnit.test('concurrency: delayed get_filter', async function (assert) {
assert.expect(3);
var def;
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
mockRPC: function (route, args) {
var result = this._super.apply(this, arguments);
if (args.method === 'search_panel_select_multi_range') {
- return $.when(def).then(_.constant(result));
+ return Promise.resolve(def).then(_.constant(result));
}
return result;
},
@@ -868,22 +874,24 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 4);
// trigger a reload and delay the get_filter
- def = $.Deferred();
+ def = testUtils.makeTestPromise();
kanban.reload({domain: [['id', '=', 1]]});
+ await testUtils.nextTick();
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 4);
def.resolve();
+ await testUtils.nextTick();
assert.containsOnce(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)');
kanban.destroy();
});
- QUnit.test('use filter (on many2one) to refine search', function (assert) {
+ QUnit.test('use filter (on many2one) to refine search', async function (assert) {
assert.expect(32);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -927,7 +935,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 3);
// check 'asustek'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
assert.containsOnce(kanban, '.o_search_panel_filter_value input:checked');
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -935,7 +943,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 2);
// check 'agrolait'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 2);
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -943,7 +951,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 3);
// uncheck 'asustek'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
assert.containsOnce(kanban, '.o_search_panel_filter_value input:checked');
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -951,7 +959,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 1);
// uncheck 'agrolait'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
assert.containsNone(kanban, '.o_search_panel_filter_value input:checked');
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -963,26 +971,26 @@ QUnit.module('Views', {
'[]',
'[["bar","=",true]]',
// 'asustek' checked
- '[["bar","=",true],["company_id","in",[3]]]',
'[["company_id","in",[3]]]',
+ '[["bar","=",true],["company_id","in",[3]]]',
// 'asustek' and 'agrolait' checked
- '[["bar","=",true],["company_id","in",[3,5]]]',
'[["company_id","in",[3,5]]]',
+ '[["bar","=",true],["company_id","in",[3,5]]]',
// 'agrolait' checked
- '[["bar","=",true],["company_id","in",[5]]]',
'[["company_id","in",[5]]]',
+ '[["bar","=",true],["company_id","in",[5]]]',
// nothing checked
- '[["bar","=",true]]',
'[]',
+ '[["bar","=",true]]',
]);
kanban.destroy();
});
- QUnit.test('use filter (on selection) to refine search', function (assert) {
+ QUnit.test('use filter (on selection) to refine search', async function (assert) {
assert.expect(32);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1026,7 +1034,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 3);
// check 'abc'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
assert.containsOnce(kanban, '.o_search_panel_filter_value input:checked');
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -1034,7 +1042,7 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 1);
// check 'def'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 2);
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -1042,7 +1050,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 2);
// uncheck 'abc'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
assert.containsOnce(kanban, '.o_search_panel_filter_value input:checked');
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -1050,7 +1058,7 @@ QUnit.module('Views', {
assert.containsOnce(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)');
// uncheck 'def'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
assert.containsNone(kanban, '.o_search_panel_filter_value input:checked');
assert.strictEqual(kanban.$('.o_search_panel_filter_value').text().replace(/\s/g, ''),
@@ -1062,26 +1070,26 @@ QUnit.module('Views', {
'[]',
'[["bar","=",true]]',
// 'asustek' checked
- '[["bar","=",true],["state","in",["abc"]]]',
'[["state","in",["abc"]]]',
+ '[["bar","=",true],["state","in",["abc"]]]',
// 'asustek' and 'agrolait' checked
- '[["bar","=",true],["state","in",["abc","def"]]]',
'[["state","in",["abc","def"]]]',
+ '[["bar","=",true],["state","in",["abc","def"]]]',
// 'agrolait' checked
- '[["bar","=",true],["state","in",["def"]]]',
'[["state","in",["def"]]]',
+ '[["bar","=",true],["state","in",["def"]]]',
// nothing checked
- '[["bar","=",true]]',
'[]',
+ '[["bar","=",true]]',
]);
kanban.destroy();
});
- QUnit.test('only reload filters when domains change', function (assert) {
+ QUnit.test('only reload filters when domains change', async function (assert) {
assert.expect(11);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1112,47 +1120,37 @@ QUnit.module('Views', {
]);
// go to page 2 (the domain doesn't change, so the filters should not be reloaded)
- testUtils.dom.click(kanban.$('.o_pager_next'));
+ await testUtils.dom.click(kanban.$('.o_pager_next'));
assert.verifySteps([
- 'search_panel_select_multi_range',
- '/web/dataset/search_read',
'/web/dataset/search_read',
]);
// reload with another domain, so the filters should be reloaded
- kanban.reload({domain: [['id', '<', 5]]});
+ await kanban.reload({domain: [['id', '<', 5]]});
assert.verifySteps([
'search_panel_select_multi_range',
'/web/dataset/search_read',
- '/web/dataset/search_read',
- '/web/dataset/search_read',
- 'search_panel_select_multi_range',
]);
// change category value, so the filters should be reloaded
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
assert.verifySteps([
'search_panel_select_multi_range',
'/web/dataset/search_read',
- '/web/dataset/search_read',
- '/web/dataset/search_read',
- 'search_panel_select_multi_range',
- '/web/dataset/search_read',
- 'search_panel_select_multi_range',
]);
kanban.destroy();
});
- QUnit.test('filter with groupby', function (assert) {
+ QUnit.test('filter with groupby', async function (assert) {
assert.expect(42);
this.data.company.records.push({id: 11, name: 'camptocamp', category_id: 7});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1200,7 +1198,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 3);
// check 'asustek'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:first input'));
assert.containsOnce(kanban, '.o_search_panel_filter_value input:checked');
var firstGroupCheckbox = kanban.$('.o_search_panel_filter_group:first > div > input').get(0);
@@ -1211,7 +1209,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 2);
// check 'agrolait'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 2);
var secondGroupCheckbox = kanban.$('.o_search_panel_filter_group:nth(1) > div > input').get(0);
@@ -1224,7 +1222,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 0);
// check 'camptocamp'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(2) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(2) input'));
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 3);
secondGroupCheckbox = kanban.$('.o_search_panel_filter_group:nth(1) > div > input').get(0);
@@ -1237,7 +1235,7 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)', 0);
// uncheck second group
- testUtils.dom.click(kanban.$('.o_search_panel_filter_group:nth(1) > div > input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_group:nth(1) > div > input'));
assert.containsOnce(kanban, '.o_search_panel_filter_value input:checked');
secondGroupCheckbox = kanban.$('.o_search_panel_filter_group:nth(1) > div > input').get(0);
@@ -1254,28 +1252,28 @@ QUnit.module('Views', {
'[]',
'[["bar","=",true]]',
// 'asustek' checked
- '[["bar","=",true],["company_id","in",[3]]]',
'[["company_id","in",[3]]]',
+ '[["bar","=",true],["company_id","in",[3]]]',
// 'asustek' and 'agrolait' checked
- '[["bar","=",true],["company_id","in",[3]],["company_id","in",[5]]]',
'[["company_id","in",[3]],["company_id","in",[5]]]',
+ '[["bar","=",true],["company_id","in",[3]],["company_id","in",[5]]]',
// 'asustek', 'agrolait' and 'camptocamp' checked
- '[["bar","=",true],["company_id","in",[3]],["company_id","in",[5,11]]]',
'[["company_id","in",[3]],["company_id","in",[5,11]]]',
+ '[["bar","=",true],["company_id","in",[3]],["company_id","in",[5,11]]]',
// 'asustek' checked
- '[["bar","=",true],["company_id","in",[3]]]',
'[["company_id","in",[3]]]',
+ '[["bar","=",true],["company_id","in",[3]]]',
]);
kanban.destroy();
});
- QUnit.test('filter with domain', function (assert) {
+ QUnit.test('filter with domain', async function (assert) {
assert.expect(3);
this.data.company.records.push({id: 40, name: 'child company 1', parent_id: 3});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1313,12 +1311,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('(un)fold filter group', function (assert) {
+ QUnit.test('(un)fold filter group', async function (assert) {
assert.expect(13);
this.data.company.records.push({id: 11, name: 'camptocamp', category_id: 7});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1340,13 +1338,13 @@ QUnit.module('Views', {
assert.containsN(kanban, '.o_search_panel_filter_value', 3);
// check 'agrolait'
- testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_value:nth(1) input'));
var secondGroupCheckbox = kanban.$('.o_search_panel_filter_group:nth(1) > div > input').get(0);
assert.strictEqual(secondGroupCheckbox.indeterminate, true);
assert.hasAttrValue(kanban.$('.o_search_panel_filter_value:nth(1) input'), 'checked', 'checked');
// fold second group
- testUtils.dom.click(kanban.$('.o_search_panel_filter_group:nth(1) .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_group:nth(1) .o_toggle_fold'));
assert.containsN(kanban, '.o_search_panel_filter_group', 2);
assert.containsOnce(kanban, '.o_search_panel_filter_value');
@@ -1354,13 +1352,13 @@ QUnit.module('Views', {
assert.strictEqual(secondGroupCheckbox.indeterminate, true);
// fold first group
- testUtils.dom.click(kanban.$('.o_search_panel_filter_group:first .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_group:first .o_toggle_fold'));
assert.containsN(kanban, '.o_search_panel_filter_group', 2);
assert.containsNone(kanban, '.o_search_panel_filter_value');
// unfold second group
- testUtils.dom.click(kanban.$('.o_search_panel_filter_group:nth(1) .o_toggle_fold'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter_group:nth(1) .o_toggle_fold'));
assert.containsN(kanban, '.o_search_panel_filter_group', 2);
assert.containsN(kanban, '.o_search_panel_filter_value', 2);
@@ -1371,10 +1369,10 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('filter with domain depending on category', function (assert) {
+ QUnit.test('filter with domain depending on category', async function (assert) {
assert.expect(22);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1408,7 +1406,7 @@ QUnit.module('Views', {
});
// select 'gold' category
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(1) header'));
assert.containsOnce(kanban, '.o_search_panel_category_value .active');
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(1) .active');
@@ -1417,7 +1415,7 @@ QUnit.module('Views', {
"asustek1");
// select 'silver' category
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:nth(2) header'));
assert.containsOnce(kanban, '.o_search_panel_category_value:nth(2) .active');
assert.containsOnce(kanban, '.o_search_panel_filter_value');
@@ -1425,7 +1423,7 @@ QUnit.module('Views', {
"agrolait2");
// select All
- testUtils.dom.click(kanban.$('.o_search_panel_category_value:first header'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_category_value:first header'));
assert.containsOnce(kanban, '.o_search_panel_category_value:first .active');
assert.containsNone(kanban, '.o_search_panel_filter_value');
@@ -1444,14 +1442,14 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('specify active filter values in context', function (assert) {
+ QUnit.test('specify active filter values in context', async function (assert) {
assert.expect(4);
var expectedDomain = [
['company_id', 'in', [5]],
['state', 'in', ['abc', 'ghi']],
];
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1483,17 +1481,17 @@ QUnit.module('Views', {
// manually untick a default value
expectedDomain = [['state', 'in', ['abc', 'ghi']]];
- testUtils.dom.click(kanban.$('.o_search_panel_filter:first .o_search_panel_filter_value:nth(1) input'));
+ await testUtils.dom.click(kanban.$('.o_search_panel_filter:first .o_search_panel_filter_value:nth(1) input'));
assert.containsN(kanban, '.o_search_panel_filter_value input:checked', 2);
kanban.destroy();
});
- QUnit.test('retrieved filter value from context does not exist', function (assert) {
+ QUnit.test('retrieved filter value from context does not exist', async function (assert) {
assert.expect(1);
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
@@ -1522,12 +1520,12 @@ QUnit.module('Views', {
kanban.destroy();
});
- QUnit.test('filter with groupby and default values in context', function (assert) {
+ QUnit.test('filter with groupby and default values in context', async function (assert) {
assert.expect(2);
this.data.company.records.push({id: 11, name: 'camptocamp', category_id: 7});
- var kanban = createView({
+ var kanban = await createView({
View: KanbanView,
model: 'partner',
data: this.data,
diff --git a/addons/web/static/tests/views/search_view_tests.js b/addons/web/static/tests/views/search_view_tests.js
index 4916834e1bc..e57194ef19c 100644
--- a/addons/web/static/tests/views/search_view_tests.js
+++ b/addons/web/static/tests/views/search_view_tests.js
@@ -266,34 +266,34 @@ QUnit.module('Search View', {
];
},
}, function () {
- QUnit.test('basic rendering', function (assert) {
+ QUnit.test('basic rendering', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
assert.strictEqual($('.o_searchview input.o_searchview_input')[0], document.activeElement,
"searchview input should be focused");
actionManager.destroy();
});
- QUnit.test('navigation with facets', function (assert) {
+ QUnit.test('navigation with facets', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
// add a facet
- testUtils.dom.click(actionManager.$('.o_dropdown_toggler_btn:contains(Group By)'));
- testUtils.dom.click(actionManager.$('.o_menu_item a'));
+ await testUtils.dom.click(actionManager.$('.o_dropdown_toggler_btn:contains(Group By)'));
+ await testUtils.dom.click(actionManager.$('.o_menu_item a'));
assert.strictEqual(actionManager.$('.o_searchview .o_searchview_facet').length, 1,
"there should be one facet");
assert.strictEqual(actionManager.$('.o_searchview input.o_searchview_input')[0], document.activeElement,
@@ -320,110 +320,111 @@ QUnit.module('Search View', {
QUnit.module('GroupByMenu');
- QUnit.test('click on groupby filter adds a facet', function (assert) {
+ QUnit.test('click on groupby filter adds a facet', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
- testUtils.dom.click($('.o_dropdown_toggler_btn:contains(Group By)'));
- testUtils.dom.click($('.o_menu_item a'));
+
+ await actionManager.doAction(1);
+ await testUtils.dom.click($('.o_dropdown_toggler_btn:contains(Group By)'));
+ await testUtils.dom.click($('.o_menu_item a'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'candle',
'should have a facet with candle name');
actionManager.destroy();
});
- QUnit.test('remove a "Group By" facet properly unchecks groupbys in groupby menu', function (assert) {
+ QUnit.test('remove a "Group By" facet properly unchecks groupbys in groupby menu', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
- testUtils.dom.click($('.o_dropdown_toggler_btn:contains(Group By)'));
- testUtils.dom.click($('.o_menu_item a'));
+ await actionManager.doAction(1);
+ await testUtils.dom.click($('.o_dropdown_toggler_btn:contains(Group By)'));
+ await testUtils.dom.click($('.o_menu_item a'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'candle',
'should have a facet with candle name');
- testUtils.dom.click($('.o_facet_remove:first'));
+ await testUtils.dom.click($('.o_facet_remove:first'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0,
'there should be no facet');
actionManager.destroy();
});
- QUnit.test('change option of a "Group By" does not remove groupy in facet "Group By"', function (assert) {
+ QUnit.test('change option of a "Group By" does not remove groupy in facet "Group By"', async function (assert) {
assert.expect(3);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(2);
- testUtils.dom.click($('span.fa-bars'));
- testUtils.dom.click($('.o_submenu_switcher'));
+ await actionManager.doAction(2);
+ await testUtils.dom.click($('span.fa-bars'));
+ await testUtils.dom.click($('.o_submenu_switcher'));
// Don't forget there is a hidden li.divider element at first place among children
- testUtils.dom.click($('.o_item_option:nth-child(2)'));
+ await testUtils.dom.click($('.o_item_option:nth-child(2)'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 1,
'should have a facet');
- testUtils.dom.click($('.o_item_option:nth-child(3)'));
+ await testUtils.dom.click($('.o_item_option:nth-child(3)'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 1,
'should have a facet');
- testUtils.dom.click($('.o_item_option:nth-child(3)'));
+ await testUtils.dom.click($('.o_item_option:nth-child(3)'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0,
'should have no facet');
actionManager.destroy();
});
- QUnit.test('select and unselect quickly groupby does not crash', function (assert) {
+ QUnit.test('select and unselect quickly groupby does not crash', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(3);
- testUtils.dom.click($('span.fa-bars'));
- testUtils.dom.click($('.o_menu_item:first'));
- testUtils.dom.click($('.o_menu_item:first'));
+ await actionManager.doAction(3);
+ await testUtils.dom.click($('span.fa-bars'));
+ await testUtils.dom.click($('.o_menu_item:first'));
+ await testUtils.dom.click($('.o_menu_item:first'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0,
'should have a facet');
actionManager.destroy();
});
- QUnit.test('groupby selected within graph subview are not deleted when modifying search view content', function (assert) {
+ QUnit.test('groupby selected within graph subview are not deleted when modifying search view content', async function (assert) {
assert.expect(2);
this.actions[3].flags = {isEmbedded: true};
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(4);
- testUtils.dom.click($('.o_graph_controller .o_control_panel .o_cp_buttons button').eq(1));
- testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item').eq(1));
- testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item .o_item_option > .dropdown-item').first());
+ await actionManager.doAction(4);
+ await testUtils.dom.click($('.o_graph_controller .o_control_panel .o_cp_buttons button').eq(1));
+ await testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item').eq(1));
+ await testUtils.dom.click($('.o_graph_controller .o_group_by_menu .o_menu_item .o_item_option > .dropdown-item').first());
assert.doesNotHaveClass($('.o_graph_controller .o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected',
'groupby should be unselected');
- testUtils.dom.click($('.o_search_options button span.fa-filter'));
- testUtils.dom.click($('.o_filters_menu .o_menu_item a').first());
+ await testUtils.dom.click($('.o_search_options button span.fa-filter'));
+ await testUtils.dom.click($('.o_filters_menu .o_menu_item a').first());
assert.doesNotHaveClass($('.o_graph_controller .o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected',
'groupby should be still unselected');
actionManager.destroy();
});
- QUnit.test('group by a date field using interval works', function (assert) {
+ QUnit.test('group by a date field using interval works', async function (assert) {
assert.expect(13);
@@ -434,7 +435,7 @@ QUnit.module('Search View', {
["birthday:year"],
];
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -446,67 +447,67 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(5);
+ await actionManager.doAction(5);
// open menu 'Group By'
- testUtils.dom.click($('.o_search_options .fa-bars'));
+ await testUtils.dom.click($('.o_search_options .fa-bars'));
// Activate the groupby 'Date'
- testUtils.dom.click($('.o_group_by_menu .o_menu_item'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item'));
// // select option 'day'
- testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]'));
assert.strictEqual($('div.o_facet_values span').text().trim(),'Date: Day');
assert.strictEqual($('.o_content tr.o_group_header').length, 5);
// // select option 'month'
- testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]'));
// // data should be grouped by the field 'Date' using the interval 'month'
assert.strictEqual($('div.o_facet_values span').text().trim(),'Date: Month');
assert.strictEqual($('.o_content tr.o_group_header').length, 3);
// // deactivate option 'month'
- testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="month"]'));
// // no groupby is applied
assert.strictEqual($('div.o_facet_values span').length, 0);
// // open 'Add custom Groupby' menu
- testUtils.dom.click($('.o_group_by_menu .o_add_custom_group'));
+ await testUtils.dom.click($('.o_group_by_menu .o_add_custom_group'));
// // click on 'Apply' button
- testUtils.dom.click($('.o_group_by_menu .o_generator_menu button'));
+ await testUtils.dom.click($('.o_group_by_menu .o_generator_menu button'));
// // data should be grouped by the field 'Birthday' using the interval 'month'
assert.strictEqual($('div.o_facet_values span').text().trim(),'Birthday: Month');
assert.strictEqual($('.o_content tr.o_group_header').length, 5);
// // open submenu with interval options
- testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_submenu_switcher').eq(1));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_submenu_switcher').eq(1));
// // select option 'year'
- testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option').eq(9));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option').eq(9));
// // data should be grouped by the field 'Birthday' using the interval 'year'
assert.strictEqual($('div.o_facet_values span').text().trim(),'Birthday: Year');
assert.strictEqual($('.o_content tr.o_group_header').length, 4);
actionManager.destroy();
});
- QUnit.test('a separator in groupbys does not cause problems', function (assert) {
+ QUnit.test('a separator in groupbys does not cause problems', async function (assert) {
assert.expect(6);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(7);
+ await actionManager.doAction(7);
// open menu 'Group By'
- testUtils.dom.click($('span.fa-bars'));
+ await testUtils.dom.click($('span.fa-bars'));
// open options menu
- testUtils.dom.click($('.o_group_by_menu .o_menu_item a:first'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item a:first'));
// activate groupby with 'day' option
- testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item .o_item_option[data-option_id="day"]'));
// activate the second groupby
- testUtils.dom.click($('.o_group_by_menu .o_menu_item > a').eq(1));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item > a').eq(1));
assert.strictEqual($('.o_group_by_menu .o_menu_item').length, 2);
assert.strictEqual($('.o_group_by_menu .o_menu_item > .dropdown-item.selected').length, 2);
// deactivate second groupby
- testUtils.dom.click($('.o_group_by_menu .o_menu_item > a').eq(1));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item > a').eq(1));
assert.hasClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(0), 'selected');
assert.doesNotHaveClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected');
// remove facet
- testUtils.dom.click($('.o_facet_remove'));
+ await testUtils.dom.click($('.o_facet_remove'));
assert.doesNotHaveClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(0), 'selected');
assert.doesNotHaveClass($('.o_group_by_menu .o_menu_item > .dropdown-item').eq(1), 'selected');
actionManager.destroy();
@@ -514,22 +515,24 @@ QUnit.module('Search View', {
QUnit.module('FilterMenu');
- QUnit.test('Search date and datetime fields. Support of timezones', function (assert) {
+ QUnit.test('Search date and datetime fields. Support of timezones', async function (assert) {
assert.expect(4);
this.data.partner.fields.birth_datetime = {string: "Birth DateTime", type: "datetime", store: true, sortable: true};
this.data.partner.records = this.data.partner.records.slice(0,-1); // exclude wrong date record
- function stringToEvent ($element, string) {
+ async function stringToEvent ($element, string) {
for (var i = 0; i < string.length; i++) {
var keyAscii = string.charCodeAt(i);
$element.val($element.val()+string[i]);
+ await testUtils.nextTick();
$element.trigger($.Event('keyup', {which: keyAscii, keyCode:keyAscii}));
+ await testUtils.nextTick();
}
}
var searchReadSequence = 0;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: [{
id: 11,
name: 'Partners Action 11',
@@ -571,31 +574,23 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(11);
+ await actionManager.doAction(11);
// Date case
var $autocomplete = $('.o_searchview_input');
- stringToEvent($autocomplete, '07/15/1983');
-
- $autocomplete.trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
+ await stringToEvent($autocomplete, '07/15/1983');
+ await testUtils.fields.triggerKey('up', $autocomplete, 'enter');
assert.equal($('.o_searchview_facet .o_facet_values').text().trim(), '07/15/1983',
'The format of the date in the facet should be in locale');
// Close Facet
- $('.o_searchview_facet .o_facet_remove').click();
+ await testUtils.dom.click($('.o_searchview_facet .o_facet_remove'));
// DateTime case
$autocomplete = $('.o_searchview_input');
- stringToEvent($autocomplete, '07/15/1983 00:00:00');
-
- $autocomplete.trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
+ await stringToEvent($autocomplete, '07/15/1983 00:00:00');
+ await testUtils.fields.triggerKey('up', $autocomplete, 'enter');
assert.equal($('.o_searchview_facet .o_facet_values').text().trim(), '07/15/1983 00:00:00',
'The format of the datetime in the facet should be in locale');
@@ -603,44 +598,44 @@ QUnit.module('Search View', {
actionManager.destroy();
});
- QUnit.test('add a custom filter works', function (assert) {
+ QUnit.test('add a custom filter works', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
- testUtils.dom.click($('span.fa-filter'));
- testUtils.dom.click($('.o_add_custom_filter'));
- testUtils.dom.click($('.o_apply_filter'));
+ await actionManager.doAction(1);
+ await testUtils.dom.click($('span.fa-filter'));
+ await testUtils.dom.click($('.o_add_custom_filter'));
+ await testUtils.dom.click($('.o_apply_filter'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').text().trim(), 'ID is \"0\"',
'should have a facet with candle name');
actionManager.destroy();
});
- QUnit.test('deactivate a new custom filter works', function (assert) {
+ QUnit.test('deactivate a new custom filter works', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
- testUtils.dom.click($('span.fa-filter'));
- testUtils.dom.click($('.o_add_custom_filter'));
- testUtils.dom.click($('.o_apply_filter'));
- testUtils.dom.click($('.o_menu_item'));
+ await actionManager.doAction(1);
+ await testUtils.dom.click($('span.fa-filter'));
+ await testUtils.dom.click($('.o_add_custom_filter'));
+ await testUtils.dom.click($('.o_apply_filter'));
+ await testUtils.dom.click($('.o_menu_item'));
assert.strictEqual($('.o_searchview .o_searchview_facet .o_facet_values span').length, 0,
'no facet should be in the search view');
actionManager.destroy();
});
- QUnit.test('filter by a date field using period works', function (assert) {
+ QUnit.test('filter by a date field using period works', async function (assert) {
assert.expect(15);
var self = this;
@@ -659,7 +654,7 @@ QUnit.module('Search View', {
return new Date(2017,2,22);
};
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -671,12 +666,12 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(5);
+ await actionManager.doAction(5);
// open menu 'Filter'
- testUtils.dom.click($('.o_search_options .fa-filter'));
+ await testUtils.dom.click($('.o_search_options .fa-filter'));
// open menu options
- testUtils.dom.click($('.o_menu_item'));
+ await testUtils.dom.click($('.o_menu_item'));
var periodOptions = $('.o_menu_item .o_item_option').map(function () {
return $(this).data('option_id');
@@ -685,33 +680,33 @@ QUnit.module('Search View', {
assert.deepEqual(periodOptions, PERIOD_OPTIONS_IDS,
"13 period options should be available:");
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_7_days"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_30_days"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_365_days"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_5_years"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="today"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_week"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_month"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_quarter"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_year"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="yesterday"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_week"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_month"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_quarter"]'));
- testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_year"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_7_days"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_30_days"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_365_days"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_5_years"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="today"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_week"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_month"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_quarter"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="this_year"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="yesterday"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_week"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_month"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_quarter"]'));
+ await testUtils.dom.click($('.o_menu_item .o_item_option[data-option_id="last_year"]'));
actionManager.destroy();
window.Date = RealDate;
});
- QUnit.test('`context` key in <filter> is used', function (assert) {
+ QUnit.test('`context` key in <filter> is used', async function (assert) {
assert.expect(3);
this.archs['partner,4,search'] = '<search>'+
'<filter string="AAA" name="some_filter" context="{\'coucou_1\': 1}"></filter>' +
'</search>';
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -723,11 +718,11 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(5);
+ await actionManager.doAction(5);
// select filter
- testUtils.dom.click($('.o_search_options .fa-filter'));
- testUtils.dom.click($('.o_menu_item:contains(AAA)'));
+ await testUtils.dom.click($('.o_search_options .fa-filter'));
+ await testUtils.dom.click($('.o_menu_item:contains(AAA)'));
assert.verifySteps([
"{}",
@@ -739,10 +734,10 @@ QUnit.module('Search View', {
QUnit.module('Favorites Menu');
- QUnit.test('dynamic filters are saved dynamic', function (assert) {
+ QUnit.test('dynamic filters are saved dynamic', async function (assert) {
assert.expect(1);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -758,18 +753,18 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(6);
- testUtils.dom.click($('span.fa-filter'));
- testUtils.dom.click($('.o_filters_menu .o_menu_item a'));
- testUtils.dom.click($('.o_item_option[data-option_id="today"]'));
- testUtils.dom.click($('span.fa-star'));
- testUtils.dom.click($('.o_favorites_menu .o_add_favorite'));
- testUtils.fields.editInput($('div.o_favorite_name input'), 'name for favorite');
- testUtils.dom.click($('.o_favorites_menu .o_save_favorite button'));
+ await actionManager.doAction(6);
+ await testUtils.dom.click($('span.fa-filter'));
+ await testUtils.dom.click($('.o_filters_menu .o_menu_item a'));
+ await testUtils.dom.click($('.o_item_option[data-option_id="today"]'));
+ await testUtils.dom.click($('span.fa-star'));
+ await testUtils.dom.click($('.o_favorites_menu .o_add_favorite'));
+ await testUtils.fields.editInput($('div.o_favorite_name input'), 'name for favorite');
+ await testUtils.dom.click($('.o_favorites_menu .o_save_favorite button'));
actionManager.destroy();
});
- QUnit.test('save search filter in modal', function (assert) {
+ QUnit.test('save search filter in modal', async function (assert) {
assert.expect(5);
this.data.partner.records.push({
id: 7,
@@ -785,7 +780,7 @@ QUnit.module('Search View', {
display_name: "Partner 9",
});
this.data.partner.fields.date_field.searchable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -803,39 +798,39 @@ QUnit.module('Search View', {
res_id: 1,
});
- testUtils.form.clickEdit(form);
+ await testUtils.form.clickEdit(form);
- testUtils.fields.many2one.clickOpenDropdown('bar');
- testUtils.fields.many2one.clickItem('bar','Search');
+ await testUtils.fields.many2one.clickOpenDropdown('bar');
+ await testUtils.fields.many2one.clickItem('bar','Search');
assert.strictEqual($('tr.o_data_row').length, 9, "should display 9 records");
- testUtils.dom.click($('button:contains(Filters)'));
- testUtils.dom.click($('.o_add_custom_filter:visible'));
+ await testUtils.dom.click($('button:contains(Filters)'));
+ await testUtils.dom.click($('.o_add_custom_filter:visible'));
assert.strictEqual($('.o_filter_condition select.o_searchview_extended_prop_field').val(), 'date_field',
"date field should be selected");
- testUtils.dom.click($('.o_apply_filter'));
+ await testUtils.dom.click($('.o_apply_filter'));
assert.strictEqual($('tr.o_data_row').length, 0, "should display 0 records");
// Save this search
- testUtils.mock.intercept(form, 'create_filter', function (event) {
+ await testUtils.mock.intercept(form, 'create_filter', function (event) {
assert.strictEqual(event.data.filter.name, "Awesome Test Customer Filter", "filter name should be correct");
});
- testUtils.dom.click($('button:contains(Favorites)'));
- testUtils.dom.click($('.o_add_favorite'));
+ await testUtils.dom.click($('button:contains(Favorites)'));
+ await testUtils.dom.click($('.o_add_favorite'));
var filterNameInput = $('.o_favorite_name .o_input[type="text"]:visible');
assert.strictEqual(filterNameInput.length, 1, "should display an input field for the filter name");
- testUtils.fields.editInput(filterNameInput, 'Awesome Test Customer Filter');
- testUtils.dom.click($('.o_save_favorite button'));
+ await testUtils.fields.editInput(filterNameInput, 'Awesome Test Customer Filter');
+ await testUtils.dom.click($('.o_save_favorite button'));
form.destroy();
});
- QUnit.test('save filters created via autocompletion works', function (assert) {
+ QUnit.test('save filters created via autocompletion works', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -846,37 +841,40 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(10);
+ await actionManager.doAction(10);
$('.o_searchview_input').trigger($.Event('keypress', {
which: 97,
}));
-
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keyup', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
+ await testUtils.nextTick();
+
+ await testUtils.nextTick();
assert.strictEqual($('.o_searchview_input_container .o_facet_values span').text().trim(), "a");
- testUtils.dom.click($('button .fa-star'));
- testUtils.dom.click($('.o_favorites_menu .o_add_favorite'));
- testUtils.fields.editInput($('div.o_favorite_name input'), 'name for favorite');
- testUtils.dom.click($('.o_favorites_menu div.o_save_favorite button'));
+ await testUtils.dom.click($('button .fa-star'));
+ await testUtils.dom.click($('.o_favorites_menu .o_add_favorite'));
+ await testUtils.fields.editInput($('div.o_favorite_name input'), 'name for favorite');
+ await testUtils.dom.click($('.o_favorites_menu div.o_save_favorite button'));
actionManager.destroy();
});
- QUnit.test('delete an active favorite remove it both in list of favorite and in search bar', function (assert) {
+ QUnit.test('delete an active favorite remove it both in list of favorite and in search bar', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
intercepts: {
load_filters: function (event) {
- return $.when([{
+ return Promise.resolve([{
context: "{}",
domain: "[]",
id: 7,
@@ -892,11 +890,11 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(6);
- testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options button.o_favorites_menu_button'));
+ await actionManager.doAction(6);
+ await testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options button.o_favorites_menu_button'));
assert.containsOnce(actionManager, '.o_control_panel .o_searchview_input_container .o_facet_values');
- testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options .o_favorites_menu span.o_trash_button'));
- testUtils.modal.clickButton('Ok');
+ await testUtils.dom.click(actionManager.$('.o_control_panel .o_search_options .o_favorites_menu span.o_trash_button'));
+ await testUtils.modal.clickButton('Ok');
assert.containsNone(actionManager, '.o_control_panel .o_searchview_input_container .o_facet_values');
actionManager.destroy();
});
@@ -910,7 +908,7 @@ QUnit.module('Search View', {
data: this.data,
intercepts: {
load_filters: function (event) {
- return $.when([{
+ return Promise.resolve([{
context: "{}",
domain: "[]",
id: 7,
@@ -932,17 +930,17 @@ QUnit.module('Search View', {
QUnit.module('Search Arch');
- QUnit.test('arch order of groups of filters preserved', function (assert) {
+ QUnit.test('arch order of groups of filters preserved', async function (assert) {
assert.expect(12);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(8);
- testUtils.dom.click($('span.fa-filter'));
+ await actionManager.doAction(8);
+ await testUtils.dom.click($('span.fa-filter'));
assert.strictEqual($('.o_filters_menu .o_menu_item').length, 11);
for (var i = 0; i < 11; i++) {
assert.strictEqual($('.o_filters_menu .o_menu_item').eq(i).text().trim(), (i+1).toString());
@@ -952,34 +950,21 @@ QUnit.module('Search View', {
QUnit.module('Autocompletion');
- QUnit.test('selection via autocompletion modifies appropriately submenus', function (assert) {
+ QUnit.test('selection via autocompletion modifies appropriately submenus', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(9);
+ await actionManager.doAction(9);
- $('.o_searchview_input').trigger($.Event('keypress', {
- which: 97,
- }));
-
- $('.o_searchview_input').trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
-
- $('.o_searchview_input').trigger($.Event('keypress', {
- which: 103,
- }));
-
- $('.o_searchview_input').trigger($.Event('keyup', {
- which: $.ui.keyCode.ENTER,
- keyCode: $.ui.keyCode.ENTER,
- }));
+ await testUtils.fields.triggerKey('press', $('.o_searchview_input'), 97);
+ await testUtils.fields.triggerKey('up', $('.o_searchview_input'), 'enter');
+ await testUtils.fields.triggerKey('press', $('.o_searchview_input'), 103);
+ await testUtils.fields.triggerKey('up', $('.o_searchview_input'), 'enter');
assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(),
"Date Field Filter: This Month",
@@ -988,28 +973,27 @@ QUnit.module('Search View', {
"Date Field Groupby: Day",
"There should be a filter facet with label 'Date Field Groupby: Day'");
- testUtils.dom.click($('button .fa-filter'));
- testUtils.dom.click($('.o_filters_menu .o_menu_item').eq(0));
+ await testUtils.dom.click($('button .fa-filter'));
+ await testUtils.dom.click($('.o_filters_menu .o_menu_item').eq(0));
assert.strictEqual($('.o_filters_menu .o_item_option a.selected').text().trim(), "This Month",
"The item 'This Month' should be selected in the filters menu");
- testUtils.dom.click($('button .fa-bars'));
- testUtils.dom.click($('.o_group_by_menu .o_menu_item').eq(0));
+ await testUtils.dom.click($('button .fa-bars'));
+ await testUtils.dom.click($('.o_group_by_menu .o_menu_item').eq(0));
assert.strictEqual($('.o_group_by_menu .o_item_option a.selected').text().trim(), "Day",
"The item 'Day' should be selected in the groupby menu");
actionManager.destroy();
});
- QUnit.test('select an autocomplete field with `context` key', function (assert) {
+ QUnit.test('select an autocomplete field with `context` key', async function (assert) {
assert.expect(9);
var searchRead = 0;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
- debug: 1,
mockRPC: function (route, args) {
if (route === '/web/dataset/search_read') {
if (searchRead === 1) {
@@ -1025,17 +1009,24 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(11);
+ await actionManager.doAction(11);
+ await testUtils.nextTick();
assert.strictEqual(searchRead, 1, "there should be 1 search_read");
// 'r' key to filter on bar "First Record"
$('.o_searchview_input').val('r');
$('.o_searchview_input').trigger($.Event('keypress', { which: 82, keyCode: 82 }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.RIGHT, keyCode: $.ui.keyCode.RIGHT }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER }));
+ await testUtils.nextTick();
+ await testUtils.nextTick();
assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), "First record",
"the autocompletion facet should be correct");
assert.strictEqual(searchRead, 2, "there should be 2 search_read");
@@ -1043,11 +1034,16 @@ QUnit.module('Search View', {
// 'r' key to filter on bar "Second Record"
$('.o_searchview_input').val('r');
$('.o_searchview_input').trigger($.Event('keypress', { which: 82, keyCode: 82 }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.RIGHT, keyCode: $.ui.keyCode.RIGHT }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN }));
+ await testUtils.nextTick();
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.DOWN, keyCode: $.ui.keyCode.DOWN }));
$('.o_searchview_input').trigger($.Event('keydown', { which: $.ui.keyCode.ENTER, keyCode: $.ui.keyCode.ENTER }));
+ await testUtils.nextTick();
assert.strictEqual($('.o_searchview_input_container .o_facet_values').eq(0).text().trim(), "First record or Second record",
"the autocompletion facet should be correct");
@@ -1056,10 +1052,10 @@ QUnit.module('Search View', {
actionManager.destroy();
});
- QUnit.test('no search text triggers a reload', function (assert) {
+ QUnit.test('no search text triggers a reload', async function (assert) {
assert.expect(2);
var rpcs = 0;
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1069,16 +1065,19 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction(10);
+ await actionManager.doAction(10);
rpcs = 0;
$('.o_searchview_input').trigger($.Event('keydown', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
+ await testUtils.nextTick();
+
$('.o_searchview_input').trigger($.Event('keyup', {
which: $.ui.keyCode.ENTER,
keyCode: $.ui.keyCode.ENTER,
}));
+ await testUtils.nextTick();
assert.containsNone(actionManager, '.o_searchview_facet_label');
assert.strictEqual(rpcs, 2, "should have reloaded");
@@ -1088,16 +1087,16 @@ QUnit.module('Search View', {
QUnit.module('TimeRangeMenu');
- QUnit.test('time range menu stays hidden', function (assert) {
+ QUnit.test('time range menu stays hidden', async function (assert) {
assert.expect(4);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
});
- actionManager.doAction(1);
+ await actionManager.doAction(1);
// check that there is no time range menu
assert.containsNone(actionManager, '.o_control_panel .o_search_options .o_time_range_menu');
@@ -1105,8 +1104,8 @@ QUnit.module('Search View', {
assert.strictEqual($('.o_facet_values').length, 0);
// activate groupby
- testUtils.dom.click($('button .fa-bars'));
- testUtils.dom.click($('.o_menu_item a').eq(0));
+ await testUtils.dom.click($('button .fa-bars'));
+ await testUtils.dom.click($('.o_menu_item a').eq(0));
// check that there is a facet
assert.strictEqual($('div.o_facet_values').length, 1);
// check that there is still no time range menu
@@ -1114,7 +1113,7 @@ QUnit.module('Search View', {
actionManager.destroy();
});
- QUnit.test('time range menu in comparison mode', function (assert) {
+ QUnit.test('time range menu in comparison mode', async function (assert) {
assert.expect(46);
var self = this;
@@ -1123,7 +1122,7 @@ QUnit.module('Search View', {
var periodOptionText, periodOptionValue;
var unpatchDate = patchDate(2017, 2, 22, 1, 0, 0);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1149,7 +1148,7 @@ QUnit.module('Search View', {
},
});
// time range menu should be available in graph view
- actionManager.doAction(4);
+ await actionManager.doAction(4);
var $timeRangeMenu = $('.o_time_range_menu');
assert.strictEqual($timeRangeMenu.not('.o_hidden').length, 1,
@@ -1164,35 +1163,34 @@ QUnit.module('Search View', {
assert.deepEqual(periodOptions, PERIOD_OPTIONS_IDS,
"13 period options should be available:");
- $periodOptions.each(function () {
- periodOptionText = $(this).text().trim();
- periodOptionValue = $(this).val();
+ for (var option of $periodOptions) {
+ periodOptionText = $(option).text().trim();
+ periodOptionValue = $(option).val();
// opens time range menu dropdown
- testUtils.dom.click($('.o_time_range_menu_button'));
+ await testUtils.dom.click($('.o_time_range_menu_button'));
var $timeRangeMenu = $('.o_time_range_menu');
// comparison is not checked by default
if (!$timeRangeMenu.find('.o_comparison_checkbox').is(':checked')) {
- testUtils.dom.click($timeRangeMenu.find('.o_comparison_checkbox'));
+ await testUtils.dom.click($timeRangeMenu.find('.o_comparison_checkbox'));
assert.strictEqual($('.o_comparison_time_range_selector:visible').length, 1,
"Comparison has to be checked (only at the first time)");
}
// select one period option to test it
$timeRangeMenu.find('.o_time_range_selector').val(periodOptionValue);
// apply
- testUtils.dom.click($timeRangeMenu.find('.o_apply_range'));
+ await testUtils.dom.click($timeRangeMenu.find('.o_apply_range'));
assert.strictEqual($('.o_facet_values').text().trim(),
"Date: " + periodOptionText + " / Previous Period",
"Facet should be updated with this period: " + periodOptionValue);
- });
-
+ }
unpatchDate();
actionManager.destroy();
});
- QUnit.test('a default time range only in context is taken into account', function (assert) {
+ QUnit.test('a default time range only in context is taken into account', async function (assert) {
assert.expect(2);
- var actionManager = createActionManager({
+ var actionManager = await createActionManager({
actions: this.actions,
archs: this.archs,
data: this.data,
@@ -1206,7 +1204,7 @@ QUnit.module('Search View', {
},
});
- actionManager.doAction({
+ await actionManager.doAction({
res_model: 'partner',
type: 'ir.actions.act_window',
views: [[false, 'pivot']],
@@ -1215,7 +1213,7 @@ QUnit.module('Search View', {
actionManager.destroy();
});
- QUnit.test('Customizing filter does not close the filter dropdown', function (assert) {
+ QUnit.test('Customizing filter does not close the filter dropdown', async function (assert) {
assert.expect(3);
var self = this;
@@ -1225,7 +1223,7 @@ QUnit.module('Search View', {
});
this.data.partner.fields.date_field.searchable = true;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -1242,25 +1240,26 @@ QUnit.module('Search View', {
res_id: 1,
});
- testUtils.fields.many2one.clickOpenDropdown('bar');
- testUtils.fields.many2one.clickItem('bar', 'Search More');
+ await testUtils.fields.many2one.clickOpenDropdown('bar');
+ await testUtils.fields.many2one.clickItem('bar', 'Search More');
assert.containsOnce(document.body, '.modal');
- testUtils.dom.click($('.modal .o_filters_menu_button'));
+ await testUtils.dom.click($('.modal .o_filters_menu_button'));
var $filterDropdown = $('.modal .o_filters_menu');
- testUtils.dom.click($filterDropdown.find('.o_add_custom_filter'));
+ await testUtils.dom.click($filterDropdown.find('.o_add_custom_filter'));
assert.containsN($filterDropdown, '.o_input', 3);
// We really are interested in the click event
// We do it twice on each input to make sure
// the parent dropdown doesn't react to any of it
- _.each($filterDropdown.find('input'), function (input) {
+ _.each($filterDropdown.find('input'), async function (input) {
var $input = $(input);
$input.click();
$input.click();
+ await testUtils.nextTick();
});
assert.isVisible($filterDropdown);
diff --git a/addons/web/static/tests/views/view_dialogs_tests.js b/addons/web/static/tests/views/view_dialogs_tests.js
index 27275e7fd80..b17112c8978 100644
--- a/addons/web/static/tests/views/view_dialogs_tests.js
+++ b/addons/web/static/tests/views/view_dialogs_tests.js
@@ -52,7 +52,6 @@ QUnit.module('Views', {
},
};
},
-
}, function () {
QUnit.module('view_dialogs');
@@ -64,7 +63,7 @@ QUnit.module('Views', {
return widget;
}
- QUnit.test('formviewdialog buttons in footer are positioned properly', function (assert) {
+ QUnit.test('formviewdialog buttons in footer are positioned properly', async function (assert) {
assert.expect(2);
var parent = createParent({
@@ -84,6 +83,7 @@ QUnit.module('Views', {
res_model: 'partner',
res_id: 1,
}).open();
+ await testUtils.nextTick();
assert.notOk($('.modal-body button').length,
"should not have any button in body");
@@ -92,7 +92,7 @@ QUnit.module('Views', {
parent.destroy();
});
- QUnit.test('formviewdialog buttons in footer are not duplicated', function (assert) {
+ QUnit.test('formviewdialog buttons in footer are not duplicated', async function (assert) {
assert.expect(2);
this.data.partner.fields.poney_ids = {string: "Poneys", type: "one2many", relation: 'partner'};
this.data.partner.records[0].poney_ids = [];
@@ -112,22 +112,20 @@ QUnit.module('Views', {
res_model: 'partner',
res_id: 1,
}).open();
+ await testUtils.nextTick();
assert.strictEqual($('.modal button.btn-primary').length, 1,
"should have 1 buttons in modal");
- testUtils.dom.click($('.o_field_x2many_list_row_add a'));
- $('input.o_input').trigger($.Event('keydown', {
- which: $.ui.keyCode.ESCAPE,
- keyCode: $.ui.keyCode.ESCAPE,
- }));
+ await testUtils.dom.click($('.o_field_x2many_list_row_add a'));
+ await testUtils.fields.triggerKeydown($('input.o_input'), 'escape');
assert.strictEqual($('.modal button.btn-primary').length, 1,
"should still have 1 buttons in modal");
parent.destroy();
});
- QUnit.test('SelectCreateDialog use domain, group_by and search default', function (assert) {
+ QUnit.test('SelectCreateDialog use domain, group_by and search default', async function (assert) {
assert.expect(3);
var search = 0;
@@ -183,7 +181,8 @@ QUnit.module('Views', {
},
});
- var dialog = new dialogs.SelectCreateDialog(parent, {
+ var dialog;
+ new dialogs.SelectCreateDialog(parent, {
no_create: true,
readonly: true,
res_model: 'partner',
@@ -192,15 +191,18 @@ QUnit.module('Views', {
search_default_groupby_bar: true,
search_default_foo: 'piou',
},
- }).open();
+ }).open().then(function (result) {
+ dialog = result;
+ });
+ await testUtils.nextTick();
- testUtils.dom.click(dialog.$('.o_searchview_facet:contains(groupby_bar) .o_facet_remove'));
- testUtils.dom.click(dialog.$('.o_searchview_facet .o_facet_remove'));
+ await testUtils.dom.click(dialog.$('.o_searchview_facet:contains(groupby_bar) .o_facet_remove'));
+ await testUtils.dom.click(dialog.$('.o_searchview_facet .o_facet_remove'));
parent.destroy();
});
- QUnit.test('SelectCreateDialog correctly evaluates domains', function (assert) {
+ QUnit.test('SelectCreateDialog correctly evaluates domains', async function (assert) {
assert.expect(1);
var parent = createParent({
@@ -234,11 +236,12 @@ QUnit.module('Views', {
res_model: 'partner',
domain: "[['id', '=', uid]]",
}).open();
+ await testUtils.nextTick();
parent.destroy();
});
- QUnit.test('SelectCreateDialog list view in readonly', function (assert) {
+ QUnit.test('SelectCreateDialog list view in readonly', async function (assert) {
assert.expect(1);
var parent = createParent({
@@ -254,12 +257,16 @@ QUnit.module('Views', {
},
});
- var dialog = new dialogs.SelectCreateDialog(parent, {
+ var dialog;
+ new dialogs.SelectCreateDialog(parent, {
res_model: 'partner',
- }).open();
+ }).open().then(function (result) {
+ dialog = result;
+ });
+ await testUtils.nextTick();
// click on the first row to see if the list is editable
- testUtils.dom.click(dialog.$('.o_list_view tbody tr:first td:not(.o_list_record_selector):first'));
+ await testUtils.dom.click(dialog.$('.o_list_view tbody tr:first td:not(.o_list_record_selector):first'));
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");
@@ -267,10 +274,10 @@ QUnit.module('Views', {
parent.destroy();
});
- QUnit.test('SelectCreateDialog cascade x2many in create mode', function (assert) {
+ QUnit.test('SelectCreateDialog cascade x2many in create mode', async function (assert) {
assert.expect(5);
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'product',
data: this.data,
@@ -310,31 +317,31 @@ QUnit.module('Views', {
mockRPC: function(route, args) {
if (route === '/web/dataset/call_kw/partner/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
if (route === '/web/dataset/call_kw/instrument/get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
if (route === '/web/dataset/call_kw/instrument/create') {
assert.deepEqual(args.args, [{badassery: [[6, false, [1]]], name: false}],
'The method create should have been called with the right arguments');
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
});
- testUtils.form.clickEdit(form);
- testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
- testUtils.dom.click(form.$('.o_field_widget .o_field_many2one[name=instrument] input'));
- testUtils.dom.click($('ul.ui-autocomplete.ui-front.ui-menu.ui-widget.ui-widget-content li.o_m2o_dropdown_option').first());
+ await testUtils.form.clickEdit(form);
+ await testUtils.dom.click(form.$('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click(form.$('.o_field_widget .o_field_many2one[name=instrument] input'));
+ await testUtils.dom.click($('ul.ui-autocomplete.ui-front.ui-menu.ui-widget.ui-widget-content li.o_m2o_dropdown_option').first());
var $modal = $('.modal-lg');
assert.equal($modal.length, 1,
'There should be one modal');
- testUtils.dom.click($modal.find('.o_field_x2many_list_row_add a'));
+ await testUtils.dom.click($modal.find('.o_field_x2many_list_row_add a'));
var $modals = $('.modal-lg');
@@ -342,9 +349,9 @@ QUnit.module('Views', {
'There should be two modals');
var $second_modal = $modals.not($modal);
- testUtils.dom.click($second_modal.find('.o_list_view.table.table-sm.table-striped.o_list_view_ungrouped .o_data_row input[type=checkbox]'));
+ await testUtils.dom.click($second_modal.find('.o_list_view.table.table-sm.table-striped.o_list_view_ungrouped .o_data_row input[type=checkbox]'));
- testUtils.dom.click($second_modal.find('.o_select_button'));
+ await testUtils.dom.click($second_modal.find('.o_select_button'));
$modal = $('.modal-lg');
@@ -354,18 +361,18 @@ QUnit.module('Views', {
assert.equal($modal.find('.o_data_cell').text(), 'Awsome',
'There should be one item in the list of the modal');
- testUtils.dom.click($modal.find('.btn.btn-primary'));
+ await testUtils.dom.click($modal.find('.btn.btn-primary'));
form.destroy();
});
- QUnit.test('Form dialog and subview with _view_ref contexts', function (assert) {
+ QUnit.test('Form dialog and subview with _view_ref contexts', async function (assert) {
assert.expect(2);
this.data.instrument.records = [{id: 1, name: 'Tromblon', badassery: [1]}];
this.data.partner.records[0].instrument = 1;
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -390,7 +397,7 @@ QUnit.module('Views', {
mockRPC: function(route, args) {
if (args.method === 'get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
@@ -410,11 +417,11 @@ QUnit.module('Views', {
},
});
- form.$('.o_field_widget[name="instrument"] button.o_external_button').click();
+ await testUtils.dom.click(form.$('.o_field_widget[name="instrument"] button.o_external_button'));
form.destroy();
});
- QUnit.test('SelectCreateDialog: save current search', function (assert) {
+ QUnit.test('SelectCreateDialog: save current search', async function (assert) {
assert.expect(4);
testUtils.mock.patch(ListController, {
@@ -451,32 +458,34 @@ QUnit.module('Views', {
},
});
- var dialog = new dialogs.SelectCreateDialog(parent, {
+ var dialog;
+ new dialogs.SelectCreateDialog(parent, {
context: {shouldNotBeInFilterContext: false},
res_model: 'partner',
- }).open();
+ }).open().then(function (result) {
+ dialog = result;
+ });
+ await testUtils.nextTick();
- assert.containsN(dialog, '.o_data_row', 3,
- "should contain 3 records");
+ assert.containsN(dialog, '.o_data_row', 3, "should contain 3 records");
// filter on bar
- testUtils.dom.click(dialog.$('.o_dropdown_toggler_btn:contains(Filters)'));
- testUtils.dom.click(dialog.$('.o_filters_menu a:contains(Bar)'));
+ await testUtils.dom.click(dialog.$('.o_dropdown_toggler_btn:contains(Filters)'));
+ await testUtils.dom.click(dialog.$('.o_filters_menu a:contains(Bar)'));
- assert.containsN(dialog, '.o_data_row', 2,
- "should contain 2 records");
+ assert.containsN(dialog, '.o_data_row', 2, "should contain 2 records");
// save filter
- testUtils.dom.click(dialog.$('.o_dropdown_toggler_btn:contains(Favorites)'));
- testUtils.dom.click(dialog.$('.o_add_favorite'));
- dialog.$('.o_favorite_name input[type=text]').val('some name'); // name the filter
- testUtils.dom.click(dialog.$('.o_save_favorite button'));
+ await testUtils.dom.click(dialog.$('.o_dropdown_toggler_btn:contains(Favorites)'));
+ await testUtils.dom.click(dialog.$('.o_add_favorite'));
+ await testUtils.fields.editInput(dialog.$('.o_favorite_name input[type=text]'), 'some name'); // name the filter
+ await testUtils.dom.click(dialog.$('.o_save_favorite button'));
testUtils.mock.unpatch(ListController);
parent.destroy();
});
- QUnit.test('propagate can_create onto the search popup o2m', function (assert) {
+ QUnit.test('propagate can_create onto the search popup o2m', async function (assert) {
assert.expect(3);
this.data.instrument.records = [
@@ -490,7 +499,7 @@ QUnit.module('Views', {
{id: 8, name: 'Tromblon8'},
];
- var form = createView({
+ var form = await createView({
View: FormView,
model: 'partner',
data: this.data,
@@ -513,18 +522,19 @@ QUnit.module('Views', {
mockRPC: function(route, args) {
if (args.method === 'get_formview_id') {
- return $.when(false);
+ return Promise.resolve(false);
}
return this._super(route, args);
},
});
- form.$('.o_field_widget[name="instrument"] .o_input').click();
+ await testUtils.dom.click(form.$('.o_field_widget[name="instrument"] .o_input'));
assert.notOk($('.ui-autocomplete a:contains(Create and Edit)').length,
'Create and edit not present in dropdown');
- $('.ui-autocomplete a:contains(Search More)').trigger('mouseenter').trigger('click');
+ await testUtils.dom.triggerEvents($('.ui-autocomplete a:contains(Search More)'),
+ ['mouseenter', 'click']);
var $modal = $('.modal-dialog.modal-lg');
diff --git a/addons/web/static/tests/widgets/data_export_tests.js b/addons/web/static/tests/widgets/data_export_tests.js
index 51c82ef1ded..d9453d70405 100644
--- a/addons/web/static/tests/widgets/data_export_tests.js
+++ b/addons/web/static/tests/widgets/data_export_tests.js
@@ -35,7 +35,7 @@ QUnit.module('widgets', {
QUnit.module('Data Export');
- QUnit.test('exporting all data in list view', function (assert) {
+ QUnit.test('exporting all data in list view', async function (assert) {
assert.expect(6);
var blockUI = framework.blockUI;
@@ -47,7 +47,7 @@ QUnit.module('widgets', {
assert.step('unblock UI');
};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -57,13 +57,13 @@ QUnit.module('widgets', {
},
mockRPC: function (route) {
if (route === '/web/export/formats') {
- return $.when([
+ return Promise.resolve([
{tag: 'csv', label: 'CSV'},
{tag: 'xls', label: 'Excel'},
]);
}
if (route === '/web/export/get_fields') {
- return $.when([
+ return Promise.resolve([
{
field_type: "one2many",
string: "Activities",
@@ -94,19 +94,19 @@ QUnit.module('widgets', {
},
});
- testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
- testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(list.sidebar.$('a:contains(Export)'));
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+ await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(list.sidebar.$('a:contains(Export)'));
assert.strictEqual($('.modal').length, 1, "a modal dialog should be open");
assert.strictEqual($('span.o_tree_column:contains(Activities)').length, 1,
"the Activities field should be in the list of exportable fields");
// select the field Description, click on add, then export and close
- testUtils.dom.click($('.modal span:contains(Description)'));
- testUtils.dom.click($('.modal .o_add_field'));
- testUtils.dom.click($('.modal span:contains(Export To File)'));
- testUtils.dom.click($('.modal span:contains(Close)'));
+ await testUtils.dom.click($('.modal span:contains(Description)'));
+ await testUtils.dom.click($('.modal .o_add_field'));
+ await testUtils.dom.click($('.modal span:contains(Export To File)'));
+ await testUtils.dom.click($('.modal span:contains(Close)'));
list.destroy();
framework.blockUI = blockUI;
@@ -118,17 +118,17 @@ QUnit.module('widgets', {
]);
});
- QUnit.test('saving fields list when exporting data', function (assert) {
+ QUnit.test('saving fields list when exporting data', async function (assert) {
assert.expect(5);
var create = data.DataSet.prototype.create;
data.DataSet.prototype.create = function (data, options) {
assert.step('create');
- return $.when([]);
+ return Promise.resolve([]);
};
- var list = createView({
+ var list = await createView({
View: ListView,
model: 'partner',
data: this.data,
@@ -138,13 +138,13 @@ QUnit.module('widgets', {
},
mockRPC: function (route) {
if (route === '/web/export/formats') {
- return $.when([
+ return Promise.resolve([
{tag: 'csv', label: 'CSV'},
{tag: 'xls', label: 'Excel'},
]);
}
if (route === '/web/export/get_fields') {
- return $.when([
+ return Promise.resolve([
{
field_type: "one2many",
string: "Activities",
@@ -162,29 +162,29 @@ QUnit.module('widgets', {
});
// Open the export modal
- testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
- testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
- testUtils.dom.click(list.sidebar.$('a:contains(Export)'));
+ await testUtils.dom.click(list.$('thead th.o_list_record_selector input'));
+ await testUtils.dom.click(list.sidebar.$('.o_dropdown_toggler_btn:contains(Action)'));
+ await testUtils.dom.click(list.sidebar.$('a:contains(Export)'));
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");
- testUtils.dom.click($('.modal .o_export_tree_item:contains(Activities)'));
- testUtils.dom.click($('.modal button:contains(Add)'));
+ await testUtils.dom.click($('.modal .o_export_tree_item:contains(Activities)'));
+ await testUtils.dom.click($('.modal button:contains(Add)'));
assert.strictEqual($('.modal select.o_fields_list option').length, 1,
"there should be one item in the fields list");
// Save fields list
- testUtils.dom.click($('.modal a:contains(Save fields list)'));
- testUtils.fields.editInput($('.modal .o_save_list > input'), 'fields list');
- testUtils.dom.click($('.modal .o_save_list > button'));
+ await testUtils.dom.click($('.modal a:contains(Save fields list)'));
+ await testUtils.fields.editInput($('.modal .o_save_list > input'), 'fields list');
+ await testUtils.dom.click($('.modal .o_save_list > button'));
assert.verifySteps(['create'],
"create should have been called");
// Close the modal and destroy list
- testUtils.dom.click($('.modal button span:contains(Close)'));
+ await testUtils.dom.click($('.modal button span:contains(Close)'));
list.destroy();
// restore create function
diff --git a/addons/web/static/tests/widgets/domain_selector_tests.js b/addons/web/static/tests/widgets/domain_selector_tests.js
index 53f1d9cff26..305315b72c6 100644
--- a/addons/web/static/tests/widgets/domain_selector_tests.js
+++ b/addons/web/static/tests/widgets/domain_selector_tests.js
@@ -50,7 +50,7 @@ QUnit.module('DomainSelector', {
},
}, function () {
- QUnit.test("creating a domain from scratch", function (assert) {
+ QUnit.test("creating a domain from scratch", async function (assert) {
assert.expect(13);
var $target = $("#qunit-fixture");
@@ -61,7 +61,7 @@ QUnit.module('DomainSelector', {
debugMode: true,
});
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
- domainSelector.appendTo($target);
+ await domainSelector.appendTo($target);
// As we gave an empty domain, there should be a visible button to add
// the first domain part
@@ -71,13 +71,14 @@ QUnit.module('DomainSelector', {
// Clicking on the button should add a visible field selector in the
// widget so that the user can change the field chain
- testUtils.dom.click($domainAddFirstNodeButton);
+ await testUtils.dom.click($domainAddFirstNodeButton);
var $fieldSelector = domainSelector.$(".o_field_selector:visible");
assert.strictEqual($fieldSelector.length, 1,
"there should be a field selector");
// Focusing the field selector input should open a field selector popover
$fieldSelector.trigger('focusin');
+ await testUtils.nextTick();
var $fieldSelectorPopover = $fieldSelector.find(".o_field_selector_popover:visible");
assert.strictEqual($fieldSelectorPopover.length, 1,
"field selector popover should be visible");
@@ -97,7 +98,7 @@ QUnit.module('DomainSelector', {
// Clicking the "Bar" field should change the internal domain and this
// should be displayed in the debug input
- testUtils.dom.click($barLi);
+ await testUtils.dom.click($barLi);
assert.strictEqual(
domainSelector.$(".o_domain_debug_input").val(),
'[["bar","=",True]]',
@@ -108,7 +109,7 @@ QUnit.module('DomainSelector', {
// should add the default "['id', '=', 1]" domain
var $plus = domainSelector.$(".fa-plus-circle");
assert.strictEqual($plus.length, 1, "there should be a '+' button");
- testUtils.dom.click($plus);
+ await testUtils.dom.click($plus);
assert.strictEqual(
domainSelector.$(".o_domain_debug_input").val(),
'["&",["bar","=",True],["id","=",1]]',
@@ -119,7 +120,7 @@ QUnit.module('DomainSelector', {
// domains and the "|" operator
var $dots = domainSelector.$(".fa-ellipsis-h");
assert.strictEqual($dots.length, 2, "there should be two '...' buttons");
- testUtils.dom.click($dots.first());
+ await testUtils.dom.click($dots.first());
assert.strictEqual(
domainSelector.$(".o_domain_debug_input").val(),
'["&","&",["bar","=",True],"|",["id","=",1],["id","=",1],["id","=",1]]',
@@ -130,6 +131,7 @@ QUnit.module('DomainSelector', {
// field instead of "id" should rerender the widget and adapt the
// widget suggestions
domainSelector.$(".o_domain_debug_input").val('["&","&",["bar","=",True],"|",["foo","=","hello"],["id","=",1],["id","=",1]]').change();
+ await testUtils.nextTick();
assert.strictEqual(domainSelector.$(".o_field_selector").eq(1).find("input.o_field_selector_debug").val(), "foo",
"the second field selector should now contain the 'foo' value");
assert.ok(domainSelector.$(".o_domain_leaf_operator_select").eq(1).html().indexOf("contains") >= 0,
@@ -140,8 +142,8 @@ QUnit.module('DomainSelector', {
// "foo" fields, with the initial "&" operator
var $minus = domainSelector.$(".o_domain_delete_node_button");
assert.strictEqual($minus.length, 5, "there should be five 'x' buttons");
- testUtils.dom.click($minus.last());
- testUtils.dom.click(domainSelector.$(".o_domain_delete_node_button").last());
+ await testUtils.dom.click($minus.last());
+ await testUtils.dom.click(domainSelector.$(".o_domain_delete_node_button").last());
assert.strictEqual(
domainSelector.$(".o_domain_debug_input").val(),
'["&",["bar","=",True],["foo","=","hello"]]',
@@ -150,7 +152,7 @@ QUnit.module('DomainSelector', {
domainSelector.destroy();
});
- QUnit.test("building a domain with a datetime", function (assert) {
+ QUnit.test("building a domain with a datetime", async function (assert) {
assert.expect(2);
var $target = $("#qunit-fixture");
@@ -160,7 +162,7 @@ QUnit.module('DomainSelector', {
readonly: false,
});
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
- domainSelector.appendTo($target);
+ await domainSelector.appendTo($target);
// Check that there is a datepicker to choose the date
var $datepicker = domainSelector.$(".o_datepicker:visible");
@@ -168,15 +170,15 @@ QUnit.module('DomainSelector', {
"there should be a datepicker");
var val = $datepicker.find('input').val();
- testUtils.dom.openDatepicker($datepicker);
- testUtils.dom.clickFirst($('.bootstrap-datetimepicker-widget :not(.today)[data-action="selectDay"]'));
+ await testUtils.dom.openDatepicker($datepicker);
+ await testUtils.dom.clickFirst($('.bootstrap-datetimepicker-widget :not(.today)[data-action="selectDay"]'));
assert.notEqual(domainSelector.$(".o_datepicker:visible input").val(), val,
"datepicker value should have changed");
domainSelector.destroy();
});
- QUnit.test("building a domain with a m2o without following the relation", function (assert) {
+ QUnit.test("building a domain with a m2o without following the relation", async function (assert) {
assert.expect(1);
var $target = $("#qunit-fixture");
@@ -187,16 +189,17 @@ QUnit.module('DomainSelector', {
readonly: false,
});
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
- domainSelector.appendTo($target);
+ await domainSelector.appendTo($target);
- testUtils.fields.editAndTrigger(domainSelector.$('.o_domain_leaf_value_input'), 'pad', ['input', 'change']);
+ await testUtils.fields.editAndTrigger(domainSelector.$('.o_domain_leaf_value_input'),
+ 'pad', ['input', 'change']);
assert.strictEqual(domainSelector.$('.o_domain_debug_input').val(), '[["product_id","ilike","pad"]]',
"string should have been allowed as m2o value");
domainSelector.destroy();
});
- QUnit.test("editing a domain with `parent` key", function (assert) {
+ QUnit.test("editing a domain with `parent` key", async function (assert) {
assert.expect(1);
var $target = $("#qunit-fixture");
@@ -207,7 +210,7 @@ QUnit.module('DomainSelector', {
readonly: false,
});
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
- domainSelector.appendTo($target);
+ await domainSelector.appendTo($target);
assert.strictEqual(domainSelector.$el.text(), "This domain is not supported.",
"an error message should be displayed because of the `parent` key");
@@ -215,7 +218,7 @@ QUnit.module('DomainSelector', {
domainSelector.destroy();
});
- QUnit.test("creating a domain with a default option", function (assert) {
+ QUnit.test("creating a domain with a default option", async function (assert) {
assert.expect(1);
var $target = $("#qunit-fixture");
@@ -227,11 +230,11 @@ QUnit.module('DomainSelector', {
default: [["foo","=","kikou"]],
});
testUtils.mock.addMockEnvironment(domainSelector, {data: this.data});
- domainSelector.appendTo($target);
+ await domainSelector.appendTo($target);
// Clicking on the button should add a visible field selector in the
// widget so that the user can change the field chain
- testUtils.dom.click(domainSelector.$(".o_domain_add_first_node_button:visible"));
+ await testUtils.dom.click(domainSelector.$(".o_domain_add_first_node_button:visible"));
assert.strictEqual(
domainSelector.$(".o_domain_debug_input").val(),
diff --git a/addons/web/static/tests/widgets/dropdown_menu_tests.js b/addons/web/static/tests/widgets/dropdown_menu_tests.js
index 709651c7cb1..c632d1b7307 100644
--- a/addons/web/static/tests/widgets/dropdown_menu_tests.js
+++ b/addons/web/static/tests/widgets/dropdown_menu_tests.js
@@ -9,8 +9,9 @@ function createDropdownMenu(items, params) {
var target = params.debug ? document.body : $('#qunit-fixture');
var menu = new DropdownMenu(null, items);
testUtils.mock.addMockEnvironment(menu, params);
- menu.appendTo(target);
- return menu;
+ return menu.appendTo(target).then(function() {
+ return menu;
+ });
}
QUnit.module('Web', {
@@ -35,10 +36,10 @@ QUnit.module('Web', {
}, function () {
QUnit.module('DropdownMenu');
- QUnit.test('simple rendering', function (assert) {
+ QUnit.test('simple rendering', async function (assert) {
assert.expect(4);
- var dropdownMenu = createDropdownMenu(this.items);
+ var dropdownMenu = await createDropdownMenu(this.items);
assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4,
'should have 4 elements counting the dividers');
assert.strictEqual(dropdownMenu.$('.o_menu_item').first().text().trim(), 'Some Item',
@@ -51,11 +52,11 @@ QUnit.module('Web', {
dropdownMenu.destroy();
});
- QUnit.test('click on an item without options should toggle it', function (assert) {
+ QUnit.test('click on an item without options should toggle it', async function (assert) {
assert.expect(7);
var self = this;
- var dropdownMenu = createDropdownMenu(this.items, {
+ var dropdownMenu = await createDropdownMenu(this.items, {
intercepts: {
menu_item_clicked: function (ev) {
assert.strictEqual(ev.data.id, 1);
@@ -64,34 +65,34 @@ QUnit.module('Web', {
},
},
});
- testUtils.dom.click(dropdownMenu.$('button:first'));
+ await testUtils.dom.click(dropdownMenu.$('button:first'));
assert.doesNotHaveClass(dropdownMenu.$('.o_menu_item:first > .dropdown-item').first(), 'selected');
- testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first());
+ await testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first());
assert.hasClass(dropdownMenu.$('.o_menu_item:first > .dropdown-item'), 'selected');
assert.ok(dropdownMenu.$('.o_menu_item:first').is(':visible'),
'item should still be visible');
- testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first());
+ await testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first());
assert.doesNotHaveClass(dropdownMenu.$('.o_menu_item:first > .dropdown-item').first(), 'selected');
assert.ok(dropdownMenu.$('.o_menu_item:first').is(':visible'),
'item should still be visible');
dropdownMenu.destroy();
});
- QUnit.test('click on an item should not change url', function (assert) {
+ QUnit.test('click on an item should not change url', async function (assert) {
assert.expect(0);
- var dropdownMenu = createDropdownMenu(this.items);
- testUtils.dom.click(dropdownMenu.$('.o_dropdown_toggler_btn'));
+ var dropdownMenu = await createDropdownMenu(this.items);
+ await testUtils.dom.click(dropdownMenu.$('.o_dropdown_toggler_btn'));
dropdownMenu.$el.click(function () {
// we do not want a click to get out and change the url, for example
throw new Error('No click should get out of the dropdown menu');
});
- testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first());
+ await testUtils.dom.click(dropdownMenu.$('.o_menu_item a').first());
dropdownMenu.destroy();
});
- QUnit.test('options rendering', function (assert) {
+ QUnit.test('options rendering', async function (assert) {
assert.expect(3);
this.items[0].hasOptions = true;
@@ -99,20 +100,20 @@ QUnit.module('Web', {
{optionId: 1, description: "First Option", groupId: 1},
{optionId: 2, description: "Second Option", groupId: 1}
];
- var dropdownMenu = createDropdownMenu(this.items);
+ var dropdownMenu = await createDropdownMenu(this.items);
testUtils.dom.click(dropdownMenu.$('button:first'));
assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4);
// open options menu
- testUtils.dom.click(dropdownMenu.$('span.fa-caret-right'));
+ await testUtils.dom.click(dropdownMenu.$('span.fa-caret-right'));
assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 7);
// close options menu
- testUtils.dom.click(dropdownMenu.$('span.fa-caret-down'));
+ await testUtils.dom.click(dropdownMenu.$('span.fa-caret-down'));
assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4);
dropdownMenu.destroy();
});
- QUnit.test('close menu closes also submenus', function (assert) {
+ QUnit.test('close menu closes also submenus', async function (assert) {
assert.expect(2);
this.items[0].hasOptions = true;
@@ -120,20 +121,20 @@ QUnit.module('Web', {
{optionId: 1, description: "First Option"},
{optionId: 2, description: "Second Option"}
];
- var dropdownMenu = createDropdownMenu(this.items);
+ var dropdownMenu = await createDropdownMenu(this.items);
// open dropdown menu
testUtils.dom.click(dropdownMenu.$('button:first'));
// open options menu
- testUtils.dom.click(dropdownMenu.$('span.fa-caret-right'));
+ await testUtils.dom.click(dropdownMenu.$('span.fa-caret-right'));
assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 7);
- testUtils.dom.click(dropdownMenu.$('button:first'));
- testUtils.dom.click(dropdownMenu.$('button:first'));
+ await testUtils.dom.click(dropdownMenu.$('button:first'));
+ await testUtils.dom.click(dropdownMenu.$('button:first'));
assert.containsN(dropdownMenu, '.dropdown-divider, .dropdown-item, .dropdown-item-text', 4);
dropdownMenu.destroy();
});
- QUnit.test('click on an option should trigger the event "item_option_clicked" with appropriate data', function (assert) {
+ QUnit.test('click on an option should trigger the event "item_option_clicked" with appropriate data', async function (assert) {
assert.expect(16);
var self = this;
@@ -143,7 +144,7 @@ QUnit.module('Web', {
{optionId: 1, description: "First Option"},
{optionId: 2, description: "Second Option"}
];
- var dropdownMenu = createDropdownMenu(this.items, {
+ var dropdownMenu = await createDropdownMenu(this.items, {
intercepts: {
item_option_clicked: function (ev) {
eventNumber++;
@@ -166,22 +167,23 @@ QUnit.module('Web', {
},
},
});
+ await testUtils.nextTick();
// open dropdown menu
- testUtils.dom.click(dropdownMenu.$('button:first'));
+ await testUtils.dom.click(dropdownMenu.$('button:first'));
assert.containsN(dropdownMenu, '.dropdown-divider, .o_menu_item', 4);
- testUtils.dom.clickFirst(dropdownMenu.$('.o_menu_item'));
+ await testUtils.dom.clickFirst(dropdownMenu.$('.o_menu_item'));
// click on first option
- testUtils.dom.click(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0));
+ await testUtils.dom.click(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0));
assert.hasClass(dropdownMenu.$('.o_menu_item > .dropdown-item').first(), 'selected');
assert.hasClass(dropdownMenu.$('.o_item_option> .dropdown-item').eq(0),'selected');
assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(1), 'selected');
// click on second option
- testUtils.dom.click($('.o_item_option > .dropdown-item').eq(1));
+ await testUtils.dom.click($('.o_item_option > .dropdown-item').eq(1));
assert.hasClass(dropdownMenu.$('.o_menu_item > .dropdown-item').first(), 'selected');
assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0), 'selected');
assert.hasClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(1), 'selected');
// click again on second option
- testUtils.dom.click($('.o_item_option > .dropdown-item').eq(1));
+ await testUtils.dom.click($('.o_item_option > .dropdown-item').eq(1));
assert.doesNotHaveClass(dropdownMenu.$('.o_menu_item > .dropdown-item').first(), 'selected');
assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(0), 'selected');
assert.doesNotHaveClass(dropdownMenu.$('.o_item_option > .dropdown-item').eq(1), 'selected');
diff --git a/addons/web/static/tests/widgets/model_field_selector_tests.js b/addons/web/static/tests/widgets/model_field_selector_tests.js
index 2510912e678..76c18b91f5b 100644
--- a/addons/web/static/tests/widgets/model_field_selector_tests.js
+++ b/addons/web/static/tests/widgets/model_field_selector_tests.js
@@ -49,7 +49,7 @@ QUnit.module('ModelFieldSelector', {
},
}, function () {
- QUnit.test("creating a field chain from scratch", function (assert) {
+ QUnit.test("creating a field chain from scratch", async function (assert) {
assert.expect(14);
var $target = $("#qunit-fixture");
@@ -60,7 +60,7 @@ QUnit.module('ModelFieldSelector', {
debugMode: true,
});
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
- fieldSelector.appendTo($target);
+ await fieldSelector.appendTo($target);
var $value = fieldSelector.$("> .o_field_selector_value");
// Focusing the field selector input should open a field selector popover
@@ -84,7 +84,7 @@ QUnit.module('ModelFieldSelector', {
// Clicking the "Bar" field should close the popover and set the field
// chain to "bar" as it is a basic field
- testUtils.dom.click($barLi);
+ await testUtils.dom.click($barLi);
assert.notOk($fieldSelectorPopover.is("visible"),
"field selector popover should be closed now");
assert.strictEqual(getValueFromDOM($value), "Bar",
@@ -100,6 +100,7 @@ QUnit.module('ModelFieldSelector', {
// Focusing the input again should open the same popover
fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
assert.ok($fieldSelectorPopover.is(":visible"),
"field selector popover should be visible");
@@ -118,7 +119,7 @@ QUnit.module('ModelFieldSelector', {
// Clicking on the "Product" field should update the popover to show
// the product fields (so only "Product Name" should be there)
- testUtils.dom.click($productLi);
+ await testUtils.dom.click($productLi);
$lis = $fieldSelectorPopover.find("li");
assert.strictEqual($lis.length, 1,
"there should be only one field proposition for 'product' model");
@@ -127,7 +128,7 @@ QUnit.module('ModelFieldSelector', {
// Clicking on "Product Name" should close the popover and set the chain
// to "product_id.name"
- testUtils.dom.click($lis.first());
+ await testUtils.dom.click($lis.first());
assert.notOk($fieldSelectorPopover.is("visible"),
"field selector popover should be closed now");
assert.strictEqual(getValueFromDOM($value), "Product -> Product Name",
@@ -135,10 +136,12 @@ QUnit.module('ModelFieldSelector', {
// Remove the current selection and recreate it again
fieldSelector.$el.trigger('focusin');
- testUtils.dom.click(fieldSelector.$('.o_field_selector_prev_page'));
- testUtils.dom.click(fieldSelector.$('.o_field_selector_close'));
+ await testUtils.nextTick();
+ await testUtils.dom.click(fieldSelector.$('.o_field_selector_prev_page'));
+ await testUtils.dom.click(fieldSelector.$('.o_field_selector_close'));
fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
$fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
$lis = $fieldSelectorPopover.find("li");
$productLi = $();
@@ -151,9 +154,9 @@ QUnit.module('ModelFieldSelector', {
assert.strictEqual($productLi.length, 1,
"field selector popover should contain the 'Product' field");
- testUtils.dom.click($productLi);
+ await testUtils.dom.click($productLi);
$lis = $fieldSelectorPopover.find("li");
- testUtils.dom.click($lis.first());
+ await testUtils.dom.click($lis.first());
assert.notOk($fieldSelectorPopover.is("visible"),
"field selector popover should be closed now");
assert.strictEqual(getValueFromDOM($value), "Product -> Product Name",
@@ -168,7 +171,7 @@ QUnit.module('ModelFieldSelector', {
}
});
- QUnit.test("use the filter option", function (assert) {
+ QUnit.test("use the filter option", async function (assert) {
assert.expect(2);
var $target = $("#qunit-fixture");
@@ -181,9 +184,10 @@ QUnit.module('ModelFieldSelector', {
},
});
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
- fieldSelector.appendTo($target);
+ await fieldSelector.appendTo($target);
fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
var $lis = $fieldSelectorPopover.find("li");
assert.strictEqual($lis.length, 1, "there should only be one element");
@@ -192,7 +196,7 @@ QUnit.module('ModelFieldSelector', {
fieldSelector.destroy();
});
- QUnit.test("default `showSearchInput` option", function (assert) {
+ QUnit.test("default `showSearchInput` option", async function (assert) {
assert.expect(6);
var $target = $("#qunit-fixture");
@@ -202,9 +206,10 @@ QUnit.module('ModelFieldSelector', {
readonly: false,
});
testUtils.mock.addMockEnvironment(fieldSelector, {data: this.data});
- fieldSelector.appendTo($target);
+ await fieldSelector.appendTo($target);
fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
var $searchInput = $fieldSelectorPopover.find(".o_field_selector_search input");
assert.strictEqual($searchInput.length, 1, "there should be a search input");
@@ -212,17 +217,17 @@ QUnit.module('ModelFieldSelector', {
// without search
assert.strictEqual($fieldSelectorPopover.find("li").length, 3, "there should be three available fields");
assert.strictEqual($fieldSelectorPopover.find("li").text().trim().replace(/\s+/g, ' '), "Bar Foo Product", "the available field should be correct");
- $searchInput.val('xx').trigger('keyup');
+ await testUtils.fields.editAndTrigger($searchInput, 'xx', 'keyup');
assert.strictEqual($fieldSelectorPopover.find("li").length, 0, "there shouldn't be any element");
- $searchInput.val('Pro').trigger('keyup');
+ await testUtils.fields.editAndTrigger($searchInput, 'Pro', 'keyup');
assert.strictEqual($fieldSelectorPopover.find("li").length, 1, "there should only be one element");
assert.strictEqual($fieldSelectorPopover.find("li").text().trim().replace(/\s+/g, ' '), "Product", "the available field should be the Product");
fieldSelector.destroy();
});
- QUnit.test("false `showSearchInput` option", function (assert) {
+ QUnit.test("false `showSearchInput` option", async function (assert) {
assert.expect(1);
var $target = $("#qunit-fixture");
@@ -233,9 +238,10 @@ QUnit.module('ModelFieldSelector', {
showSearchInput: false,
});
testUtils.mock.addMockEnvironment(fieldSelector, { data: this.data });
- fieldSelector.appendTo($target);
+ await fieldSelector.appendTo($target);
fieldSelector.$el.trigger('focusin');
+ await testUtils.nextTick();
var $fieldSelectorPopover = fieldSelector.$(".o_field_selector_popover:visible");
var $searchInput = $fieldSelectorPopover.find(".o_field_selector_search input");
assert.strictEqual($searchInput.length, 0, "there should be no search input");