Conversation
- SMProAssayCreateTest.testAddResultFields - SMSampleCreateTest.testSamplesWithMultiChoice - SMSourceTypeMultiChoiceTest - ListTest.testMultiChoiceValues
…ag() fix test testMultiChoiceEditInBulk()
-add new shuffleSelect -replace my method with shuffleSelect
labkey-danield
left a comment
There was a problem hiding this comment.
Added a few comments.
| if(textChoiceValidator.getMultipleSelections()) | ||
| { | ||
| fieldRow.setAllowMultipleSelections(textChoiceValidator.getMultipleSelections()); | ||
| } |
There was a problem hiding this comment.
This will only set it if textChoiceValidator.getMultipleSelections is true, correct? This is ok if you are creating a field, but wouldn't work as expected if the test is editing an existing field and wants to change to field from a multi-choice to a single choice.
Perhaps a better check would be:
if(null != textChoiceValidator.getMultipleSelections())
| lookupSelect.clearSelection(); | ||
|
|
There was a problem hiding this comment.
Will this work if a test is trying to add to an existing selections?
There was a problem hiding this comment.
I would expect a method called setCellValue to overwrite any existing value.
| if(textChoiceValidator.getMultipleSelections()) | ||
| { | ||
| fieldRow.setAllowMultipleSelections(textChoiceValidator.getMultipleSelections()); | ||
| } |
There was a problem hiding this comment.
This would make it impossible to disable multi-select through this method.
This should either call setAllowMultipleSelections unconditionally or the condition should check whether textChoiceValidator.getMultipleSelections() != null.
| List<String> values = (List<String>) value; | ||
| filterModal.selectFacetTab().selectValue(values.get(0)); | ||
| filterModal.selectFacetTab().checkValues(values.toArray(String[]::new)); | ||
| filterModal.selectFacetTab().selectFilter(operator.getDisplayValue()); |
There was a problem hiding this comment.
I think this will (or could) break functionality for other column types; the facet panel usually doesn't have a filter type.
Also, this wouldn't work for "Is Empty" or "Is Not Empty".
There was a problem hiding this comment.
I’m planning to add support for 'Is Empty' and 'Is Not Empty' as well.
Regarding the functionality for other types: I’ve already found one test that was failing, so I added a check to the initFilterColumn method. It now checks if the filter type selector is present on the page before trying to interact with it. After this change, the test is passing.
Does this approach sound okay to you?
| for (Map.Entry<String, String> entry : values.entrySet()) | ||
| { | ||
| WebElement fieldInput = Locator.name(EscapeUtil.getFormFieldName(entry.getKey())).findElement(getDriver()); | ||
| WebElement fieldInput = Locator.nameContaining(EscapeUtil.getFormFieldName(entry.getKey())).findElement(getDriver()); |
There was a problem hiding this comment.
Use a more precise locator and add a comment explaining why this can't match the name exactly. (See UpdateQueryRowPage)
| table.clickInsertNewRow(); | ||
| String valuesToChoose = tcValues.subList(1, 3).stream() | ||
| .sorted() | ||
| .collect(Collectors.joining(" ")); | ||
| Locator loc = Locator.nameContaining(EscapeUtil.getFormFieldName(columnName)); | ||
| selectOptionByText(loc, valuesToChoose); |
There was a problem hiding this comment.
clickInsertNewRow returns a page object that should have methods for setting fields.
| if(Boolean.parseBoolean(selectElement.getAttribute("multiple"))) { | ||
| List<WebElement> elems = selectElement.findElements(Locator.tag("option")); | ||
| elems.forEach(element->{ | ||
| if(value.contains(element.getAttribute("value")) ^ element.isSelected()) element.click(); | ||
| }); | ||
| return; | ||
| } |
There was a problem hiding this comment.
This is less precise than we like for broadly available helpers; it would get confused by selection options that have overlapping text. I would suggest having a separate method for multi-select (selectOptionsByText(WebElement selectElement, List<String> values).
Co-authored-by: Trey Chadick <tchad@labkey.com>
- Test fixes for change from quoted values to bold in error messages
getConversionErrorMessage() fix to message case for invalid date/timestamp now quoting field name for consistency
Co-authored-by: Trey Chadick <tchad@labkey.com>
Co-authored-by: Trey Chadick <tchad@labkey.com>
# Conflicts: # src/org/labkey/test/pages/query/UpdateQueryRowPage.java
labkey-tchad
left a comment
There was a problem hiding this comment.
I think Xing is going to work on the Java remote API. This PR is blocked by that update.
| lookupSelect.clearSelection(); | ||
|
|
There was a problem hiding this comment.
I would expect a method called setCellValue to overwrite any existing value.
| * Select a filer by clicking its label. Right now this method relevant only for multi-value text choice. | ||
| * @param operator desired filter value | ||
| */ | ||
| public void selectFilter(Filter.Operator operator) |
There was a problem hiding this comment.
A slightly more descriptive method name.
| public void selectFilter(Filter.Operator operator) | |
| public void selectArrayFilterOperator(Filter.Operator operator) |
| protected final ReactSelect filterTypeSelects = | ||
| new ReactSelect.ReactSelectFinder(getDriver()).index(0).findWhenNeeded(this); |
There was a problem hiding this comment.
Making name consistent with method rename suggestion.
| protected final ReactSelect filterTypeSelects = | |
| new ReactSelect.ReactSelectFinder(getDriver()).index(0).findWhenNeeded(this); | |
| protected final ReactSelect arrayFilterOperatorSelect = | |
| new ReactSelect.ReactSelectFinder(getDriver()).index(0).findWhenNeeded(this); |
| */ | ||
| public boolean isFiltersPresented() | ||
| { | ||
| return waitFor(() -> isVisible(elementCache().filterTypeSelects), 1000); |
There was a problem hiding this comment.
We shouldn't wait for things that might not be present, especially when the most common state is for it to not be present.
| WebElement field = elementCache().findField(fieldName, true); | ||
| List<WebElement> options = field.findElements(By.tagName("option")); | ||
| //unselect all options that selected but shouldn't be selected | ||
| options.forEach(option -> | ||
| { | ||
| if (!values.contains(option.getText()) && option.getAttribute("selected") != null) option.click(); | ||
| }); | ||
| values.forEach(value -> selectOptionByText(field, value)); | ||
| return this; |
There was a problem hiding this comment.
WebDriver's Select class handles multi-select.
| WebElement field = elementCache().findField(fieldName, true); | |
| List<WebElement> options = field.findElements(By.tagName("option")); | |
| //unselect all options that selected but shouldn't be selected | |
| options.forEach(option -> | |
| { | |
| if (!values.contains(option.getText()) && option.getAttribute("selected") != null) option.click(); | |
| }); | |
| values.forEach(value -> selectOptionByText(field, value)); | |
| return this; | |
| WebElement field = new Select(elementCache().findField(fieldName, true)); | |
| field.deselectAll(); | |
| values.forEach(value -> field.selectByVisibleText(value)); | |
| return this; |
| return this; | ||
| } | ||
|
|
||
| public UpdateQueryRowPage setField(String fieldName, List<String> values) |
There was a problem hiding this comment.
This can replace the existing setMultiValueField that was added last week. It only has one usage and doesn't actually support multiple values.
| fieldRow.setAllowMultipleSelections(false); | ||
| } | ||
| else if (validator instanceof FieldDefinition.MultiValueTextChoiceValidator multiValueTextChoiceValidator) | ||
| { | ||
| // MultiValueTextChoice is a field type; implemented using a special validator. TextChoice field cannot have other validators. | ||
| if (validators.size() > 1) | ||
| { | ||
| throw new IllegalArgumentException("TextChoice fields cannot have additional validators."); | ||
| } | ||
| fieldRow.setTextChoiceValues(multiValueTextChoiceValidator.getValues()); | ||
| fieldRow.setAllowMultipleSelections(true); |
There was a problem hiding this comment.
MultiValueTextChoiceValidator is redundant. We can just check the column type to decide whether to allow multiple selections.
| fieldRow.setAllowMultipleSelections(false); | |
| } | |
| else if (validator instanceof FieldDefinition.MultiValueTextChoiceValidator multiValueTextChoiceValidator) | |
| { | |
| // MultiValueTextChoice is a field type; implemented using a special validator. TextChoice field cannot have other validators. | |
| if (validators.size() > 1) | |
| { | |
| throw new IllegalArgumentException("TextChoice fields cannot have additional validators."); | |
| } | |
| fieldRow.setTextChoiceValues(multiValueTextChoiceValidator.getValues()); | |
| fieldRow.setAllowMultipleSelections(true); | |
| fieldRow.setAllowMultipleSelections(fieldDefinition.getType() == FieldDefinition.ColumnType.MultiValueTextChoice); | |
| } |
| * to an external data source. The user only provides the list of (string) values that the field will display in the dropdown. | ||
| * Another difference is that there can only be one TextChoice on a field, whereas you can have multiple validators on a field. | ||
| */ | ||
| public static class MultiValueTextChoiceValidator extends FieldValidator<MultiValueTextChoiceValidator> |
There was a problem hiding this comment.
MultiValueTextChoiceValidator is redundant and should be removed.
|
|
||
| private GridFilterModal initFilterColumn(CharSequence columnIdentifier, Filter.Operator operator, Object value) | ||
| { | ||
| List<Filter.Operator> listOperators = List.of(IN, CONTAINS_ALL, CONTAINS_ANY, CONTAINS_EXACTLY, CONTAINS_NONE, | ||
| DOES_NOT_CONTAIN_EXACTLY); |
There was a problem hiding this comment.
IN isn't actually a list operator (this component just uses it as a signal to use the checkboxes). It shouldn't be grouped with them. This list should also be static and contain the empty operators.
| private GridFilterModal initFilterColumn(CharSequence columnIdentifier, Filter.Operator operator, Object value) | |
| { | |
| List<Filter.Operator> listOperators = List.of(IN, CONTAINS_ALL, CONTAINS_ANY, CONTAINS_EXACTLY, CONTAINS_NONE, | |
| DOES_NOT_CONTAIN_EXACTLY); | |
| public static final List<Filter.Operator> ARRAY_OPERATORS = List.of(CONTAINS_ALL, CONTAINS_ANY, CONTAINS_EXACTLY, CONTAINS_NONE, DOES_NOT_CONTAIN_EXACTLY, IS_EMPTY, IS_NOT_EMPTY); | |
| private GridFilterModal initFilterColumn(CharSequence columnIdentifier, Filter.Operator operator, Object value) | |
| { |
| if (operator.equals(Filter.Operator.IN) && value instanceof List<?>) | ||
| if (listOperators.contains(operator) && value instanceof List<?>) | ||
| { | ||
| List<String> values = (List<String>) value; | ||
| filterModal.selectFacetTab().selectValue(values.get(0)); | ||
| filterModal.selectFacetTab().checkValues(values.toArray(String[]::new)); | ||
| FilterFacetedPanel filterPanel = filterModal.selectFacetTab(); | ||
| filterPanel.selectValue(values.get(0)); | ||
| filterPanel.checkValues(values.toArray(String[]::new)); | ||
| if (filterPanel.isFiltersPresented()) | ||
| { | ||
| filterPanel.selectFilter(operator); | ||
| } | ||
| } | ||
| else if (value == null) | ||
| { | ||
| filterModal.selectFacetTab().selectFilter(operator); | ||
| } |
There was a problem hiding this comment.
Now that I have a better understanding of these new filter operators, I have a better idea for this method. We don't actually need to check whether the operator select is present; for the new operators, the select will always be present.
Something like this:
if (operator.equals(Filter.Operator.IN) && value instanceof List<?> || ARRAY_OPERATORS.contains(operator))
{
FilterFacetedPanel filterPanel = filterModal.selectFacetTab();
if (ARRAY_OPERATORS.contains(operator))
{
filterPanel.selectFilter(operator);
}
if (value != null)
{
List<String> values = (List<String>) value;
filterPanel.selectValue(values.get(0));
filterPanel.checkValues(values.toArray(String[]::new));
}
}
|
Rationale
Some changes to support multi choice
Related Pull Requests
Changes