summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/helpers/test_utils_fields.js
diff options
context:
space:
mode:
authorRobot Odoo <xmo+roboto@odoo.com>2018-11-19 15:38:25 +0100
committerGitHub <noreply@github.com>2018-11-19 15:38:25 +0100
commit7c3d5dc067c7c331dcc0b52bafbdfd067087a3c4 (patch)
tree6058f8a893815bf0ed2495649c125523f4def762 /addons/web/static/tests/helpers/test_utils_fields.js
parent8fc246da31aa2a1c770732ae97e0cb4e840f07cf (diff)
parentabf32b8b21394491040e5c11c1fea809c1d7c62c (diff)
[MERGE][REF] *: update js test suite to use helpers
This rev. introduces robust helpers to use in the JS tests suite to interact with DOM and components, and starts using them (almost) everywhere. All the helpers are exposed though testUtils.js. There are 2 kinds of helpers: 1. Assertions ------------- * assert.containsNone, containsN, containsOnce check that the DOM (or a specific part of the DOM) contains a `selector`. It generates a correct error message automatically. ex: assert.notOk(form.$('button').hasClass('btn-primary')); -> assert.doesNotHaveClass(form.$('button'), 'btn-primary'); * assert.isVisible, isNotVisible check that the DOM has an element visible or not. They also check that the element is actually in the DOM (before most tests didn't verify this). * assert.hasClass, doesNotHaveClass, hasAttrVAlue, check specific properties of a DOM element, and also validate that it is applied on a single existing DOM element (before most tests didn't verify this). 2. Utilities ------------ The goal of the utilities is to centralize the definition of many standard components and interactions, ensuring that when we refactor the JS framework, we do not need to change all the tests. Existing mock utilities (addMockEnvironment, intercept, path, patchDate, unpatch and fieldsViewGet) are moved to 'testUtils.mock.*'. Existing DOM utilities are moved to 'testUtils.dom.*'. New dom utilities are created for opendDatePicker, click, clickFirst and clickLast. Helper `click` verifies that there is exactly 1 element visible in the DOM you click on, `clickFirst` and `clickLast` verify that there are more than one element on the DOM. ex: form.$('button').click(); -> testUtils.dom.click(form.$('button')); New Form utilities: (testUtils.form.*) clickEdit, clickSave, clickCreate, clickDiscard, all clicks on the control panel buttons of the form. `reload` reloads the form data. New modal, graph, kanban and pivot utils (testUtils.pivot.*, testUtils.kanban.*, etc.). New fields utils: (testUtils.fields.*) * editInput, editSelect: allow to change the value of a field, using a selector to identify it. They validate that the input exists and trigger the change event automatically. * editAndTrigger: allow to modify a field and trigger specific events after the value change * many2one (testUtils.fields.many2one.*) clickOpenDropdown, clickHighlightedItem, clickItem, searchAndClickItem: use a field name instead of a selector and do all the complex mechanism to open, filter and highlight many2one fields. Joint work with aab, dam, ged, mge, svs and vsc. closes odoo/odoo#28784
Diffstat (limited to 'addons/web/static/tests/helpers/test_utils_fields.js')
-rw-r--r--addons/web/static/tests/helpers/test_utils_fields.js172
1 files changed, 172 insertions, 0 deletions
diff --git a/addons/web/static/tests/helpers/test_utils_fields.js b/addons/web/static/tests/helpers/test_utils_fields.js
new file mode 100644
index 00000000000..f7d8829ce82
--- /dev/null
+++ b/addons/web/static/tests/helpers/test_utils_fields.js
@@ -0,0 +1,172 @@
+odoo.define('web.test_utils_fields', function (require) {
+"use strict";
+
+/**
+ * Field Test Utils
+ *
+ * This module defines various utility functions to help testing field widgets.
+ *
+ * Note that all methods defined in this module are exported in the main
+ * testUtils file.
+ */
+
+var concurrency = require('web.concurrency');
+
+//------------------------------------------------------------------------------
+// Public functions
+//------------------------------------------------------------------------------
+
+/**
+ * Sets the value of an element and then, trigger all specified events.
+ * Note that this helper also checks the unicity of the target.
+ *
+ * Example:
+ * testUtils.fields.editAndTrigger($('selector'), 'test', ['input', 'change']);
+ *
+ * @param {jQuery} $el should target an input, textarea or select
+ * @param {string|number} value
+ * @param {string[]} events
+ */
+function editAndTrigger($el, value, events) {
+ if ($el.length !== 1) {
+ throw new Error(`target ${$el.selector} has length ${$el.length} instead of 1`);
+ }
+ $el.val(value);
+ events.forEach(function (event) {
+ $el.trigger(event);
+ });
+}
+
+/**
+ * Sets the value of an input.
+ *
+ * Note that this helper also checks the unicity of the target.
+ *
+ * Example:
+ * testUtils.fields.editInput($('selector'), 'somevalue');
+ *
+ * @param {jQuery} $el
+ * @param {string|number} value
+ */
+function editInput($el, value) {
+ editAndTrigger($el, value, ['input']);
+}
+
+/**
+ * Sets the value of a select.
+ *
+ * Note that this helper also checks the unicity of the target.
+ *
+ * Example:
+ * testUtils.fields.editSelect($('selector'), 'somevalue');
+ *
+ * @param {jQuery} $el
+ * @param {string|number} value
+ */
+function editSelect($el, value) {
+ editAndTrigger($el, value, ['change']);
+}
+
+/**
+ * Click to open the dropdown on a many2one
+ *
+ * @param {string} fieldName
+ * @param {[string]} selector if set, this will restrict the search for the m2o
+ * input
+ * @returns {HTMLInputElement} the main many2one input
+ */
+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];
+}
+
+/**
+ * Click on the active (highlighted) selection in a m2o dropdown.
+ *
+ * @param {string} fieldName
+ * @param {[string]} selector if set, this will restrict the search for the m2o
+ * input
+ */
+function clickM2OHighlightedItem(fieldName, selector) {
+ var m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`;
+ var $dropdown = $(m2oSelector).autocomplete('widget');
+ // clicking on an li (no matter which one), will select the focussed one
+ $dropdown.find('li:first()').click();
+}
+
+/**
+ * Click on a menuitem in the m2o dropdown. This helper will target an element
+ * which contains some specific text. Note that it assumes that the dropdown
+ * is currently open.
+ *
+ * Example:
+ * testUtils.fields.many2one.clickM2OItem('partner_id', 'George');
+ *
+ * @param {string} fieldName
+ * @param {string} searchText
+ */
+function clickM2OItem(fieldName, searchText) {
+ var m2oSelector = `.o_field_many2one[name=${fieldName}] input`;
+ var $dropdown = $(m2oSelector).autocomplete('widget');
+ var $target = $dropdown.find(`li:contains(${searchText})`).first();
+ if ($target.length !== 1 || !$target.is(':visible')) {
+ throw new Error('Menu item should be unique and visible');
+ }
+ $target.mouseenter().click();
+}
+
+/**
+ * This helper is useful to test many2one fields. Here is what it does:
+ * - click to open the dropdown
+ * - enter a search string in the input
+ * - wait for the selection
+ * - click on the active menuitem
+ *
+ * Example:
+ * testUtils.fields.many2one.searchAndClickM2OItem('partner_id', 'George');
+ *
+ * @param {string} fieldName
+ * @param {[Object]} options
+ * @param {[string]} options.selector
+ * @param {[string]} options.search
+ * @returns {Promise}
+ */
+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 $.when(def).then(function () {
+ clickM2OHighlightedItem(fieldName, options.selector);
+ });
+}
+return {
+ clickOpenM2ODropdown: clickOpenM2ODropdown,
+ clickM2OHighlightedItem: clickM2OHighlightedItem,
+ clickM2OItem: clickM2OItem,
+ editAndTrigger: editAndTrigger,
+ editInput: editInput,
+ editSelect: editSelect,
+ searchAndClickM2OItem: searchAndClickM2OItem,
+};
+
+});