summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/helpers/test_utils_fields.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/tests/helpers/test_utils_fields.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web/static/tests/helpers/test_utils_fields.js')
-rw-r--r--addons/web/static/tests/helpers/test_utils_fields.js250
1 files changed, 250 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 00000000..3e35235c
--- /dev/null
+++ b/addons/web/static/tests/helpers/test_utils_fields.js
@@ -0,0 +1,250 @@
+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.
+ */
+
+ const testUtilsDom = require('web.test_utils_dom');
+
+ const ARROW_KEYS_MAPPING = {
+ down: 'ArrowDown',
+ left: 'ArrowLeft',
+ right: 'ArrowRight',
+ up: 'ArrowUp',
+ };
+
+ //-------------------------------------------------------------------------
+ // Public functions
+ //-------------------------------------------------------------------------
+
+ /**
+ * Autofills the input of a many2one field and clicks on the "Create and Edit" option.
+ *
+ * @param {string} fieldName
+ * @param {string} text Used as default value for the record name
+ * @see clickM2OItem
+ */
+ async function clickM2OCreateAndEdit(fieldName, text = "ABC") {
+ await clickOpenM2ODropdown(fieldName);
+ const match = document.querySelector(`.o_field_many2one[name=${fieldName}] input`);
+ await editInput(match, text);
+ return clickM2OItem(fieldName, "Create and Edit");
+ }
+
+ /**
+ * 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
+ * @returns {Promise}
+ */
+ async function clickM2OHighlightedItem(fieldName, selector) {
+ const m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`;
+ const $dropdown = $(m2oSelector).autocomplete('widget');
+ // clicking on an li (no matter which one), will select the focussed one
+ return testUtilsDom.click($dropdown[0].querySelector('li'));
+ }
+
+ /**
+ * 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
+ * @returns {Promise}
+ */
+ async function clickM2OItem(fieldName, searchText) {
+ const m2oSelector = `.o_field_many2one[name=${fieldName}] input`;
+ const $dropdown = $(m2oSelector).autocomplete('widget');
+ const $target = $dropdown.find(`li:contains(${searchText})`).first();
+ if ($target.length !== 1 || !$target.is(':visible')) {
+ throw new Error('Menu item should be visible');
+ }
+ $target.mouseenter(); // This is NOT a mouseenter event. See jquery.js:5516 for more headaches.
+ return testUtilsDom.click($target);
+ }
+
+ /**
+ * 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 {Promise<HTMLInputElement>} the main many2one input
+ */
+ async function clickOpenM2ODropdown(fieldName, selector) {
+ const m2oSelector = `${selector || ''} .o_field_many2one[name=${fieldName}] input`;
+ const matches = document.querySelectorAll(m2oSelector);
+ if (matches.length !== 1) {
+ throw new Error(`cannot open m2o: selector ${selector} has been found ${matches.length} instead of 1`);
+ }
+
+ await testUtilsDom.click(matches[0]);
+ return matches[0];
+ }
+
+ /**
+ * 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|EventTarget} el should target an input, textarea or select
+ * @param {string|number} value
+ * @param {string[]} events
+ * @returns {Promise}
+ */
+ async function editAndTrigger(el, value, events) {
+ if (el instanceof jQuery) {
+ if (el.length !== 1) {
+ throw new Error(`target ${el.selector} has length ${el.length} instead of 1`);
+ }
+ el.val(value);
+ } else {
+ el.value = value;
+ }
+ return testUtilsDom.triggerEvents(el, events);
+ }
+
+ /**
+ * 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|EventTarget} el should target an input, textarea or select
+ * @param {string|number} value
+ * @returns {Promise}
+ */
+ async function editInput(el, value) {
+ return 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|EventTarget} el should target an input, textarea or select
+ * @param {string|number} value
+ * @returns {Promise}
+ */
+ function editSelect(el, value) {
+ return editAndTrigger(el, value, ['change']);
+ }
+
+ /**
+ * 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 requested menuitem, or the active one by default
+ *
+ * Example:
+ * testUtils.fields.many2one.searchAndClickM2OItem('partner_id', {search: 'George'});
+ *
+ * @param {string} fieldName
+ * @param {[Object]} [options = {}]
+ * @param {[string]} [options.selector]
+ * @param {[string]} [options.search]
+ * @param {[string]} [options.item]
+ * @returns {Promise}
+ */
+ async function searchAndClickM2OItem(fieldName, options = {}) {
+ const input = await clickOpenM2ODropdown(fieldName, options.selector);
+ if (options.search) {
+ await editInput(input, options.search);
+ }
+ if (options.item) {
+ return clickM2OItem(fieldName, options.item);
+ } else {
+ return clickM2OHighlightedItem(fieldName, options.selector);
+ }
+ }
+
+ /**
+ * 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;
+ const params = {};
+ if (typeof keyCode === 'string') {
+ // Key (new API)
+ if (keyCode in ARROW_KEYS_MAPPING) {
+ params.key = ARROW_KEYS_MAPPING[keyCode];
+ } else {
+ params.key = keyCode[0].toUpperCase() + keyCode.slice(1).toLowerCase();
+ }
+ // KeyCode/which (jQuery)
+ if (keyCode.length > 1) {
+ keyCode = keyCode.toUpperCase();
+ keyCode = $.ui.keyCode[keyCode];
+ } else {
+ keyCode = keyCode.charCodeAt(0);
+ }
+ }
+ params.keyCode = keyCode;
+ params.which = keyCode;
+ return testUtilsDom.triggerEvent($el, type, params);
+ }
+
+ /**
+ * 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 {
+ clickM2OCreateAndEdit,
+ clickM2OHighlightedItem,
+ clickM2OItem,
+ clickOpenM2ODropdown,
+ editAndTrigger,
+ editInput,
+ editSelect,
+ searchAndClickM2OItem,
+ triggerKey,
+ triggerKeydown,
+ triggerKeyup,
+ };
+});