From 0ccd659b7e896d5740bfc7b0536ec19328359b80 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:11:23 -0700 Subject: [PATCH 1/6] just first working changes no formatting --- .../components/domain/DomainFieldRow.java | 2 +- .../test/pages/assay/AssayRunsPage.java | 6 +++ .../test/util/data/TestArrayDataUtils.java | 41 +++++++++++++++---- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/org/labkey/test/components/domain/DomainFieldRow.java b/src/org/labkey/test/components/domain/DomainFieldRow.java index 5261edb788..03a1d597b1 100644 --- a/src/org/labkey/test/components/domain/DomainFieldRow.java +++ b/src/org/labkey/test/components/domain/DomainFieldRow.java @@ -770,7 +770,7 @@ public DomainFieldRow clickRemoveOntologyConcept() public void setAllowMultipleSelections(Boolean allowMultipleSelections) { WebDriverWrapper.waitFor(() -> elementCache().allowMultipleSelectionsCheckbox.isDisplayed(), - "Allow Multiple Selections checkbox did not become visible", 2000); + "Allow Multiple Selections checkbox did not become visible", 1000); elementCache().allowMultipleSelectionsCheckbox.set(allowMultipleSelections); } diff --git a/src/org/labkey/test/pages/assay/AssayRunsPage.java b/src/org/labkey/test/pages/assay/AssayRunsPage.java index 48f679da12..a90d4f7950 100644 --- a/src/org/labkey/test/pages/assay/AssayRunsPage.java +++ b/src/org/labkey/test/pages/assay/AssayRunsPage.java @@ -113,6 +113,12 @@ public void clickEditAssayDesign() elementCache().manageMenu.doMenuAction("Edit Assay Design"); } + public AssayImportPage clickImportData() + { + clickAndWait(Locator.linkWithText("Import Data")); + return new AssayImportPage(getDriver()); + } + @Override protected ElementCache newElementCache() { diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index e878d2e790..8c26e15579 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -2,11 +2,13 @@ import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.CSVRecord; import org.labkey.remoteapi.query.Filter; import java.io.IOException; import java.io.StringReader; +import java.io.StringWriter; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; @@ -45,19 +47,27 @@ public static Map> filterMap(Map map, List isMatch(entry.getValue(), searchValues, filterType)) .collect(Collectors.toMap( Map.Entry::getKey, - e -> e.getValue().stream() - // Standard alphabetical sort that accounts for symbols and numbers. - // But uppercase letters are positioned before lowercase letters. - .sorted(Comparator - .comparing((String s) -> s.substring(0, 1).toLowerCase()) - .thenComparing(s -> s.substring(0, 1)) - .thenComparing(s -> s)) - .collect(Collectors.toList()), + e -> sortValues(e.getValue()), (e1, e2) -> e1, LinkedHashMap::new )); } + /** + * Standard alphabetical sort that accounts for symbols and numbers. + * Uppercase letters are positioned before lowercase letters. + */ + public static List sortValues(List values) + { + return values.stream() + .filter(s -> !s.isEmpty()) + .sorted(Comparator + .comparing((String s) -> s.substring(0, 1).toLowerCase()) + .thenComparing(s -> s.substring(0, 1)) + .thenComparing(s -> s)) + .collect(Collectors.toList()); + } + public static Map prepareMapForCheck(Map> map) { return map.entrySet().stream() @@ -87,6 +97,21 @@ public static List parseMultiValueText(String multiValueString) throws I } } + public static String formatMultiValueText(List values) + { + CSVFormat format = CSVFormat.RFC4180; + StringWriter stringWriter = new StringWriter(); + try (CSVPrinter printer = new CSVPrinter(stringWriter, format)) + { + printer.printRecord(values); + } + catch (IOException e) + { + throw new RuntimeException("Failed to format multi-value text", e); + } + return stringWriter.toString().trim(); + } + private static boolean isMatch(List actualValues, List searchValues, Filter.Operator type) { return switch (type) From a4ff5388bf815225ee8c08791a52bc5e8611e0a2 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Fri, 20 Mar 2026 15:50:02 -0700 Subject: [PATCH 2/6] formatted version --- src/org/labkey/test/util/data/TestArrayDataUtils.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index 8c26e15579..c11fc3f12a 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -68,6 +68,14 @@ public static List sortValues(List values) .collect(Collectors.toList()); } + /** + * Sorts values alphabetically and joins them with the given separator. + */ + public static String sortAndJoin(List values, String separator) + { + return String.join(separator, sortValues(values)); + } + public static Map prepareMapForCheck(Map> map) { return map.entrySet().stream() From 92039b332432e43a6b447c5a288c36e68cb89944 Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Mon, 23 Mar 2026 10:44:34 -0700 Subject: [PATCH 3/6] exclude some characters --- src/org/labkey/test/util/TestDataGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 6f10582645..77363e1a59 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) Set textChoices = new LinkedHashSet<>(); while (textChoices.size() < size) { - String generated = randomString(randomInt(1, 25)).trim(); + String generated = randomString(randomInt(1, 25), "%<>").trim(); if (!generated.isEmpty()) { textChoices.add(generated); From bbd7b3709396acaa147d706b5ec345576260faef Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:00:01 -0700 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Trey Chadick --- src/org/labkey/test/util/data/TestArrayDataUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index c11fc3f12a..73f8fc3dc7 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -60,7 +60,7 @@ public static Map> filterMap(Map map, List sortValues(List values) { return values.stream() - .filter(s -> !s.isEmpty()) + .peek(s -> { if (s.isEmpty()) throw new IllegalArgumentException("Empty values aren't allowed: " + values);}) .sorted(Comparator .comparing((String s) -> s.substring(0, 1).toLowerCase()) .thenComparing(s -> s.substring(0, 1)) From b920794c1448ddcc500169d0c7f43761fd1602bd Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:29:16 -0700 Subject: [PATCH 5/6] fix pr comments --- src/org/labkey/test/pages/assay/AssayRunsPage.java | 1 + src/org/labkey/test/util/TestDataGenerator.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/pages/assay/AssayRunsPage.java b/src/org/labkey/test/pages/assay/AssayRunsPage.java index a90d4f7950..a56716f543 100644 --- a/src/org/labkey/test/pages/assay/AssayRunsPage.java +++ b/src/org/labkey/test/pages/assay/AssayRunsPage.java @@ -113,6 +113,7 @@ public void clickEditAssayDesign() elementCache().manageMenu.doMenuAction("Edit Assay Design"); } + //Method for Standard assays only. public AssayImportPage clickImportData() { clickAndWait(Locator.linkWithText("Import Data")); diff --git a/src/org/labkey/test/util/TestDataGenerator.java b/src/org/labkey/test/util/TestDataGenerator.java index 77363e1a59..6f10582645 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) Set textChoices = new LinkedHashSet<>(); while (textChoices.size() < size) { - String generated = randomString(randomInt(1, 25), "%<>").trim(); + String generated = randomString(randomInt(1, 25)).trim(); if (!generated.isEmpty()) { textChoices.add(generated); From 5ac461eec074c775567c56d1fae06effb15e023b Mon Sep 17 00:00:00 2001 From: Daria Bodiakova <70635654+DariaBod@users.noreply.github.com> Date: Wed, 25 Mar 2026 13:27:19 -0700 Subject: [PATCH 6/6] fix comments --- .../components/ui/grids/EditableGrid.java | 34 +++++++++++++++++++ .../test/util/data/TestArrayDataUtils.java | 16 ++------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/org/labkey/test/components/ui/grids/EditableGrid.java b/src/org/labkey/test/components/ui/grids/EditableGrid.java index 937db346c2..6b1c20097d 100644 --- a/src/org/labkey/test/components/ui/grids/EditableGrid.java +++ b/src/org/labkey/test/components/ui/grids/EditableGrid.java @@ -56,6 +56,7 @@ import static org.labkey.test.BaseWebDriverTest.WAIT_FOR_JAVASCRIPT; import static org.labkey.test.WebDriverWrapper.waitFor; import static org.labkey.test.util.TestLogger.log; +import static org.labkey.test.util.data.TestArrayDataUtils.formatMultiValueText; import static org.labkey.test.util.selenium.ScrollUtils.Alignment.center; import static org.labkey.test.util.selenium.WebDriverUtils.MODIFIER_KEY; @@ -921,6 +922,39 @@ public EditableGrid pasteMultipleCells(String pasteText, int startRowIndex, Char return this; } + /** + * Format data for pasting into an editable grid. List elements in each row are quoted and separated by commas. + * This allows values containing commas to be pasted into multi-value columns. Even single-selections for these + * types of columns should be passed in as Lists to ensure they are quoted properly. + * + * @param rows values for pasting into an editable grid. + * @return rows formatted for pasting into an editable grid. + */ + public static String formatForPaste(List> rows) + { + StringBuilder sb = new StringBuilder(); + for (List row : rows) + { + if (!sb.isEmpty()) + sb.append("\n"); + + boolean firstVal = true; + for (Object value : row) + { + if (!firstVal) + sb.append("\t"); + else + firstVal = false; + + if (value instanceof List l) + sb.append(formatMultiValueText(l)); + else + sb.append(value); + } + } + return sb.toString(); + } + /** * Copies text from the grid, b * @param startRowIndex Index of the top-left cell's row diff --git a/src/org/labkey/test/util/data/TestArrayDataUtils.java b/src/org/labkey/test/util/data/TestArrayDataUtils.java index 73f8fc3dc7..7509828bdb 100644 --- a/src/org/labkey/test/util/data/TestArrayDataUtils.java +++ b/src/org/labkey/test/util/data/TestArrayDataUtils.java @@ -2,13 +2,11 @@ import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; -import org.apache.commons.csv.CSVPrinter; import org.apache.commons.csv.CSVRecord; import org.labkey.remoteapi.query.Filter; import java.io.IOException; import java.io.StringReader; -import java.io.StringWriter; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; @@ -105,19 +103,9 @@ public static List parseMultiValueText(String multiValueString) throws I } } - public static String formatMultiValueText(List values) + public static String formatMultiValueText(List values) { - CSVFormat format = CSVFormat.RFC4180; - StringWriter stringWriter = new StringWriter(); - try (CSVPrinter printer = new CSVPrinter(stringWriter, format)) - { - printer.printRecord(values); - } - catch (IOException e) - { - throw new RuntimeException("Failed to format multi-value text", e); - } - return stringWriter.toString().trim(); + return values.stream().map(CSVFormat.DEFAULT::format).collect(Collectors.joining(",")); } private static boolean isMatch(List actualValues, List searchValues, Filter.Operator type)