Let's assume a many2one field with a lot of possible values. The user clicks on 'Search More...'. In the opened dialog, only 160 records are available (their ids have been obtained with a name_search, with the optional text the user could have typed in the many2one input). Before4cd379cf, that extra domain on ids was removed automatically as soon as the user interacted with the search view in the dialog. This was especially useful when there were more than 160 records. However, this was rather an happy coincidence than a designed feature. From4cd379cf, the ids selection was added to the initial domain of the list, so they couldn't be removed from the domain afterwards. The user was thus stucked with its preselected 160 records. This rev. doesn't restore the former behavior, but rather improves the current one, as follows: - when there is no text in the many2one input (i.e. no value to filter on), we bypass the name_search, s.t. all records are available in the dialog - when there is some text in the input, we perform a name_search (as before) to get a list of record ids, and we add a special filter to the search view in the dialog (the filter on those ids), s.t. the user can remove it if he wants to access the remaining records. - finally, the limit is now set to 320, to mitigate the problem Issue reported on the saas-12.1 migration pad. closes odoo/odoo#31232
178 lines
5.3 KiB
JavaScript
178 lines
5.3 KiB
JavaScript
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 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}
|
|
*/
|
|
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 () {
|
|
if (options.item) {
|
|
clickM2OItem(fieldName, options.item);
|
|
} else {
|
|
clickM2OHighlightedItem(fieldName, options.selector);
|
|
}
|
|
});
|
|
}
|
|
return {
|
|
clickOpenM2ODropdown: clickOpenM2ODropdown,
|
|
clickM2OHighlightedItem: clickM2OHighlightedItem,
|
|
clickM2OItem: clickM2OItem,
|
|
editAndTrigger: editAndTrigger,
|
|
editInput: editInput,
|
|
editSelect: editSelect,
|
|
searchAndClickM2OItem: searchAndClickM2OItem,
|
|
};
|
|
|
|
});
|