From de9b9cb503a4b33ba3d3ec4ea003a47e43f9b8d1 Mon Sep 17 00:00:00 2001 From: cnathe Date: Thu, 9 Oct 2025 13:32:28 -0500 Subject: [PATCH 01/11] Test helper updates for chart field options modal selection of Y Axis Aggregate Method from tooltip --- .../components/react/QueryChartDialog.java | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index cc028eae8f..6c94f18cae 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -98,10 +98,9 @@ public boolean hasAxisFieldOptions(String label) return elementCache().fieldOptionIconByLabel(label) != null; } - private QueryChartDialog clickAxisFieldOptions(String label) + private void clickFieldOptions(String label) { elementCache().fieldOptionIconByLabel(label).click(); - return this; } /** @@ -112,23 +111,23 @@ private QueryChartDialog clickAxisFieldOptions(String label) */ public QueryChartDialog setAxisScaleType(String label, String value) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover if ("linear".equalsIgnoreCase(value)) elementCache().scaleLinearRadio.check(); else if ("log".equalsIgnoreCase(value)) elementCache().scaleLogRadio.check(); else throw new IllegalArgumentException("Invalid scale value: " + value); - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return this; } public boolean isAxisScaleTypeSelected(String label, String value) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover boolean selected = "linear".equalsIgnoreCase(value) ? elementCache().scaleLinearRadio.isChecked() : "log".equalsIgnoreCase(value) && elementCache().scaleLogRadio.isChecked(); - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return selected; } @@ -140,51 +139,51 @@ public boolean isAxisScaleTypeSelected(String label, String value) */ public QueryChartDialog setAxisRangeType(String label, String value) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover if ("automatic".equalsIgnoreCase(value)) elementCache().scaleAutomaticRadio.check(); else if ("manual".equalsIgnoreCase(value)) elementCache().scaleManualRadio.check(); else throw new IllegalArgumentException("Invalid range value: " + value); - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return this; } public boolean isAxisRangeTypeSelected(String label, String value) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover boolean selected = "automatic".equalsIgnoreCase(value) ? elementCache().scaleAutomaticRadio.isChecked() : "manual".equalsIgnoreCase(value) && elementCache().scaleManualRadio.isChecked(); - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return selected; } public QueryChartDialog setAxisRange(String label, String min, String max) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover if (elementCache().scaleManualRadio.isChecked()) { elementCache().scaleRangeMinInput.set(min); elementCache().scaleRangeMaxInput.set(max); } - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return this; } public String getAxisRangeMin(String label) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover String min = elementCache().scaleRangeMinInput.get(); - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return min; } public String getAxisRangeMax(String label) { - clickAxisFieldOptions(label); // open the popover + clickFieldOptions(label); // open the popover String max = elementCache().scaleRangeMaxInput.get(); - clickAxisFieldOptions(label); // close the popover + clickFieldOptions(label); // close the popover return max; } @@ -212,13 +211,25 @@ public List getYAxisSelectionOptions() */ public QueryChartDialog selectYAxisAggregateMethod(String option) { - elementCache().reactSelectByLabel("Y Axis Aggregate Method").select(option); + clickFieldOptions("Y Axis"); // open the popover + getAggregateMethodSelect().select(option); + Locator.tagWithText("label", "Name *").findElement(this).click(); // close the popover return this; } public String getYAxisAggregateMethod() { - return elementCache().reactSelectByLabel("Y Axis Aggregate Method").getValue(); + clickFieldOptions("Y Axis"); // open the popover + String value = getAggregateMethodSelect().getValue(); + Locator.tagWithText("label", "Name *").findElement(this).click(); // close the popover + return value; + } + + private ReactSelect getAggregateMethodSelect() + { + // can't use elementCache().reactSelectByLabel because the popover is outside the dialog + Locator loc = Locator.tag("div").withChild(Locator.tagContainingText("label", "Aggregate Method")); + return ReactSelect.finder(getDriver()).find(loc.waitForElement(getDriver(), 1500)); } /* From f7b9095e70d591c557c20145de1743284b66de1d Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 13 Oct 2025 09:01:17 -0500 Subject: [PATCH 02/11] BiologicsReportTest update for error bar options in bar chart --- .../components/react/QueryChartDialog.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index 6c94f18cae..f67318d0b1 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -206,9 +206,6 @@ public List getYAxisSelectionOptions() return elementCache().reactSelectByLabel("Y Axis").getOptions(); } - /* - Y Axis Aggregate Method is an option for bar chart - */ public QueryChartDialog selectYAxisAggregateMethod(String option) { clickFieldOptions("Y Axis"); // open the popover @@ -227,11 +224,25 @@ public String getYAxisAggregateMethod() private ReactSelect getAggregateMethodSelect() { - // can't use elementCache().reactSelectByLabel because the popover is outside the dialog + // can't use elementCache() because the popover is outside the dialog Locator loc = Locator.tag("div").withChild(Locator.tagContainingText("label", "Aggregate Method")); return ReactSelect.finder(getDriver()).find(loc.waitForElement(getDriver(), 1500)); } + private RadioButton getErrorBarsRadio(String value) + { + // can't use elementCache() because the popover is outside the dialog + return RadioButton.RadioButton(Locator.radioButtonByNameAndValue("error-bar-method", value)).find(getDriver()); + } + + public QueryChartDialog selectYAxisErrorBar(String value) + { + clickFieldOptions("Y Axis"); // open the popover + getErrorBarsRadio(value).check(); + Locator.tagWithText("label", "Name *").findElement(this).click(); // close the popover + return this; + } + /* groupBy is an option for bar charts only */ From 5af0f477b6d59591185c6713ff59f4e9506cb8a1 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 13 Oct 2025 16:29:51 -0500 Subject: [PATCH 03/11] BiologicsReportTest.testBarChartWithAggregateMethod updates for error bar radio options --- .../test/components/react/QueryChartDialog.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index f67318d0b1..2ff3b0fcec 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -214,6 +214,14 @@ public QueryChartDialog selectYAxisAggregateMethod(String option) return this; } + public List getYAxisAggregateMethodOptions() + { + clickFieldOptions("Y Axis"); // open the popover + List options = getAggregateMethodSelect().getOptions(); + Locator.tagWithText("label", "Name *").findElement(this).click(); // close the popover + return options; + } + public String getYAxisAggregateMethod() { clickFieldOptions("Y Axis"); // open the popover @@ -243,6 +251,14 @@ public QueryChartDialog selectYAxisErrorBar(String value) return this; } + public boolean isYAxisErrorBarOptionEnabled(String value) + { + clickFieldOptions("Y Axis"); // open the popover + boolean enabled = getErrorBarsRadio(value).isEnabled(); + Locator.tagWithText("label", "Name *").findElement(this).click(); // close the popover + return enabled; + } + /* groupBy is an option for bar charts only */ From 7bca076cbe796be3b30a0cc7725fe7e037325ddc Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 15 Oct 2025 11:40:47 -0500 Subject: [PATCH 04/11] QueryChartDialog.clickSaveChart to wait for previous chart SVG to go stale --- src/org/labkey/test/components/react/QueryChartDialog.java | 2 ++ src/org/labkey/test/components/react/QueryChartPanel.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index 2ff3b0fcec..5dc350248e 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -441,9 +441,11 @@ public QueryChartPanel clickCreateChart() */ public QueryChartPanel clickSaveChart() { + WebElement prevChart = _queryGrid.getChartPanel().getSvgChart(); WebDriverWrapper.waitFor(this::isSaveChartButtonEnabled, "the Save chart button did not become enabled", 2000); dismiss("Save Chart"); + getWrapper().shortWait().until(ExpectedConditions.stalenessOf(prevChart)); return _queryGrid.getChartPanel(); } diff --git a/src/org/labkey/test/components/react/QueryChartPanel.java b/src/org/labkey/test/components/react/QueryChartPanel.java index 6f4b856508..106e49f330 100644 --- a/src/org/labkey/test/components/react/QueryChartPanel.java +++ b/src/org/labkey/test/components/react/QueryChartPanel.java @@ -52,7 +52,7 @@ public String getTitle() public WebElement getSvgChart() { - return Locator.byClass("svg-chart").waitForElement(this, WAIT_FOR_JAVASCRIPT); + return Locator.byClass("svg-chart__chart").childTag("svg").waitForElement(this, WAIT_FOR_JAVASCRIPT); } public QueryGrid clickClose() From 067e124bab3e05c5bdd3b8e17cba121313a66bb8 Mon Sep 17 00:00:00 2001 From: cnathe Date: Wed, 15 Oct 2025 16:59:57 -0500 Subject: [PATCH 05/11] BarPlotTest updates for aggregate method and error bar options --- .../test/components/ChartLayoutDialog.java | 22 +++++++++++++++ .../test/tests/visualization/BarPlotTest.java | 27 ++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/components/ChartLayoutDialog.java b/src/org/labkey/test/components/ChartLayoutDialog.java index 63bf6db606..9bba563d17 100644 --- a/src/org/labkey/test/components/ChartLayoutDialog.java +++ b/src/org/labkey/test/components/ChartLayoutDialog.java @@ -190,6 +190,25 @@ public ChartLayoutDialog setYAxisRangeMinMax(String min, String max) return this; } + public ChartLayoutDialog setYAxisAggregateMethod(String method) + { + clickYAxisTab(); + getWrapper()._ext4Helper.selectComboBoxItem("Aggregate Method:", method); + return this; + } + + public ChartLayoutDialog setYAxisErrorBarsMethod(String method) + { + clickYAxisTab(); + if (method.equals("Standard Deviation")) + getWrapper().click(elementCache().sdErrorBarRadioButton); + else if (method.equals("Standard Error of the Mean")) + getWrapper().click(elementCache().semErrorBarRadioButton); + else + getWrapper().click(elementCache().noneErrorBarRadioButton); + return this; + } + protected void setLabel(String label) { getWrapper().setFormElement(elementCache().visibleLabelTextBox, label); @@ -461,6 +480,9 @@ class ElementCache extends ChartWizardDialog.ElementCache public Locator visibleLabelTextBox = Locator.xpath(VISIBLE_PANEL_XPATH + "//input[@name='label']"); public Locator visibleRangeMinTextBox = Locator.xpath(VISIBLE_PANEL_XPATH + "//input[@name='rangeMin']"); public Locator visibleRangeMaxTextBox = Locator.xpath(VISIBLE_PANEL_XPATH + "//input[@name='rangeMax']"); + public Locator noneErrorBarRadioButton = Locator.xpath(VISIBLE_PANEL_XPATH + "//label[text()='None']/preceding-sibling::input[@type='button']"); + public Locator sdErrorBarRadioButton = Locator.xpath(VISIBLE_PANEL_XPATH + "//label[text()='Standard Deviation']/preceding-sibling::input[@type='button']"); + public Locator semErrorBarRadioButton = Locator.xpath(VISIBLE_PANEL_XPATH + "//label[text()='Standard Error of the Mean']/preceding-sibling::input[@type='button']"); } public enum ScaleType diff --git a/src/org/labkey/test/tests/visualization/BarPlotTest.java b/src/org/labkey/test/tests/visualization/BarPlotTest.java index aec1e17bdd..e6cf769adf 100644 --- a/src/org/labkey/test/tests/visualization/BarPlotTest.java +++ b/src/org/labkey/test/tests/visualization/BarPlotTest.java @@ -66,6 +66,11 @@ public class BarPlotTest extends GenericChartsTest private final String MIN_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n-1\n-0.9\n-0.8\n-0.7\n-0.6\n-0.5\n-0.4\n-0.3\n-0.2\n-0.1\n0\nTypes\nStudy: Cohort\nMin of Double"; private final String MAX_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n1e+7\n2e+7\n3e+7\n4e+7\n5e+7\n6e+7\n7e+7\n8e+7\n9e+7\n1e+8\n1.1e+8\n1.2e+8\nTypes\nStudy: Cohort\nMax of Double"; private final String MEAN_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n2e+6\n4e+6\n6e+6\n8e+6\n1e+7\n1.2e+7\n1.4e+7\n1.6e+7\n1.8e+7\n2e+7\nTypes\nStudy: Cohort\nMean of Double"; + private final String MEAN_SD_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n1e+7\n2e+7\n3e+7\n4e+7\n5e+7\n6e+7\nTypes\nStudy: Cohort\nMean of Double"; + private final String MEAN_SEM_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n5e+6\n1e+7\n1.5e+7\n2e+7\n2.5e+7\n3e+7\nTypes\nStudy: Cohort\nMean of Double"; + private final String MEAN_NONE_GROUPED_BAR_PLOT_SVG_TEXT = "Enroll/Vacc#1\nScreening\n0\n2e+6\n4e+6\n6e+6\n8e+6\n1e+7\n1.2e+7\n1.4e+7\n1.6e+7\n1.8e+7\n2e+7\n2.2e+7\n2.4e+7\nTypes\nVisit\nMean of Double\nGroup 1\nGroup 2"; + private final String MEAN_SD_GROUPED_BAR_PLOT_SVG_TEXT = "Enroll/Vacc#1\nScreening\n0\n1e+7\n2e+7\n3e+7\n4e+7\n5e+7\n6e+7\n7e+7\nTypes\nVisit\nMean of Double\nGroup 1\nGroup 2"; + private final String MEAN_SEM_GROUPED_BAR_PLOT_SVG_TEXT = "Enroll/Vacc#1\nScreening\n0\n5e+6\n1e+7\n1.5e+7\n2e+7\n2.5e+7\n3e+7\n3.5e+7\n4e+7\n4.5e+7\nTypes\nVisit\nMean of Double\nGroup 1\nGroup 2"; private final String MEDIAN_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n0.05\n0.1\n0.15\n0.2\n0.25\n0.3\n0.35\n0.4\n0.45\n0.5\n0.55\n0.6\nTypes\nStudy: Cohort\nMedian of Double"; @Override @@ -462,14 +467,34 @@ private void doYAxisAggregateMethodTest() setBarAggregateMethodAndVerify("Mean", MEAN_BAR_PLOT_SVG_TEXT); setBarAggregateMethodAndVerify("Median", MEDIAN_BAR_PLOT_SVG_TEXT); + log("Change and verify error bar types for Mean aggregate method"); + setBarAggregateMethodAndVerify("Mean", null); + setBarErrorBarMethodAndVerify("Standard Deviation", MEAN_SD_BAR_PLOT_SVG_TEXT); + setBarErrorBarMethodAndVerify("Standard Error of the Mean", MEAN_SEM_BAR_PLOT_SVG_TEXT); + + log("Add a Group By variable and verify aggregate and error bar case."); + chartWizard.clickChartTypeButton().setXSubCategory("Visit").clickApply(); + setBarErrorBarMethodAndVerify("None", MEAN_NONE_GROUPED_BAR_PLOT_SVG_TEXT); + setBarErrorBarMethodAndVerify("Standard Deviation", MEAN_SD_GROUPED_BAR_PLOT_SVG_TEXT); + setBarErrorBarMethodAndVerify("Standard Error of the Mean", MEAN_SEM_GROUPED_BAR_PLOT_SVG_TEXT); + savePlot(BAR_PLOT_SAVE_NAME_4, null); } + private void setBarErrorBarMethodAndVerify(String method, String svgTxt) + { + LookAndFeelBarPlot lookAndFeelDialog = clickChartLayoutButton(); + lookAndFeelDialog.setYAxisErrorBarsMethod(method); + lookAndFeelDialog.clickApply(); + assertSVG(svgTxt); + } + private void setBarAggregateMethodAndVerify(String method, String svgTxt) { clickButton("Chart Type", 0); ChartTypeDialog chartTypeDialog = new ChartTypeDialog(getDriver()); chartTypeDialog.setYAxisAggregateMethod(method).clickApply(); - assertSVG(svgTxt); + if (svgTxt != null) + assertSVG(svgTxt); } } From 5cbea4288b18fa4c97ab21c58a66b547b4206030 Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 17 Oct 2025 09:37:57 -0500 Subject: [PATCH 06/11] BarPlotTest fix for default range min when max is set --- src/org/labkey/test/tests/visualization/BarPlotTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/labkey/test/tests/visualization/BarPlotTest.java b/src/org/labkey/test/tests/visualization/BarPlotTest.java index e6cf769adf..3dacb3153c 100644 --- a/src/org/labkey/test/tests/visualization/BarPlotTest.java +++ b/src/org/labkey/test/tests/visualization/BarPlotTest.java @@ -60,7 +60,7 @@ public class BarPlotTest extends GenericChartsTest private final String ALT_GROUPED_BAR_PLOT_SVG_TEXT = "0\nNormal\nNot Done\n0\n2\n4\n6\n8\n10\n12\n14\n16\n18\n20\n22\nAPX-1: Abbreviated Physical Exam\nNew Label\n0\nNegative"; private final String SECOND_BAR_PLOT_SVG_TEXT = "0\nNegative\n0\n200\n400\n600\n800\n1000\n1200\n1400\n1600\n1800\n2000\n2200\n2400\n" + TRICKY_CHART_TITLE + "\n" + PREG_TEST_RESULTS + "\nSum of " + BP_DIASTOLIC; private final String THIRD_BAR_PLOT_SVG_TEXT = "0\nNegative\n-50\n-49\n-48\n-47\n-46\n-45\n-44\n-43\n-42\n-41\n-40\n"+ TRICKY_CHART_TITLE + "\n" + PREG_TEST_RESULTS + "\nSum of " + BP_DIASTOLIC; - private final String FOURTH_BAR_PLOT_SVG_TEXT = "0\nNegative\n200\n400\n600\n800\n1000\n1200\n1400\n1600\n1800\n2000\n2200\n2400\n2600\n2800\n3000\n"+ TRICKY_CHART_TITLE + "\n" + PREG_TEST_RESULTS + "\nSum of " + BP_DIASTOLIC; + private final String FOURTH_BAR_PLOT_SVG_TEXT = "0\nNegative\n0\n500\n1000\n1500\n2000\n2500\n3000\n"+ TRICKY_CHART_TITLE + "\n" + PREG_TEST_RESULTS + "\nSum of " + BP_DIASTOLIC; private final String SUM_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n2e+7\n4e+7\n6e+7\n8e+7\n1e+8\n1.2e+8\n1.4e+8\n1.6e+8\n1.8e+8\n2e+8\n2.2e+8\n2.4e+8\nTypes\nStudy: Cohort\nSum of Double"; private final String COUNT_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n0\n2\n4\n6\n8\n10\n12\n14\n16\n18\n20\nTypes\nStudy: Cohort\nCount (non-blank) of Double"; private final String MIN_BAR_PLOT_SVG_TEXT = "Group 1\nGroup 2\n-1\n-0.9\n-0.8\n-0.7\n-0.6\n-0.5\n-0.4\n-0.3\n-0.2\n-0.1\n0\nTypes\nStudy: Cohort\nMin of Double"; From 4bcf84542f4411d67c4ddd786aea9d811732fbd4 Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 17 Oct 2025 10:05:06 -0500 Subject: [PATCH 07/11] QueryGrid.showChart to wait for previous chart to be stale --- .../test/components/react/QueryChartDialog.java | 2 +- .../labkey/test/components/ui/grids/QueryGrid.java | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index 5dc350248e..e64fb37e58 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -527,7 +527,7 @@ public String grayTextPreviewInstruction() } private final Locator previewBodyLoc = Locator.tagWithClass("div", "chart-builder-preview-body"); - private final Locator svgLoc = Locator.tagWithClass("div", "svg-chart__chart"); + private final Locator svgLoc = Locator.tagWithClass("div", "svg-chart__chart").childTag("svg"); public WebElement svg() { diff --git a/src/org/labkey/test/components/ui/grids/QueryGrid.java b/src/org/labkey/test/components/ui/grids/QueryGrid.java index 04a477c094..83c65560c6 100644 --- a/src/org/labkey/test/components/ui/grids/QueryGrid.java +++ b/src/org/labkey/test/components/ui/grids/QueryGrid.java @@ -719,7 +719,14 @@ public QueryGrid resetToDefaultState(boolean revertDefaultView) public QueryChartPanel showChart(String chartName) { + // if there was a different chart already shown, wait for it to close first + // NOTE: this will need to be updated soon with the changes for the "multiple chart rendering" feature + WebElement prevChart = hasChartPanel() ? getChartPanel().getSvgChart() : null; + elementCache().chartsMenu.clickSubMenu(false, chartName); + + if (prevChart != null) + getWrapper().shortWait().until(ExpectedConditions.stalenessOf(prevChart)); return getChartPanel(); } @@ -737,6 +744,12 @@ public QueryChartPanel getChartPanel() return new QueryChartPanel.QueryChartPanelFinder(getDriver(), this).waitFor(this); } + public boolean hasChartPanel() + { + QueryChartPanel chartPanel = new QueryChartPanel.QueryChartPanelFinder(getDriver(), this).findOrNull(this); + return chartPanel != null; + } + public WebElement showRReport(String reportName) { elementCache().chartsMenu.clickSubMenu(false, reportName); From 9fd3bdb8e08c2651481c4a660ffa0b6dfab36567 Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 17 Oct 2025 13:18:50 -0500 Subject: [PATCH 08/11] LinePlotTest additions for aggregate method and error bars --- .../test/components/ChartLayoutDialog.java | 10 +++++ .../tests/visualization/LinePlotTest.java | 44 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/src/org/labkey/test/components/ChartLayoutDialog.java b/src/org/labkey/test/components/ChartLayoutDialog.java index 9bba563d17..5a2763e27e 100644 --- a/src/org/labkey/test/components/ChartLayoutDialog.java +++ b/src/org/labkey/test/components/ChartLayoutDialog.java @@ -197,6 +197,11 @@ public ChartLayoutDialog setYAxisAggregateMethod(String method) return this; } + public boolean isYAxisAggregateMethodVisible() + { + return getWrapper().isElementPresent(Ext4Helper.Locators.formItemWithLabel("Aggregate Method:")); + } + public ChartLayoutDialog setYAxisErrorBarsMethod(String method) { clickYAxisTab(); @@ -209,6 +214,11 @@ else if (method.equals("Standard Error of the Mean")) return this; } + public boolean isYAxisErrorBarsMethodVisible() + { + return getWrapper().isElementPresent(Ext4Helper.Locators.formItemWithLabel("Error Bars:")); + } + protected void setLabel(String label) { getWrapper().setFormElement(elementCache().visibleLabelTextBox, label); diff --git a/src/org/labkey/test/tests/visualization/LinePlotTest.java b/src/org/labkey/test/tests/visualization/LinePlotTest.java index 7c0b1dd198..89b3503dfe 100644 --- a/src/org/labkey/test/tests/visualization/LinePlotTest.java +++ b/src/org/labkey/test/tests/visualization/LinePlotTest.java @@ -77,6 +77,7 @@ protected void testPlots() private static final String LINE_PLOT_MV_2 = "60\n70\n80\n90\n100\n110\n32.0\n33.0\n34.0\n35.0\n36.0\n37.0\n38.0\n39.0\n40.0\nTestTitle\nTestXAxis\nTestYAxis"; private static final String LINE_PLOT_MULTI_YAXIS_1 = "60\n80\n100\n120\n140\n160\n180\n200\n10\n20\n30\n40\n50\n60\n70\n80\n90\n100\n110APX-1: Abbreviated Physical Exam\n1. Weight\n4. Pulse, 5. Respirations\n4. Pulse\n5. Respirations"; private static final String LINE_PLOT_MULTI_YAXIS_2 = "60\n80\n100\n120\n140\n160\n180\n200\n60\n65\n70\n75\n80\n85\n90\n95\n100\n105\n110\n115\n6\n8\n10\n12\n14\n16\n18APX-1: Abbreviated Physical Exam\n1. Weight\n4. Pulse\n5. Respirations\n4. Pulse\n5. Respirations"; + private static final String LINE_PLOT_MULTI_YAXIS_3 = "60\n80\n100\n120\n140\n160\n180\n200\n60\n65\n70\n75\n80\n85\n90\n95\n100\n105\n110\n115APX-1: Abbreviated Physical Exam\n1. Weight\n4. Pulse"; private static final String LINE_PLOT_NAME_MV = "ManageViewsLinePlot"; private static final String LINE_PLOT_DESC_MV = "This line plot was created through the manage views UI"; private static final String LINE_PLOT_MULTI_YAXIS_NAME = "LinePlotMultiYAxis"; @@ -199,6 +200,49 @@ private void doMultiYAxisLinePlotTest() waitForElement(Locator.linkWithText(LINE_PLOT_MULTI_YAXIS_NAME)); clickAndWait(Locator.linkWithText(LINE_PLOT_MULTI_YAXIS_NAME), WAIT_FOR_PAGE); export(EXPORTED_SCRIPT_CHECK_TYPE, MEASURE_1_WEIGHT, MEASURE_5_RESPIRATIONS); + + log("verify aggregate and error bar options are hidden for multi chart"); + chartWizard = openSavedPlotInEditMode(LINE_PLOT_MULTI_YAXIS_NAME); + chartLayoutDialog = clickChartLayoutButton(); + chartLayoutDialog.clickYAxisTabRight(); + checker().verifyFalse("Aggregate method should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisAggregateMethodVisible()); + checker().verifyFalse("Error Bars should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisErrorBarsMethodVisible()); + chartLayoutDialog.clickYAxisTabLeft(); + checker().verifyFalse("Aggregate method should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisAggregateMethodVisible()); + checker().verifyFalse("Error Bars should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisErrorBarsMethodVisible()); + chartLayoutDialog.clickCancel(); + log("verify aggregate and error bar options are hidden for right chart"); + chartTypeDialog = chartWizard.clickChartTypeButton(); + chartWizard = chartTypeDialog + .removeYAxis() + .removeYAxis() + .setYAxis(MEASURE_4_PULSE) + .setYAxisSide(0,ChartTypeDialog.YAxisSide.Right) + .clickApply(); + chartLayoutDialog = clickChartLayoutButton(); + click(Locator.xpath("//div[contains(@class, 'item')][text()='Y-Axis']").index(1)); // click the right y-axis tab + checker().verifyFalse("Aggregate method should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisAggregateMethodVisible()); + checker().verifyFalse("Error Bars should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisErrorBarsMethodVisible()); + chartLayoutDialog.clickCancel(); + log("change back to y-axis left and verify aggregate and error bar options"); + chartTypeDialog = chartWizard.clickChartTypeButton(); + chartWizard = chartTypeDialog.setYAxisSide(0, ChartTypeDialog.YAxisSide.Left).clickApply(); + assertSVG(LINE_PLOT_MULTI_YAXIS_3); + checker().verifyEquals("Point count in line plot not as expected", 33, Locator.css("svg g a path").findElements(getDriver()).size()); + chartLayoutDialog = clickChartLayoutButton(); + chartLayoutDialog.clickYAxisTab(); + checker().verifyTrue("Aggregate method should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisAggregateMethodVisible()); + checker().verifyTrue("Error Bars should not be visible for multiple y axis line plot", chartLayoutDialog.isYAxisErrorBarsMethodVisible()); + chartLayoutDialog.setYAxisAggregateMethod("Mean").clickApply(); + assertSVG(LINE_PLOT_MULTI_YAXIS_3); + checker().verifyEquals("Point count in line plot not as expected", 19, Locator.css("svg g a path").findElements(getDriver()).size()); + checker().verifyEquals("Point count in line plot not as expected", 0, Locator.css("svg g.error-bar").findElements(getDriver()).size()); + chartLayoutDialog = clickChartLayoutButton(); + chartLayoutDialog.clickYAxisTab(); + chartLayoutDialog.setYAxisErrorBarsMethod("Standard Deviation").clickApply(); + assertSVG(LINE_PLOT_MULTI_YAXIS_3); + checker().verifyEquals("Point count in line plot not as expected", 19, Locator.css("svg g a path").findElements(getDriver()).size()); + checker().verifyEquals("Point count in line plot not as expected", 19, Locator.css("svg g.error-bar").findElements(getDriver()).size()); } private static final String LINE_PLOT_DR_1 = "60\n65\n70\n75\n80\n85\n90\n50\n55\n60\n65\n70\n75\n80\n85\n90\n95\n100\n105\n110\nAPX-1: Abbreviated Physical Exam\n4. Pulse\n1. Weight"; From b8c343dbeb28dbe2bffd3532ca20f97d4f642515 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 20 Oct 2025 16:49:06 -0500 Subject: [PATCH 09/11] update after merge from develop --- src/org/labkey/test/components/react/QueryChartDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index 4a496c6b13..edd84ccc3d 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -442,13 +442,13 @@ public QueryChartPanel clickCreateChart() */ public QueryChartPanel clickSaveChart() { - WebElement prevChart = _queryGrid.getChartPanel().getSvgChart(); + String name = getName(); + WebElement prevChart = _queryGrid.getChartPanel(name).getSvgChart(); WebDriverWrapper.waitFor(this::isSaveChartButtonEnabled, "the Save chart button did not become enabled", 2000); - String name = getName(); dismiss("Save Chart"); getWrapper().shortWait().until(ExpectedConditions.stalenessOf(prevChart)); - return _queryGrid.getChartPanel(); + return _queryGrid.getChartPanel(name); } /* From cb4fbb0a4e3b21f9ea4280b873e7adc44416f263 Mon Sep 17 00:00:00 2001 From: cnathe Date: Mon, 20 Oct 2025 17:17:33 -0500 Subject: [PATCH 10/11] update after merge from develop --- .../test/components/ui/grids/QueryGrid.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/org/labkey/test/components/ui/grids/QueryGrid.java b/src/org/labkey/test/components/ui/grids/QueryGrid.java index f22ae4809e..8569b1a8c0 100644 --- a/src/org/labkey/test/components/ui/grids/QueryGrid.java +++ b/src/org/labkey/test/components/ui/grids/QueryGrid.java @@ -720,15 +720,8 @@ public QueryGrid resetToDefaultState(boolean revertDefaultView) public QueryChartPanel showChart(String chartName) { - // if there was a different chart already shown, wait for it to close first - // NOTE: this will need to be updated soon with the changes for the "multiple chart rendering" feature - WebElement prevChart = hasChartPanel() ? getChartPanel().getSvgChart() : null; - elementCache().chartsMenu.clickSubMenu(false, chartName); - - if (prevChart != null) - getWrapper().shortWait().until(ExpectedConditions.stalenessOf(prevChart)); - return getChartPanel(); + return getChartPanel(chartName); } public QueryChartDialog createChart() @@ -772,12 +765,6 @@ public QueryChartPanel getChartPanel(String name) return new QueryChartPanel.QueryChartPanelFinder(getDriver(), this, name).waitFor(this); } - public boolean hasChartPanel() - { - QueryChartPanel chartPanel = new QueryChartPanel.QueryChartPanelFinder(getDriver(), this).findOrNull(this); - return chartPanel != null; - } - public WebElement showRReport(String reportName) { elementCache().chartsMenu.clickSubMenu(false, reportName); From e812f0bbe38d56449953c06d9bc91bfb4902fa8a Mon Sep 17 00:00:00 2001 From: cnathe Date: Thu, 23 Oct 2025 08:39:24 -0500 Subject: [PATCH 11/11] clickSaveChart() to account for a rename when finding previous chart to wait for staleness --- src/org/labkey/test/components/react/QueryChartDialog.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/org/labkey/test/components/react/QueryChartDialog.java b/src/org/labkey/test/components/react/QueryChartDialog.java index edd84ccc3d..29edbd878a 100644 --- a/src/org/labkey/test/components/react/QueryChartDialog.java +++ b/src/org/labkey/test/components/react/QueryChartDialog.java @@ -441,9 +441,13 @@ public QueryChartPanel clickCreateChart() appears when dialog is in 'edit' mode */ public QueryChartPanel clickSaveChart() + { + return clickSaveChart(getName()); + } + public QueryChartPanel clickSaveChart(String previousChartName) { String name = getName(); - WebElement prevChart = _queryGrid.getChartPanel(name).getSvgChart(); + WebElement prevChart = _queryGrid.getChartPanel(previousChartName).getSvgChart(); WebDriverWrapper.waitFor(this::isSaveChartButtonEnabled, "the Save chart button did not become enabled", 2000); dismiss("Save Chart");