From 4ebccdcedb69caffd8608650eb826aeb1ecdce48 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Sun, 13 Sep 2026 11:50:30 -0700 Subject: [PATCH 1/4] Docs and more --- .../test/util/exp/SampleTypeAPIHelper.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java b/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java index 45c1d4d649..5de3a606ab 100644 --- a/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java +++ b/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java @@ -19,6 +19,7 @@ import org.junit.Assert; import org.labkey.remoteapi.CommandException; import org.labkey.remoteapi.Connection; +import org.labkey.remoteapi.query.ContainerFilter; import org.labkey.remoteapi.query.Filter; import org.labkey.remoteapi.query.SelectRowsCommand; import org.labkey.remoteapi.query.SelectRowsResponse; @@ -201,6 +202,27 @@ public static Map getRowIdsForSamples(String containerPath, Str return rowIds; } + /** + * Row ids of every sample type named {@code sampleTypeName} that is visible from {@code containerPath}, in the + * CurrentPlusProjectAndShared scope a sample type lookup resolves against. + * + *

Manufacturing a rowId/name collision needs the id the server actually assigned, because + * {@code exp.MaterialSource.RowId} is a database-wide sequence: a hardcoded numeric sample type name collides +fix 2, 6, 7 * only when the sequence happens to cooperate. Require exactly one match as well, since a resolver reports an + * ambiguity rather than picking, and that error is swallowed by the import code. + */ + public static List getSampleTypeRowIds(String containerPath, String sampleTypeName) throws IOException, CommandException + { + SelectRowsCommand cmd = new SelectRowsCommand("exp", "SampleSets"); + cmd.setColumns(List.of("RowId")); + cmd.addFilter("Name", sampleTypeName, Filter.Operator.EQUAL); + cmd.setContainerFilter(ContainerFilter.CurrentPlusProjectAndShared); + + return cmd.execute(WebTestHelper.getRemoteApiConnection(), containerPath).getRows().stream() + .map(row -> Integer.parseInt(row.get("RowId").toString())) + .toList(); + } + /** * Get sample state IDs defined in the specified project/folder. Useful for updating sample status via API * @param containerPath Path to the project/folder where the sample statuses are defined (typically project) From d44032fffefb57156c41540fc146ad83083b20f0 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Mon, 14 Sep 2026 11:57:52 -0700 Subject: [PATCH 2/4] Fix stray text --- src/org/labkey/test/util/exp/SampleTypeAPIHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java b/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java index 5de3a606ab..552b66b483 100644 --- a/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java +++ b/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java @@ -208,7 +208,7 @@ public static Map getRowIdsForSamples(String containerPath, Str * *

Manufacturing a rowId/name collision needs the id the server actually assigned, because * {@code exp.MaterialSource.RowId} is a database-wide sequence: a hardcoded numeric sample type name collides -fix 2, 6, 7 * only when the sequence happens to cooperate. Require exactly one match as well, since a resolver reports an + * only when the sequence happens to cooperate. Require exactly one match as well, since a resolver reports an * ambiguity rather than picking, and that error is swallowed by the import code. */ public static List getSampleTypeRowIds(String containerPath, String sampleTypeName) throws IOException, CommandException From 9ebd985c5437f27cf430cc37186e3b1cff2bd6bb Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Sun, 27 Sep 2026 21:40:49 -0700 Subject: [PATCH 3/4] Trim getSampleTypeRowIds Javadoc --- src/org/labkey/test/util/exp/SampleTypeAPIHelper.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java b/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java index 552b66b483..e008169a76 100644 --- a/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java +++ b/src/org/labkey/test/util/exp/SampleTypeAPIHelper.java @@ -203,13 +203,7 @@ public static Map getRowIdsForSamples(String containerPath, Str } /** - * Row ids of every sample type named {@code sampleTypeName} that is visible from {@code containerPath}, in the - * CurrentPlusProjectAndShared scope a sample type lookup resolves against. - * - *

Manufacturing a rowId/name collision needs the id the server actually assigned, because - * {@code exp.MaterialSource.RowId} is a database-wide sequence: a hardcoded numeric sample type name collides - * only when the sequence happens to cooperate. Require exactly one match as well, since a resolver reports an - * ambiguity rather than picking, and that error is swallowed by the import code. + * Row ids of sample types named {@code sampleTypeName} visible from {@code containerPath} under CurrentPlusProjectAndShared. */ public static List getSampleTypeRowIds(String containerPath, String sampleTypeName) throws IOException, CommandException { From df98b87be78ee319221575c37e065731fae3421f Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Tue, 29 Sep 2026 07:51:36 -0700 Subject: [PATCH 4/4] Attempt to fix flakiness in TimeChartDateBasedTest --- .../labkey/test/components/ChartTypeDialog.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/org/labkey/test/components/ChartTypeDialog.java b/src/org/labkey/test/components/ChartTypeDialog.java index 7659d89692..d0e91e37c7 100644 --- a/src/org/labkey/test/components/ChartTypeDialog.java +++ b/src/org/labkey/test/components/ChartTypeDialog.java @@ -193,11 +193,15 @@ public ChartTypeDialog setYAxis(String columnName, boolean hasExistingSelection) public ChartTypeDialog setYAxisSide(int measureIndex, YAxisSide side) { - WebElement measureEl = elementCache().Y_FIELD_DISPLAY.index(measureIndex).findElement(this); - if (!measureEl.getAttribute("class").contains("selected")) - { - Locator.byClass("field-selection-text").findElement(measureEl).click(); - } + Locator measureLoc = elementCache().Y_FIELD_DISPLAY.index(measureIndex); + // A click that lands while the dialog is still rendering doesn't select the measure, so retry it + WebDriverWrapper.waitFor(() -> { + WebElement el = measureLoc.findElement(this); + if (!el.getAttribute("class").contains("x4-item-selected")) + Locator.byClass("field-selection-text").findElement(el).click(); + return WebDriverWrapper.waitFor(() -> measureLoc.findElement(this).getAttribute("class").contains("x4-item-selected"), 1_000); + }, "Y axis measure " + measureIndex + " was not selected", 5_000); + WebElement measureEl = measureLoc.findElement(this); WebElement arrow = Locator.tagWithClass("i", "fa-arrow-circle-" + side.name().toLowerCase()).waitForElement(measureEl, 5_000); WebDriverWait quickWait = new WebDriverWait(getWrapper().getDriver(), Duration.ofSeconds(4)); quickWait.until(ExpectedConditions.visibilityOf(arrow));