diff --git a/src/org/labkey/test/WebDriverWrapper.java b/src/org/labkey/test/WebDriverWrapper.java index 858a67b383..7d1d4b6e63 100644 --- a/src/org/labkey/test/WebDriverWrapper.java +++ b/src/org/labkey/test/WebDriverWrapper.java @@ -3709,6 +3709,9 @@ private void setHtml5Input(WebElement input, String inputType, String value) case "date": setHtml5DateInput(input, value); break; + case "datetime-local": + setHtml5DateTimeInput(input, value); + break; case "password": case "search": setInput(input, value); // These don't require special handling, don't output warning @@ -3737,6 +3740,21 @@ private void setHtml5DateInput(WebElement el, String text) } } + private void setHtml5DateTimeInput(WebElement el, String text) + { + String inputFormat = "yyyy-MM-dd'T'HH:mm"; + SimpleDateFormat inputFormatter = new SimpleDateFormat(inputFormat); + + try + { + setHtml5DateTimeInput(el, inputFormatter.parse(text)); + } + catch (ParseException e) + { + throw new IllegalArgumentException("Unable to parse date " + text + ". Format should be " + inputFormat); + } + } + private void setHtml5DateInput(WebElement el, Date date) { // Firefox requires ISO date format (yyyy-MM-dd) @@ -3749,6 +3767,18 @@ private void setHtml5DateInput(WebElement el, Date date) el.sendKeys(formDate); } + private void setHtml5DateTimeInput(WebElement el, Date date) + { + // Firefox and Chrome want different formats, neither of which align with all online guidance to use ISO-style + String formFormat = isFirefox() ? "MMddyyyy hh:mm a" : "MM-dd-yyyy'\t'hh:mma"; + SimpleDateFormat formFormatter = new SimpleDateFormat(formFormat); + String formDate = formFormatter.format(date); + + fireEvent(el, SeleniumEvent.focus); + executeScript("arguments[0].value = ''", el); + el.sendKeys(formDate); + } + private void setHtml5NumberInput(WebElement el, String text) { diff --git a/src/org/labkey/test/components/react/QueryChartPanel.java b/src/org/labkey/test/components/react/QueryChartPanel.java index 9ba0135e58..4aa22782cf 100644 --- a/src/org/labkey/test/components/react/QueryChartPanel.java +++ b/src/org/labkey/test/components/react/QueryChartPanel.java @@ -3,8 +3,8 @@ import org.labkey.test.Locator; import org.labkey.test.components.Component; import org.labkey.test.components.WebDriverComponent; -import org.labkey.test.components.html.BootstrapMenu; import org.labkey.test.components.ui.grids.QueryGrid; +import org.labkey.test.components.ui.grids.ResponsiveGrid; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; @@ -38,11 +38,7 @@ public QueryChartDialog clickEdit() public File clickExport(String subMenuText) { - elementCache().exportMenu.expand(); - return getWrapper().doAndWaitForDownload(() -> - Locator.tagWithClass("li", "lk-menu-item") - .descendant(Locator.tagContainingText("a", subMenuText)) - .findElement(elementCache().headingEl).click()); + return getWrapper().doAndWaitForDownload(() -> elementCache().exportMenu.doMenuAction(subMenuText)); } public String getTitle() @@ -55,13 +51,27 @@ public WebElement getSvgChart() return Locator.byClass("svg-chart__chart").childTag("svg").waitForElement(this, WAIT_FOR_JAVASCRIPT); } - public QueryGrid clickClose() + public ResponsiveGrid getCurveStatsGrid() + { + return new ResponsiveGrid.ResponsiveGridFinder(getDriver()).waitFor(elementCache().curveStatsPanel); + } + + public boolean isCurveStatsPanelPresent() + { + return ElementCache.curveStatsPanelLoc.findOptionalElement(this).isPresent(); + } + + public File exportCurveStats(String type) + { + return getWrapper().doAndWaitForDownload(() -> elementCache().exportStatsMenu.doMenuAction(type)); + } + + public void clickClose() { var btn = elementCache().closeButton; getWrapper().shortWait().until(ExpectedConditions.elementToBeClickable(btn)); btn.click(); getWrapper().shortWait().until(ExpectedConditions.stalenessOf(btn)); - return _queryGrid; } @Override @@ -88,11 +98,17 @@ protected class ElementCache extends Component.ElementCache .findWhenNeeded(this).withTimeout(2000); public final WebElement editButton = Locator.tagWithAttribute("button", "title", "Edit chart") .findWhenNeeded(headingEl); - public final BootstrapMenu exportMenu = new MultiMenu.MultiMenuFinder(getDriver()).withButtonClass("chart-panel-export-btn").findWhenNeeded(headingEl); + public final MultiMenu exportMenu = new MultiMenu.MultiMenuFinder(getDriver()) + .withButtonClass("chart-panel-export-btn") + .findWhenNeeded(headingEl); public final WebElement closeButton = Locator.tagWithAttribute("button", "title", "Hide chart") .findWhenNeeded(headingEl); public final WebElement titleElement= Locator.tagWithClass("div", "chart-panel__heading-title") .findWhenNeeded(headingEl); + public static final Locator curveStatsPanelLoc = Locator.byClass("curve-fit-statistics"); + public final WebElement curveStatsPanel = curveStatsPanelLoc.findWhenNeeded(this).withTimeout(WAIT_FOR_JAVASCRIPT); + public final WebElement curveStatsHeader = Locator.byClass("curve-fit-statistics__header").findWhenNeeded(curveStatsPanel); + public final MultiMenu exportStatsMenu = new MultiMenu.MultiMenuFinder(getDriver()).findWhenNeeded(curveStatsHeader); } diff --git a/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java b/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java index e8bfad7634..199f30c04e 100644 --- a/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java +++ b/src/org/labkey/test/components/ui/grids/ResponsiveGrid.java @@ -995,6 +995,12 @@ public ResponsiveGridFinder inParentWithId(String id) return this; } + public ResponsiveGridFinder inParentWithClass(String className) + { + _locator = Locator.byClass(className).child(Locators.responsiveGrid()); + return this; + } + public ResponsiveGridFinder withGridId(String id) { _locator = Locators.responsiveGrid(id); diff --git a/src/org/labkey/test/pages/core/admin/ShowAdminPage.java b/src/org/labkey/test/pages/core/admin/ShowAdminPage.java index 0df5e6ea13..7f448e18b6 100644 --- a/src/org/labkey/test/pages/core/admin/ShowAdminPage.java +++ b/src/org/labkey/test/pages/core/admin/ShowAdminPage.java @@ -251,6 +251,11 @@ public void clickPostgresLocks() clickSettingsLink("postgres locks"); } + public void clickPostgresTableSizes() + { + clickSettingsLink("postgres table sizes"); + } + public List getAllAdminConsoleLinks() { goToSettingsSection(); diff --git a/src/org/labkey/test/tests/PostgresQueriesTest.java b/src/org/labkey/test/tests/PostgresQueriesTest.java index dc1838e43b..bce53b2f03 100644 --- a/src/org/labkey/test/tests/PostgresQueriesTest.java +++ b/src/org/labkey/test/tests/PostgresQueriesTest.java @@ -66,6 +66,9 @@ public void testQueries() throws IOException, CommandException goToAdminConsole().clickPostgresLocks(); verifyLocksGrid(); + // Verify locks grid as site admin + goToAdminConsole().clickPostgresTableSizes(); + verifyTableSizesGrid(); // Verify project admin gets a 401 for locks grid pushLocation(); @@ -150,6 +153,17 @@ private void verifyLocksGrid() Assertions.assertThat(cols).as("pg_locks columns").contains("Locktype", "Virtualtransaction"); } + private void verifyTableSizesGrid() + { + assertTextPresent("pg_tablesizes"); + DataRegionTable table = new DataRegionTable("query", this); + List cols = table.getColumnLabels(); + Assertions.assertThat(cols).as("pg_tablesizes columns").contains("Table Schema", "Table Name", "Table Size", "Index Size", "Total Size"); + // Check a couple of expected tables + table.setFilter("table_schema", "Equals", "audit"); + assertTextPresent("queryupdateauditdomain", "userauditdomain"); + } + private void verifyActivityGrid(boolean expectDelete) { assertTextPresent("pg_stat_activity");