Files
odoo_source/addons/web/static/tests/helpers/test_utils_fields.js
T
Aaron Bohy 6a8e1b53e3 [FIX] web: search more in many2one: filter on ids
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).

Before 4cd379cf, 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.

From 4cd379cf, 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
2019-02-26 08:26:51 +00:00

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,
};
});