From 814a35424c64a966a261c36070ee5172dde1b8a8 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:43:47 -0800 Subject: [PATCH 1/6] add sample finder test for multi choice field create TestArrayDataUtils to move duplicated methods for multi choice simplify verifyFilter method in SMSourceTypeMultiChoiceTest --- .../components/ui/grids/ResponsiveGrid.java | 2 +- .../test/util/data/TestArrayDataUtils.java | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/org/labkey/test/util/data/TestArrayDataUtils.java diff --git a/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java b/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java index 625e9d4909..6b57ae7e4b 100644 --- a/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java +++ b/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java @@ -256,7 +256,7 @@ private GridFilterModal initFilterColumn(CharSequence columnIdentifier, Filter.O { filterPanel.selectArrayFilterOperator(operator); } - if (value != null) + if (value != null && !((List) value).isEmpty()) { List values = (List) value; filterPanel.selectValue(values.get(0)); diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java new file mode 100644 index 0000000000..e42856303b --- /dev/null +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -0,0 +1,43 @@ +package org.labkey.test.util.data; + +import org.labkey.remoteapi.query.Filter; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class TestArrayDataUtils +{ + /** + * Filtering Map according to filter and then sorting values in alphabetical order. + * + * @return filtered Map + */ + public static Map filterMap(Map> sourceMap, List searchValues, Filter.Operator filterType) + { + return sourceMap.entrySet().stream() + .filter(entry -> isMatch(entry.getValue(), searchValues, filterType)) + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> e.getValue().stream().sorted().collect(Collectors.joining(", ")), + (e1, e2) -> e1, + LinkedHashMap::new + )); + } + + private static boolean isMatch(List actualValues, List searchValues, Filter.Operator type) + { + return switch (type) + { + case ARRAY_CONTAINS_ALL -> actualValues.containsAll(searchValues); + case ARRAY_CONTAINS_ANY -> searchValues.stream().anyMatch(actualValues::contains); + case ARRAY_CONTAINS_EXACT -> actualValues.size() == searchValues.size() && actualValues.containsAll(searchValues); + case ARRAY_CONTAINS_NONE -> searchValues.stream().noneMatch(actualValues::contains); + case ARRAY_CONTAINS_NOT_EXACT -> !(actualValues.size() == searchValues.size() && actualValues.containsAll(searchValues)); + case ARRAY_ISEMPTY -> actualValues.isEmpty(); + case ARRAY_ISNOTEMPTY -> !actualValues.isEmpty(); + default -> true; + }; + } +} \ No newline at end of file From 20852090b24636aad3579a46f630144120497b46 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 10 Mar 2026 09:00:15 -0700 Subject: [PATCH 2/6] fix part of comments --- .../labkey/test/params/FieldDefinition.java | 2 +- .../labkey/test/util/TestDataGenerator.java | 8 +++++++ .../test/util/data/TestArrayDataUtils.java | 23 +++++++++++++++++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/params/FieldDefinition.java b/src/org/labkey/test/params/FieldDefinition.java index 78585ac23e..0336d68b51 100644 --- a/src/org/labkey/test/params/FieldDefinition.java +++ b/src/org/labkey/test/params/FieldDefinition.java @@ -617,7 +617,7 @@ public boolean isMeasureByDefault() ColumnType Sample = new ColumnTypeImpl("Sample", "int", "http://www.labkey.org/exp/xml#sample", new IntLookup( "exp", "Materials")); ColumnType Barcode = new ColumnTypeImpl("Unique ID", "string", "http://www.labkey.org/types#storageUniqueId", null); ColumnType TextChoice = new ColumnTypeImpl("Text Choice", "string", "http://www.labkey.org/types#textChoice", null); - ColumnType MultiValueTextChoice = new ColumnTypeImpl("Text Choice", "string", "http://cpas.fhcrc.org/exp/xml#multiChoice", null); + ColumnType MultiValueTextChoice = new ColumnTypeImpl("Text Choice", "http://cpas.fhcrc.org/exp/xml#multiChoice", null, null); ColumnType SMILES = new ColumnTypeImpl("SMILES", "string", "http://www.labkey.org/exp/xml#smiles", null); ColumnType Calculation = new ColumnTypeImpl("Calculation", null, "http://www.labkey.org/exp/xml#calculated", null); /** diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 3432935859..51a213ad13 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -183,6 +183,14 @@ else if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.TextChoice) else entityData.put(key, textChoices.get(textChoiceIndex)); } + else if (fieldDefinition.getType().equals(FieldDefinition.ColumnType.MultiValueTextChoice)) + { + FieldDefinition.TextChoiceValidator validator = + (FieldDefinition.TextChoiceValidator) fieldDefinition.getValidators().getFirst(); + List values = shuffleSelect(validator.getValues()); + Collections.sort(values); + entityData.put(key, values); + } } } diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index e42856303b..14cb36fdae 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -7,16 +7,35 @@ import java.util.Map; import java.util.stream.Collectors; +import static org.labkey.test.util.samplemanagement.SMTestUtils.COL_SAMPLE_ID_NAME; +import static org.labkey.test.util.samplemanagement.SMTestUtils.COL_SAMPLE_NAME_NAME; + public class TestArrayDataUtils { + + public static Map getMapWithIdAndMultiChoiceField(List> data) + { + return data.stream() + .collect(Collectors.toMap( + row -> String.valueOf(row.get(COL_SAMPLE_NAME_NAME)!=null?row.get(COL_SAMPLE_NAME_NAME):row.get(COL_SAMPLE_ID_NAME)), + row -> {String complexKey = row.keySet().stream() + .filter(k -> k.contains("Multi Choice")) + .findFirst() + .orElse(""); + return row.get(complexKey);} + )); + } + /** * Filtering Map according to filter and then sorting values in alphabetical order. * * @return filtered Map */ - public static Map filterMap(Map> sourceMap, List searchValues, Filter.Operator filterType) + public static Map filterMap(Map map, List searchValues, Filter.Operator filterType) { - return sourceMap.entrySet().stream() + return map.entrySet().stream() + .filter(entry -> entry.getValue() instanceof List) + .map(entry -> Map.entry(entry.getKey(), (List) entry.getValue())) .filter(entry -> isMatch(entry.getValue(), searchValues, filterType)) .collect(Collectors.toMap( Map.Entry::getKey, From 510a266bb5926f7b419578b559dcee4d0aeb5f52 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 10 Mar 2026 11:56:46 -0700 Subject: [PATCH 3/6] add values with tricky characters --- src/org/labkey/test/util/TestDataGenerator.java | 10 ++++++++++ src/org/labkey/test/util/data/TestArrayDataUtils.java | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 51a213ad13..bb916414f1 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -499,6 +499,16 @@ public static String randomString(int size) return randomString(size, null); } + public static List randomTextChoice(int size) + { + List textChoices = new ArrayList<>(); + for (int i = 0; i < size; i++) + { + textChoices.add(randomString(randomInt(0, 30))); + } + return textChoices; + } + public static String randomString(int size, @Nullable String exclusion) { return randomString(size, exclusion, CHARSET_STRING); diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index 14cb36fdae..150b2cb587 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -2,6 +2,7 @@ import org.labkey.remoteapi.query.Filter; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -31,7 +32,7 @@ public static Map getMapWithIdAndMultiChoiceField(List Map filterMap(Map map, List searchValues, Filter.Operator filterType) + public static Map filterMap(Map map, List searchValues, Filter.Operator filterType) { return map.entrySet().stream() .filter(entry -> entry.getValue() instanceof List) @@ -39,7 +40,9 @@ public static Map filterMap(Map map, List .filter(entry -> isMatch(entry.getValue(), searchValues, filterType)) .collect(Collectors.toMap( Map.Entry::getKey, - e -> e.getValue().stream().sorted().collect(Collectors.joining(", ")), + e -> e.getValue().stream() + .sorted(Comparator.comparing(String::toLowerCase)) + .collect(Collectors.joining(", ")), (e1, e2) -> e1, LinkedHashMap::new )); From 5c2040300a45f2c252a3693a6ece66c28dab4752 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 10 Mar 2026 13:44:04 -0700 Subject: [PATCH 4/6] fix filtering issue --- src/org/labkey/test/util/data/TestArrayDataUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index 150b2cb587..8b48baa34e 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -34,6 +34,7 @@ public static Map getMapWithIdAndMultiChoiceField(List Map filterMap(Map map, List searchValues, Filter.Operator filterType) { + Comparator comparator = Comparator.comparing((String s) -> s.toLowerCase()).thenComparing(s -> s); return map.entrySet().stream() .filter(entry -> entry.getValue() instanceof List) .map(entry -> Map.entry(entry.getKey(), (List) entry.getValue())) @@ -41,7 +42,7 @@ public static Map filterMap(Map map, List .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().stream() - .sorted(Comparator.comparing(String::toLowerCase)) + .sorted(comparator) .collect(Collectors.joining(", ")), (e1, e2) -> e1, LinkedHashMap::new From 78e7084545a5c65aefe1af1e3b5a4a64f82873d1 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Wed, 11 Mar 2026 07:58:09 -0700 Subject: [PATCH 5/6] fix test failure --- .../test/components/ui/search/FilterFacetedPanel.java | 11 ++++++++++- src/org/labkey/test/util/TestDataGenerator.java | 2 +- src/org/labkey/test/util/data/TestArrayDataUtils.java | 3 +-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/org/labkey/test/components/ui/search/FilterFacetedPanel.java b/src/org/labkey/test/components/ui/search/FilterFacetedPanel.java index 1ffbe27f88..cdff449be2 100644 --- a/src/org/labkey/test/components/ui/search/FilterFacetedPanel.java +++ b/src/org/labkey/test/components/ui/search/FilterFacetedPanel.java @@ -13,9 +13,12 @@ import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; +import java.io.IOException; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import static org.labkey.test.WebDriverWrapper.waitFor; import static org.labkey.test.components.html.Input.Input; public class FilterFacetedPanel extends WebDriverComponent @@ -74,9 +77,15 @@ public boolean isChecked(String value) */ public void checkValues(String... values) { + // waitForElement(elementCache().findCheckbox(values[0])); + // waitFor(() -> elementCache().findCheckbox(values[0]).isDisplayed(), 10000); for (String value : values) { - elementCache().findCheckbox(value).check(); + try{ + elementCache().findCheckbox(value).check();} + catch (Exception e){ + elementCache().findCheckbox(value).check(); + } } } diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index bb916414f1..964c193c76 100644 --- a/src/org/labkey/test/util/TestDataGenerator.java +++ b/src/org/labkey/test/util/TestDataGenerator.java @@ -504,7 +504,7 @@ public static List randomTextChoice(int size) List textChoices = new ArrayList<>(); for (int i = 0; i < size; i++) { - textChoices.add(randomString(randomInt(0, 30))); + textChoices.add(randomString(randomInt(1, 25))); } return textChoices; } diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index 8b48baa34e..150b2cb587 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -34,7 +34,6 @@ public static Map getMapWithIdAndMultiChoiceField(List Map filterMap(Map map, List searchValues, Filter.Operator filterType) { - Comparator comparator = Comparator.comparing((String s) -> s.toLowerCase()).thenComparing(s -> s); return map.entrySet().stream() .filter(entry -> entry.getValue() instanceof List) .map(entry -> Map.entry(entry.getKey(), (List) entry.getValue())) @@ -42,7 +41,7 @@ public static Map filterMap(Map map, List .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().stream() - .sorted(comparator) + .sorted(Comparator.comparing(String::toLowerCase)) .collect(Collectors.joining(", ")), (e1, e2) -> e1, LinkedHashMap::new From b6c5c63f136e0d2ded32ebc638507a1ab2790168 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Fri, 13 Mar 2026 11:39:34 -0700 Subject: [PATCH 6/6] fix comments --- .../test/util/data/TestArrayDataUtils.java | 62 +++++++++++++++---- .../labkey/test/util/data/TestDataUtils.java | 13 ---- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index 150b2cb587..ea71248b59 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -1,7 +1,12 @@ package org.labkey.test.util.data; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; import org.labkey.remoteapi.query.Filter; +import java.io.IOException; +import java.io.StringReader; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; @@ -14,16 +19,19 @@ public class TestArrayDataUtils { - public static Map getMapWithIdAndMultiChoiceField(List> data) + public static Map getMapWithIdAndMultiChoiceField(List> data) { return data.stream() .collect(Collectors.toMap( - row -> String.valueOf(row.get(COL_SAMPLE_NAME_NAME)!=null?row.get(COL_SAMPLE_NAME_NAME):row.get(COL_SAMPLE_ID_NAME)), - row -> {String complexKey = row.keySet().stream() - .filter(k -> k.contains("Multi Choice")) - .findFirst() - .orElse(""); - return row.get(complexKey);} + row -> String.valueOf(row.get(COL_SAMPLE_NAME_NAME) != null ? row.get(COL_SAMPLE_NAME_NAME) : row.get(COL_SAMPLE_ID_NAME)), + row -> + { + String complexKey = row.keySet().stream() + .filter(k -> k.contains("Multi Choice")) + .findFirst() + .orElse(""); + return row.get(complexKey); + } )); } @@ -32,7 +40,7 @@ public static Map getMapWithIdAndMultiChoiceField(List Map filterMap(Map map, List searchValues, Filter.Operator filterType) + public static Map> filterMap(Map map, List searchValues, Filter.Operator filterType) { return map.entrySet().stream() .filter(entry -> entry.getValue() instanceof List) @@ -41,13 +49,45 @@ public static Map filterMap(Map map, List .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().stream() - .sorted(Comparator.comparing(String::toLowerCase)) - .collect(Collectors.joining(", ")), + .sorted(Comparator + .comparing((String s) -> s.substring(0, 1).toLowerCase()) + .thenComparing(s -> s.substring(0, 1)) + .thenComparing(s -> s)) + .collect(Collectors.toList()), (e1, e2) -> e1, LinkedHashMap::new )); } + public static Map prepareMapForCheck(Map> map) + { + return map.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> String.join(", ", entry.getValue()), + (e1, e2) -> e1, + LinkedHashMap::new + )); + } + + public static Map filterAndPrepareMap(Map map, List searchValues, Filter.Operator filterType) + { + return prepareMapForCheck(filterMap(map, searchValues, filterType)); + } + + public static List parseMultiValueText(String multiValueString) throws IOException + { + CSVFormat format = CSVFormat.RFC4180.builder() + .setIgnoreSurroundingSpaces(true).setTrim(true).get(); + try (CSVParser parser = format.parse(new StringReader(multiValueString))) + { + List records = parser.getRecords(); + if (records.size() != 1) + throw new IllegalArgumentException("Invalid multi-value text string: " + multiValueString); + return records.getFirst().toList(); + } + } + private static boolean isMatch(List actualValues, List searchValues, Filter.Operator type) { return switch (type) @@ -59,7 +99,7 @@ private static boolean isMatch(List actualValues, List searchVal case ARRAY_CONTAINS_NOT_EXACT -> !(actualValues.size() == searchValues.size() && actualValues.containsAll(searchValues)); case ARRAY_ISEMPTY -> actualValues.isEmpty(); case ARRAY_ISNOTEMPTY -> !actualValues.isEmpty(); - default -> true; + default -> throw new IllegalArgumentException("Invalid filter type " + type); }; } } \ No newline at end of file diff --git a/src/org/labkey/test/util/data/TestDataUtils.java b/src/org/labkey/test/util/data/TestDataUtils.java index 2795dd4916..149ad38817 100644 --- a/src/org/labkey/test/util/data/TestDataUtils.java +++ b/src/org/labkey/test/util/data/TestDataUtils.java @@ -578,19 +578,6 @@ public static List> readRowsFromFile(File file, CSVFormat format) t } } - public static List parseMultiValueText(String multiValueString) throws IOException - { - CSVFormat format = CSVFormat.RFC4180.builder() - .setIgnoreSurroundingSpaces(true).setTrim(true).get(); - try (CSVParser parser = format.parse(new StringReader(multiValueString))) - { - List records = parser.getRecords(); - if (records.size() != 1) - throw new IllegalArgumentException("Invalid multi-value text string: " + multiValueString); - return records.getFirst().toList(); - } - } - public static String stringFromRows(List> rows, CSVFormat format) { StringWriter stringWriter = new StringWriter();