From 083808a21bf5bdd6e20c058a293dbbafbb4bf5fc Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Fri, 24 Apr 2026 20:49:04 -0700 Subject: [PATCH 1/4] Switch from GWT to React --- .../pages/assay/plate/PlateDesignerPage.java | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java index 3e3018795c..3ebd9c4123 100644 --- a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java +++ b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java @@ -37,46 +37,47 @@ public void createWellGroup(String type, String name) { selectTypeTab(type); - WebElement nameField = Locator.tagWithName("input", "wellGroupName") - .withAttribute("data-type", type) - .findElement(getDriver()); - setFormElement(nameField, name); - fireEvent(nameField, SeleniumEvent.change); + // Wait for the create row to be visible (canAdd must be true for this type) + WebElement newNameInput = Locator.css(".group-types-panel__new-name-input") + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); + + // If it's a text input, type the name; if it's a select, the default is already populated + if ("input".equalsIgnoreCase(newNameInput.getTagName())) + { + setFormElement(newNameInput, name); + } + // else: select already has the correct option pre-selected or we rely on default + clickButton("Create", 0); - waitForElement(Locator.tagContainingText("label", name)); + waitForElement(Locator.css(".group-types-panel__group-name").withText(name)); } public void selectTypeTab(String name) { - Locator.tagWithClass("div", "gwt-Label").withText(name).waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT).click(); + Locator.css(".group-types-panel__tab").withText(name) + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT).click(); + } + + public void selectGroup(String name) + { + Locator.css(".group-types-panel__group-name").withText(name) + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT).click(); } public void selectWellsForWellgroup(String type, String wellGroup, String startLocation, String endLocation) { selectTypeTab(type); - waitForElement(Locator.tagWithText("label", wellGroup)); - Locator start = Locator.css(".Cell-"+startLocation); - Locator end = Locator.css(".Cell-"+endLocation); - if (wellGroup != null & !"".equals(wellGroup)) + if (wellGroup != null && !wellGroup.isEmpty()) { - if (!getText(Locator.css(".gwt-TabBarItem-selected")).equals(type)) - { - Locator.css(".gwt-Label").withText(type).findElement(getDriver()).click(); - //want for switch - } - if (!isChecked(Locator.xpath("//input[@name='wellGroup' and following-sibling::label[text()='"+wellGroup+"']]"))) - click(Locator.xpath("//input[@name='wellGroup' and following-sibling::label[text()='"+wellGroup+"']]")); - if (!getAttribute(start, "style").contains("rgb(255, 255, 255)")) - click(start); - } - else - { - Locator.tagWithClass("*", "gwt-Label").withText(type).findElement(getDriver()).click(); - //select no group in order to clear area + selectGroup(wellGroup); } - WebElement fromEl = start.findElement(getDriver()); - WebElement toEl = end.findElement(getDriver()); + + // Cells are elements with title matching the location (e.g. "A1" or "A1: Specimen 1") + WebElement fromEl = Locator.css(".template-grid__cell[title^='" + startLocation + "']") + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); + WebElement toEl = Locator.css(".template-grid__cell[title^='" + endLocation + "']") + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); Actions builder = new Actions(getDriver()); builder.clickAndHold(fromEl).moveToElement(toEl).release().build().perform(); @@ -84,8 +85,8 @@ public void selectWellsForWellgroup(String type, String wellGroup, String startL public void setName(String name) { - Locator nameField = Locator.id("templateName"); - waitForElement(nameField, WAIT_FOR_JAVASCRIPT); + WebElement nameField = Locator.css(".plate-template-designer__name-input") + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); setFormElement(nameField, name); fireEvent(nameField, SeleniumEvent.change); } @@ -100,13 +101,18 @@ public void save() clickButton("Save", 0); } + public void cancel() + { + clickButton("Cancel"); + } + @Override protected ElementCache newElementCache() { return new ElementCache(); } - protected class ElementCache extends LabKeyPage.ElementCache + protected class ElementCache extends LabKeyPage.ElementCache { } From adcd33bdb59bfd33108fa72944a3a8845704e19a Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Sat, 25 Apr 2026 08:46:50 -0700 Subject: [PATCH 2/4] Auto code review and comments --- .../labkey/test/pages/assay/plate/PlateDesignerPage.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java index 3ebd9c4123..2bafd5d000 100644 --- a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java +++ b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java @@ -8,6 +8,7 @@ import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.Select; import java.util.HashMap; import java.util.Map; @@ -41,12 +42,14 @@ public void createWellGroup(String type, String name) WebElement newNameInput = Locator.css(".group-types-panel__new-name-input") .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); - // If it's a text input, type the name; if it's a select, the default is already populated if ("input".equalsIgnoreCase(newNameInput.getTagName())) { setFormElement(newNameInput, name); } - // else: select already has the correct option pre-selected or we rely on default + else + { + new Select(newNameInput).selectByVisibleText(name); + } clickButton("Create", 0); waitForElement(Locator.css(".group-types-panel__group-name").withText(name)); From f3dbe1ecadc542f30fd696cbb1d02886077678c1 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Sat, 25 Apr 2026 12:06:16 -0700 Subject: [PATCH 3/4] Test fixes --- .../pages/assay/plate/PlateDesignerPage.java | 7 +++++ .../tests/elispotassay/ElispotAssayTest.java | 2 +- .../labkey/test/tests/nab/NabAssayTest.java | 26 +++++++------------ .../tests/nab/NabHighThroughputAssayTest.java | 17 +++++------- .../tests/nab/NabMultiVirusPlateTest.java | 7 +++-- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java index 2bafd5d000..1b4c89922e 100644 --- a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java +++ b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java @@ -86,6 +86,13 @@ public void selectWellsForWellgroup(String type, String wellGroup, String startL builder.clickAndHold(fromEl).moveToElement(toEl).release().build().perform(); } + public void setWellGroupProperty(String propertyKey, String value) + { + WebElement input = Locator.tag("input").withAttribute("aria-label", propertyKey) + .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); + setFormElement(input, value); + } + public void setName(String name) { WebElement nameField = Locator.css(".plate-template-designer__name-input") diff --git a/src/org/labkey/test/tests/elispotassay/ElispotAssayTest.java b/src/org/labkey/test/tests/elispotassay/ElispotAssayTest.java index 0026867d17..d510ad8f84 100644 --- a/src/org/labkey/test/tests/elispotassay/ElispotAssayTest.java +++ b/src/org/labkey/test/tests/elispotassay/ElispotAssayTest.java @@ -467,7 +467,7 @@ protected void createTemplate() plateDesigner.selectTypeTab("CONTROL"); clickButton("Create", 0); - waitForElement(Locator.tagWithText("label", "Background Wells")); + waitForElement(Locator.tagWithText("span", "Background Wells")); plateDesigner.selectWellsForWellgroup("CONTROL", "Background Wells", "A1", "B3"); plateDesigner.selectWellsForWellgroup("CONTROL", "Background Wells", "C4", "D6"); diff --git a/src/org/labkey/test/tests/nab/NabAssayTest.java b/src/org/labkey/test/tests/nab/NabAssayTest.java index b064647619..135489dd78 100644 --- a/src/org/labkey/test/tests/nab/NabAssayTest.java +++ b/src/org/labkey/test/tests/nab/NabAssayTest.java @@ -210,28 +210,22 @@ public void runUITests() .setAssayType("NAb") .setTemplateType("single-plate"))); - setFormElement(Locator.inputById("templateName"), PLATE_TEMPLATE_NAME); + PlateDesignerPage designerPage = new PlateDesignerPage(getDriver()); + designerPage.setName(PLATE_TEMPLATE_NAME); + designerPage.selectTypeTab("SPECIMEN"); - // select the specimen wellgroup tab - click(Locator.tagWithText("div", "SPECIMEN")); + designerPage.selectGroup("Specimen 1"); + designerPage.setWellGroupProperty("ReverseDilutionDirection", "true"); - // select the first specimen group - click(Locator.tagWithText("label", "Specimen 1")); - // set reversed dilution direction to true: - setFormElement(Locator.inputById("property-ReverseDilutionDirection"), "true"); + designerPage.selectGroup("Specimen 2"); + designerPage.setWellGroupProperty("ReverseDilutionDirection", "false"); - // select the second specimen group - click(Locator.tagWithText("label", "Specimen 2")); - // set reversed dilution direction to false: - setFormElement(Locator.inputById("property-ReverseDilutionDirection"), "false"); - - // select the third specimen group - click(Locator.tagWithText("label", "Specimen 3")); + designerPage.selectGroup("Specimen 3"); // set reversed dilution direction to a nonsense value: - setFormElement(Locator.inputById("property-ReverseDilutionDirection"), "invalid boolean value"); + designerPage.setWellGroupProperty("ReverseDilutionDirection", "invalid boolean value"); // note that we're intentionally leaving the fourth and fifth direction specifiers null, which should default to 'false' - clickButton("Save & Close"); + designerPage.saveAndClose(); assertTextPresent(PLATE_TEMPLATE_NAME, "NAb: 5 specimens in duplicate"); diff --git a/src/org/labkey/test/tests/nab/NabHighThroughputAssayTest.java b/src/org/labkey/test/tests/nab/NabHighThroughputAssayTest.java index b79a98628d..f8cc429f4e 100644 --- a/src/org/labkey/test/tests/nab/NabHighThroughputAssayTest.java +++ b/src/org/labkey/test/tests/nab/NabHighThroughputAssayTest.java @@ -88,12 +88,9 @@ protected void doInit() .setAssayType("NAb") .setTemplateType("high-throughput (single plate dilution)"))); - Locator.IdLocator nameField = Locator.id("templateName"); - waitForElement(nameField, WAIT_FOR_JAVASCRIPT); - setFormElement(nameField, PLATE_TEMPLATE_NAME); - fireEvent(nameField, SeleniumEvent.change); - - clickButton("Save & Close"); + PlateDesignerPage designerPage = new PlateDesignerPage(getDriver()); + designerPage.setName(PLATE_TEMPLATE_NAME); + designerPage.saveAndClose(); assertTextPresent(PLATE_TEMPLATE_NAME); // create the cross plate dilution template @@ -103,11 +100,9 @@ protected void doInit() .setAssayType("NAb") .setTemplateType("high-throughput (cross plate dilution)"))); - waitForElement(nameField, WAIT_FOR_JAVASCRIPT); - setFormElement(nameField, CPD_PLATE_TEMPLATE_NAME); - fireEvent(nameField, SeleniumEvent.change); - - clickButton("Save & Close"); + designerPage = new PlateDesignerPage(getDriver()); + designerPage.setName(CPD_PLATE_TEMPLATE_NAME); + designerPage.saveAndClose(); assertTextPresent(CPD_PLATE_TEMPLATE_NAME); _containerHelper.createSubfolder(getProjectName(), TEST_ASSAY_FLDR_NAB); diff --git a/src/org/labkey/test/tests/nab/NabMultiVirusPlateTest.java b/src/org/labkey/test/tests/nab/NabMultiVirusPlateTest.java index 6359c13867..54f0537d86 100644 --- a/src/org/labkey/test/tests/nab/NabMultiVirusPlateTest.java +++ b/src/org/labkey/test/tests/nab/NabMultiVirusPlateTest.java @@ -111,10 +111,9 @@ private void doCreateSteps() .setAssayType("NAb") .setTemplateType("multi-virus plate"))); - waitForElement(Locator.xpath("//input[@id='templateName']"), WAIT_FOR_JAVASCRIPT); - setFormElement(Locator.xpath("//input[@id='templateName']"), PLATE_TEMPLATE_NAME); - - clickButton("Save & Close"); + PlateDesignerPage designerPage = new PlateDesignerPage(getDriver()); + designerPage.setName(PLATE_TEMPLATE_NAME); + designerPage.saveAndClose(); goToProjectHome(); From 35c22d4e13e226c153d389e4c58bb3adf57d2b8a Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Mon, 27 Apr 2026 19:09:36 -0700 Subject: [PATCH 4/4] Unit tests and other improvements --- .../labkey/test/pages/assay/plate/PlateDesignerPage.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java index 1b4c89922e..75fddd7e6c 100644 --- a/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java +++ b/src/org/labkey/test/pages/assay/plate/PlateDesignerPage.java @@ -76,10 +76,10 @@ public void selectWellsForWellgroup(String type, String wellGroup, String startL selectGroup(wellGroup); } - // Cells are elements with title matching the location (e.g. "A1" or "A1: Specimen 1") - WebElement fromEl = Locator.css(".template-grid__cell[title^='" + startLocation + "']") + // Cells are elements with aria-label matching the location (e.g. "A1" or "A1: Specimen 1") + WebElement fromEl = Locator.css(".template-grid__cell[aria-label^='" + startLocation + "']") .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); - WebElement toEl = Locator.css(".template-grid__cell[title^='" + endLocation + "']") + WebElement toEl = Locator.css(".template-grid__cell[aria-label^='" + endLocation + "']") .waitForElement(getDriver(), WAIT_FOR_JAVASCRIPT); Actions builder = new Actions(getDriver());