From 32711098c1c09f8b31ba7c04a60415246fcd6bea Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Fri, 17 Feb 2023 12:03:55 -0600 Subject: [PATCH] new test on audits; selenium upgrade to make usable by team hopefully --- .gitignore | 1 + pom.xml | 12 + .../lib/QBaseSeleniumTest.java | 4 +- .../lib/QQQMaterialDashboardSelectors.java | 2 +- .../lib/QSeleniumLib.java | 87 +++++-- .../lib/javalin/CapturedContext.java | 2 +- .../lib/javalin/CapturingHandler.java | 10 +- .../lib/javalin/QSeleniumJavalin.java | 54 ++-- .../lib/javalin/RouteFromFileHandler.java | 8 +- .../lib/javalin/RouteFromStringHandler.java | 8 +- .../tests/AppPageNavTest.java | 8 +- .../materialdashboard/tests/AuditTest.java | 160 ++++++++++++ .../tests/QueryScreenTest.java | 10 +- .../fixtures/data/audit/query-empty.json | 3 + .../resources/fixtures/data/audit/query.json | 245 ++++++++++++++++++ .../resources/fixtures/data/person/1701.json | 16 ++ .../resources/fixtures/metaData/index.json | 15 ++ src/test/resources/log4j2.xml | 21 ++ 18 files changed, 610 insertions(+), 56 deletions(-) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/QBaseSeleniumTest.java (96%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/QQQMaterialDashboardSelectors.java (92%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/QSeleniumLib.java (79%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/javalin/CapturedContext.java (97%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/javalin/CapturingHandler.java (76%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/javalin/QSeleniumJavalin.java (80%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/javalin/RouteFromFileHandler.java (85%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/lib/javalin/RouteFromStringHandler.java (82%) rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/tests/AppPageNavTest.java (92%) create mode 100755 src/test/java/com/kingsrook/qqq/materialdashboard/tests/AuditTest.java rename src/test/java/com/kingsrook/qqq/{materialdashbaord => materialdashboard}/tests/QueryScreenTest.java (96%) create mode 100644 src/test/resources/fixtures/data/audit/query-empty.json create mode 100644 src/test/resources/fixtures/data/audit/query.json create mode 100644 src/test/resources/fixtures/data/person/1701.json create mode 100644 src/test/resources/log4j2.xml diff --git a/.gitignore b/.gitignore index 367a0b4..be24dee 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ yalc.lock /build /lib /target +/log # misc .DS_Store diff --git a/pom.xml b/pom.xml index 6896f0e..bd435b8 100755 --- a/pom.xml +++ b/pom.xml @@ -94,6 +94,18 @@ 20220924 test + + org.apache.logging.log4j + log4j-api + 2.17.1 + test + + + org.apache.logging.log4j + log4j-core + 2.17.1 + test + diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QBaseSeleniumTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java similarity index 96% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QBaseSeleniumTest.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java index 45b0068..e1965b8 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QBaseSeleniumTest.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java @@ -1,7 +1,7 @@ -package com.kingsrook.qqq.materialdashbaord.lib; +package com.kingsrook.qqq.materialdashboard.lib; -import com.kingsrook.qqq.materialdashbaord.lib.javalin.QSeleniumJavalin; +import com.kingsrook.qqq.materialdashboard.lib.javalin.QSeleniumJavalin; import io.github.bonigarcia.wdm.WebDriverManager; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QQQMaterialDashboardSelectors.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QQQMaterialDashboardSelectors.java similarity index 92% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QQQMaterialDashboardSelectors.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/QQQMaterialDashboardSelectors.java index 8a10812..3fbea4a 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QQQMaterialDashboardSelectors.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QQQMaterialDashboardSelectors.java @@ -1,4 +1,4 @@ -package com.kingsrook.qqq.materialdashbaord.lib; +package com.kingsrook.qqq.materialdashboard.lib; /******************************************************************************* diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QSeleniumLib.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java similarity index 79% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QSeleniumLib.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java index 6958a01..8b86fd4 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/QSeleniumLib.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java @@ -1,4 +1,4 @@ -package com.kingsrook.qqq.materialdashbaord.lib; +package com.kingsrook.qqq.materialdashboard.lib; import java.io.File; @@ -6,6 +6,8 @@ import java.time.Duration; import java.util.List; import java.util.Objects; import org.apache.commons.io.FileUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.openqa.selenium.By; import org.openqa.selenium.OutputType; import org.openqa.selenium.StaleElementReferenceException; @@ -23,6 +25,8 @@ import static org.junit.jupiter.api.Assertions.fail; *******************************************************************************/ public class QSeleniumLib { + Logger LOG = LogManager.getLogger(QSeleniumLib.class); + public final WebDriver driver; private long WAIT_SECONDS = 10; @@ -118,7 +122,7 @@ public class QSeleniumLib { // todo - if env says we're in CIRCLECI, then... just do a hard fail (or just not wait forever?) - System.out.println("Going into a waitForever..."); + LOG.warn("Going into a waitForever..."); new WebDriverWait(driver, Duration.ofHours(1)) .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(".wontEverBePresent"))); } @@ -131,13 +135,11 @@ public class QSeleniumLib public void gotoAndWaitForBreadcrumbHeader(String path, String headerText) { driver.get(BASE_URL + path); - String title = driver.getTitle(); - System.out.println("Page Title: " + title); WebElement header = new WebDriverWait(driver, Duration.ofSeconds(WAIT_SECONDS)) .until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(QQQMaterialDashboardSelectors.BREADCRUMB_HEADER))); - System.out.println("Breadcrumb Header: " + header.getText()); + LOG.debug("Navigated to [" + path + "]. Breadcrumb Header: " + header.getText()); assertEquals(headerText, header.getText()); } @@ -158,7 +160,7 @@ public class QSeleniumLib *******************************************************************************/ public List waitForSelectorAll(String cssSelector, int minCount) { - System.out.println("Waiting for element matching selector [" + cssSelector + "]"); + LOG.debug("Waiting for element matching selector [" + cssSelector + "]"); long start = System.currentTimeMillis(); do @@ -166,7 +168,7 @@ public class QSeleniumLib List elements = driver.findElements(By.cssSelector(cssSelector)); if(elements.size() >= minCount) { - System.out.println("Found [" + elements.size() + "] element(s) matching selector [" + cssSelector + "]"); + LOG.debug("Found [" + elements.size() + "] element(s) matching selector [" + cssSelector + "]"); return (elements); } @@ -180,6 +182,32 @@ public class QSeleniumLib + /******************************************************************************* + ** + *******************************************************************************/ + public void waitForSelectorToNotExist(String cssSelector) + { + LOG.debug("Waiting for non-existence of element matching selector [" + cssSelector + "]"); + long start = System.currentTimeMillis(); + + do + { + List elements = driver.findElements(By.cssSelector(cssSelector)); + if(elements.size() == 0) + { + LOG.debug("Found non-existence of element(s) matching selector [" + cssSelector + "]"); + return; + } + + sleepABit(); + } + while(start + (1000 * WAIT_SECONDS) > System.currentTimeMillis()); + + fail("Failed for non-existence of element matching selector [" + cssSelector + "] after [" + WAIT_SECONDS + "] seconds."); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -205,26 +233,51 @@ public class QSeleniumLib + /******************************************************************************* + ** + *******************************************************************************/ + public boolean waitForCondition(String message, Code c) + { + LOG.debug("Waiting for condition: " + message); + long start = System.currentTimeMillis(); + do + { + Boolean b = c.run(); + if(b != null && b) + { + LOG.debug("Condition became true: " + message); + return (true); + } + + sleepABit(); + } + while(start + (1000 * WAIT_SECONDS) > System.currentTimeMillis()); + LOG.warn("Failed for condition to become true: " + message); + return (false); + } + + + /******************************************************************************* ** *******************************************************************************/ public T waitLoop(String message, Code c) { - System.out.println("Waiting for: " + message); + LOG.debug("Waiting for: " + message); long start = System.currentTimeMillis(); do { T t = c.run(); if(t != null) { - System.out.println("Found: " + message); + LOG.debug("Found: " + message); return (t); } sleepABit(); } while(start + (1000 * WAIT_SECONDS) > System.currentTimeMillis()); - System.out.println("Failed to match while waiting for: " + message); + LOG.warn("Failed to match while waiting for: " + message); return (null); } @@ -235,7 +288,7 @@ public class QSeleniumLib *******************************************************************************/ public WebElement waitForSelectorContaining(String cssSelector, String textContains) { - System.out.println("Waiting for element matching selector [" + cssSelector + "] containing text [" + textContains + "]."); + LOG.debug("Waiting for element matching selector [" + cssSelector + "] containing text [" + textContains + "]."); long start = System.currentTimeMillis(); do @@ -247,7 +300,7 @@ public class QSeleniumLib { if(element.getText() != null && element.getText().toLowerCase().contains(textContains.toLowerCase())) { - System.out.println("Found element matching selector [" + cssSelector + "] containing text [" + textContains + "]."); + LOG.debug("Found element matching selector [" + cssSelector + "] containing text [" + textContains + "]."); Actions actions = new Actions(driver); actions.moveToElement(element); return (element); @@ -255,7 +308,7 @@ public class QSeleniumLib } catch(StaleElementReferenceException sere) { - System.err.println("Caught a StaleElementReferenceException - will retry."); + LOG.debug("Caught a StaleElementReferenceException - will retry."); } } @@ -289,7 +342,7 @@ public class QSeleniumLib } catch(StaleElementReferenceException sere) { - System.err.println("Caught a StaleElementReferenceException - will retry."); + LOG.debug("Caught a StaleElementReferenceException - will retry."); } } return (null); @@ -329,11 +382,11 @@ public class QSeleniumLib destFile.delete(); } FileUtils.moveFile(outputFile, destFile); - System.out.println("Made screenshot at: " + destFile); + LOG.info("Made screenshot at: " + destFile); } catch(Exception e) { - System.err.println("Error taking screenshot to file: " + e.getMessage()); + LOG.warn("Error taking screenshot to file: " + e.getMessage()); } } } @@ -391,7 +444,7 @@ public class QSeleniumLib { if(i < noOfTries - 1) { - System.out.println("On try [" + i + " of " + noOfTries + "] caught: " + e.getMessage()); + LOG.debug("On try [" + i + " of " + noOfTries + "] caught: " + e.getMessage()); } else { diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/CapturedContext.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/CapturedContext.java similarity index 97% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/CapturedContext.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/CapturedContext.java index 1270c95..4a8836d 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/CapturedContext.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/CapturedContext.java @@ -1,4 +1,4 @@ -package com.kingsrook.qqq.materialdashbaord.lib.javalin; +package com.kingsrook.qqq.materialdashboard.lib.javalin; import io.javalin.http.Context; diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/CapturingHandler.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/CapturingHandler.java similarity index 76% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/CapturingHandler.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/CapturingHandler.java index 210fff7..ea0f555 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/CapturingHandler.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/CapturingHandler.java @@ -1,8 +1,10 @@ -package com.kingsrook.qqq.materialdashbaord.lib.javalin; +package com.kingsrook.qqq.materialdashboard.lib.javalin; import io.javalin.http.Context; import io.javalin.http.Handler; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /******************************************************************************* @@ -11,6 +13,8 @@ import io.javalin.http.Handler; *******************************************************************************/ public class CapturingHandler implements Handler { + Logger LOG = LogManager.getLogger(CapturingHandler.class); + private final QSeleniumJavalin qSeleniumJavalin; @@ -34,12 +38,12 @@ public class CapturingHandler implements Handler { if(qSeleniumJavalin.capturing) { - System.out.println("Capturing request for path [" + context.path() + "]"); + LOG.info("Capturing request for path [" + context.path() + "]"); qSeleniumJavalin.captured.add(new CapturedContext(context)); } else { - System.out.println("Not capturing request for path [" + context.path() + "]"); + LOG.trace("Not capturing request for path [" + context.path() + "]"); } } } diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/QSeleniumJavalin.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/QSeleniumJavalin.java similarity index 80% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/QSeleniumJavalin.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/QSeleniumJavalin.java index 6ce9d91..8e81b00 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/QSeleniumJavalin.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/QSeleniumJavalin.java @@ -1,12 +1,14 @@ -package com.kingsrook.qqq.materialdashbaord.lib.javalin; +package com.kingsrook.qqq.materialdashboard.lib.javalin; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.kingsrook.qqq.materialdashbaord.lib.QSeleniumLib; +import com.kingsrook.qqq.materialdashboard.lib.QSeleniumLib; import io.javalin.Javalin; import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConnectionFactory; import static io.javalin.apibuilder.ApiBuilder.get; @@ -19,6 +21,8 @@ import static org.junit.jupiter.api.Assertions.fail; *******************************************************************************/ public class QSeleniumJavalin { + Logger LOG = LogManager.getLogger(QSeleniumJavalin.class); + private long WAIT_SECONDS = 10; private List> routesToFiles; @@ -52,13 +56,13 @@ public class QSeleniumJavalin ** Fluent setter for routeToFile ** *******************************************************************************/ - public QSeleniumJavalin withRouteToFile(String path, String file) + public QSeleniumJavalin withRouteToFile(String path, String fixtureFilePath) { if(this.routesToFiles == null) { this.routesToFiles = new ArrayList<>(); } - this.routesToFiles.add(Pair.of(path, file)); + this.routesToFiles.add(Pair.of(path, fixtureFilePath)); return (this); } @@ -92,7 +96,7 @@ public class QSeleniumJavalin { for(Pair routeToFile : routesToFiles) { - System.out.println("Setting up route for [" + routeToFile.getKey() + "] => [" + routeToFile.getValue() + "]"); + LOG.debug("Setting up route for [" + routeToFile.getKey() + "] => [" + routeToFile.getValue() + "]"); get(routeToFile.getKey(), new RouteFromFileHandler(this, routeToFile)); post(routeToFile.getKey(), new RouteFromFileHandler(this, routeToFile)); } @@ -105,7 +109,7 @@ public class QSeleniumJavalin { for(Pair routeToString : routesToStrings) { - System.out.println("Setting up route for [" + routeToString.getKey() + "] => [" + routeToString.getValue() + "]"); + LOG.debug("Setting up route for [" + routeToString.getKey() + "] => [" + routeToString.getValue() + "]"); get(routeToString.getKey(), new RouteFromStringHandler(this, routeToString)); post(routeToString.getKey(), new RouteFromStringHandler(this, routeToString)); } @@ -115,7 +119,7 @@ public class QSeleniumJavalin javalin.before(new CapturingHandler(this)); javalin.error(404, context -> { - System.out.println("Returning 404 for [" + context.method() + " " + context.path() + "]"); + LOG.warn("Returning 404 for [" + context.method() + " " + context.path() + "]"); pathsThat404ed.add(context.path()); }); @@ -143,21 +147,33 @@ public class QSeleniumJavalin if(javalin != null) { javalin.stop(); + javalin = null; } } + /******************************************************************************* + ** + *******************************************************************************/ + public void restart() + { + stop(); + start(); + } + + + /******************************************************************************* ** *******************************************************************************/ public void report() { - System.out.println("Paths that 404'ed:"); - pathsThat404ed.forEach(s -> System.out.println(" - " + s)); + LOG.info("Paths that 404'ed:"); + pathsThat404ed.forEach(s -> LOG.info(" - " + s)); - System.out.println("Routes served as static files:"); - routeFilesServed.forEach(s -> System.out.println(" - " + s)); + LOG.info("Routes served as static files:"); + routeFilesServed.forEach(s -> LOG.info(" - " + s)); } @@ -167,7 +183,7 @@ public class QSeleniumJavalin *******************************************************************************/ public void beginCapture() { - System.out.println("Beginning to capture requests now"); + LOG.info("Beginning to capture requests now"); capturing = true; captured.clear(); } @@ -179,7 +195,7 @@ public class QSeleniumJavalin *******************************************************************************/ public void endCapture() { - System.out.println("Ending capturing of requests now"); + LOG.info("Ending capturing of requests now"); capturing = false; } @@ -200,17 +216,17 @@ public class QSeleniumJavalin *******************************************************************************/ public CapturedContext waitForCapturedPath(String path) { - System.out.println("Waiting for captured request for path [" + path + "]"); + LOG.debug("Waiting for captured request for path [" + path + "]"); long start = System.currentTimeMillis(); do { - // System.out.println(" captured paths: " + captured.stream().map(CapturedContext::getPath).collect(Collectors.joining(","))); + // LOG.debug(" captured paths: " + captured.stream().map(CapturedContext::getPath).collect(Collectors.joining(","))); for(CapturedContext context : captured) { if(context.getPath().equals(path)) { - System.out.println("Found captured request for path [" + path + "]"); + LOG.debug("Found captured request for path [" + path + "]"); return (context); } } @@ -230,19 +246,19 @@ public class QSeleniumJavalin *******************************************************************************/ public CapturedContext waitForCapturedPathWithBodyContaining(String path, String bodyContaining) { - System.out.println("Waiting for captured request for path [" + path + "] with body containing [" + bodyContaining + "]"); + LOG.debug("Waiting for captured request for path [" + path + "] with body containing [" + bodyContaining + "]"); long start = System.currentTimeMillis(); do { - // System.out.println(" captured paths: " + captured.stream().map(CapturedContext::getPath).collect(Collectors.joining(","))); + // LOG.debug(" captured paths: " + captured.stream().map(CapturedContext::getPath).collect(Collectors.joining(","))); for(CapturedContext context : captured) { if(context.getPath().equals(path)) { if(context.getBody() != null && context.getBody().contains(bodyContaining)) { - System.out.println("Found captured request for path [" + path + "] with body containing [" + bodyContaining + "]"); + LOG.debug("Found captured request for path [" + path + "] with body containing [" + bodyContaining + "]"); return (context); } } diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/RouteFromFileHandler.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/RouteFromFileHandler.java similarity index 85% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/RouteFromFileHandler.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/RouteFromFileHandler.java index 3ebe24d..364664c 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/RouteFromFileHandler.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/RouteFromFileHandler.java @@ -1,4 +1,4 @@ -package com.kingsrook.qqq.materialdashbaord.lib.javalin; +package com.kingsrook.qqq.materialdashboard.lib.javalin; import java.nio.charset.StandardCharsets; @@ -7,6 +7,8 @@ import io.javalin.http.Context; import io.javalin.http.Handler; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /******************************************************************************* @@ -14,6 +16,8 @@ import org.apache.commons.lang3.tuple.Pair; *******************************************************************************/ public class RouteFromFileHandler implements Handler { + Logger LOG = LogManager.getLogger(RouteFromFileHandler.class); + private final String route; private final String filePath; private final QSeleniumJavalin qSeleniumJavalin; @@ -42,7 +46,7 @@ public class RouteFromFileHandler implements Handler try { qSeleniumJavalin.routeFilesServed.add(this.route); - System.out.println("Serving route [" + this.route + "] via file [" + this.filePath + "]"); + LOG.debug("Serving route [" + this.route + "] via file [" + this.filePath + "]"); List lines = IOUtils.readLines(getClass().getResourceAsStream("/fixtures/" + this.filePath), StandardCharsets.UTF_8); context.result(String.join("\n", lines)); } diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/RouteFromStringHandler.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/RouteFromStringHandler.java similarity index 82% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/RouteFromStringHandler.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/RouteFromStringHandler.java index 30f8a01..3dc7e93 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/lib/javalin/RouteFromStringHandler.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/javalin/RouteFromStringHandler.java @@ -1,9 +1,11 @@ -package com.kingsrook.qqq.materialdashbaord.lib.javalin; +package com.kingsrook.qqq.materialdashboard.lib.javalin; import io.javalin.http.Context; import io.javalin.http.Handler; import org.apache.commons.lang3.tuple.Pair; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; /******************************************************************************* @@ -11,6 +13,8 @@ import org.apache.commons.lang3.tuple.Pair; *******************************************************************************/ public class RouteFromStringHandler implements Handler { + Logger LOG = LogManager.getLogger(RouteFromStringHandler.class); + private final String route; private final String responseString; private final QSeleniumJavalin qSeleniumJavalin; @@ -37,7 +41,7 @@ public class RouteFromStringHandler implements Handler public void handle(Context context) { qSeleniumJavalin.routeFilesServed.add(this.route); - System.out.println("Serving route [" + this.route + "] via static String"); + LOG.debug("Serving route [" + this.route + "] via static String"); context.result(this.responseString); } } diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/tests/AppPageNavTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/AppPageNavTest.java similarity index 92% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/tests/AppPageNavTest.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/tests/AppPageNavTest.java index be6fb2d..2660a02 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/tests/AppPageNavTest.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/AppPageNavTest.java @@ -19,12 +19,12 @@ * along with this program. If not, see . */ -package com.kingsrook.qqq.materialdashbaord.tests; +package com.kingsrook.qqq.materialdashboard.tests; -import com.kingsrook.qqq.materialdashbaord.lib.QBaseSeleniumTest; -import com.kingsrook.qqq.materialdashbaord.lib.QQQMaterialDashboardSelectors; -import com.kingsrook.qqq.materialdashbaord.lib.javalin.QSeleniumJavalin; +import com.kingsrook.qqq.materialdashboard.lib.QBaseSeleniumTest; +import com.kingsrook.qqq.materialdashboard.lib.QQQMaterialDashboardSelectors; +import com.kingsrook.qqq.materialdashboard.lib.javalin.QSeleniumJavalin; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/kingsrook/qqq/materialdashboard/tests/AuditTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/AuditTest.java new file mode 100755 index 0000000..45b2616 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/AuditTest.java @@ -0,0 +1,160 @@ +/* + * QQQ - Low-code Application Framework for Engineers. + * Copyright (C) 2021-2022. Kingsrook, LLC + * 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States + * contact@kingsrook.com + * https://github.com/Kingsrook/ + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package com.kingsrook.qqq.materialdashboard.tests; + + +import java.util.List; +import com.kingsrook.qqq.materialdashboard.lib.QBaseSeleniumTest; +import com.kingsrook.qqq.materialdashboard.lib.javalin.CapturedContext; +import com.kingsrook.qqq.materialdashboard.lib.javalin.QSeleniumJavalin; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.WebElement; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + + +/******************************************************************************* + ** Test for the audit screen (e.g., modal) + *******************************************************************************/ +public class AuditTest extends QBaseSeleniumTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + protected void addJavalinRoutes(QSeleniumJavalin qSeleniumJavalin) + { + super.addJavalinRoutes(qSeleniumJavalin); + qSeleniumJavalin + .withRouteToFile("/data/person/1701", "data/person/1701.json"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testOpenAuditsFromRecordWithNoAuditsFoundThenClose() + { + ///////////////////////////////////////////////////////////////////// + // setup route for empty audits - then assert we show such message // + ///////////////////////////////////////////////////////////////////// + qSeleniumJavalin.withRouteToFile("/data/audit/query", "data/audit/query-empty.json"); + qSeleniumJavalin.restart(); + + qSeleniumLib.gotoAndWaitForBreadcrumbHeader("/peopleApp/greetingsApp/person/1701", "John Doe"); + + qSeleniumLib.waitForSelectorContaining("BUTTON", "Actions").click(); + qSeleniumLib.waitForSelectorContaining("LI", "Audit").click(); + qSeleniumLib.waitForSelector(".audit"); + qSeleniumLib.waitForSelectorContaining("DIV", "Audit for Person: John Doe"); + qSeleniumLib.waitForSelectorContaining("DIV", "No audits were found for this record"); + + /////////////////////////////////////// + // make sure we can close the dialog // + /////////////////////////////////////// + qSeleniumLib.waitForSelectorContaining("BUTTON", "Close").click(); + qSeleniumLib.waitForSelectorToNotExist(".audit"); + + qSeleniumLib.takeScreenshotToFile(); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testOpenAuditsFromRecordWithSomeAuditsFound() + { + String auditQueryPath = "/data/audit/query"; + qSeleniumJavalin.withRouteToFile(auditQueryPath, "data/audit/query.json"); + qSeleniumJavalin.restart(); + + qSeleniumLib.gotoAndWaitForBreadcrumbHeader("/peopleApp/greetingsApp/person/1701", "John Doe"); + + qSeleniumLib.waitForSelectorContaining("BUTTON", "Actions").click(); + qSeleniumLib.waitForSelectorContaining("LI", "Audit").click(); + qSeleniumLib.waitForSelectorContaining("DIV", "Audit for Person: John Doe"); + qSeleniumLib.waitForSelectorContaining("DIV", "Showing all 5 audits for this record"); + + ////////////////////////////////////////////////////////////////////////////////////////////////// + // assertions about the different styles of detail messages (set a value, cleared a value, etc) // + ////////////////////////////////////////////////////////////////////////////////////////////////// + qSeleniumLib.waitForSelectorContaining("LI", "First Name: Set to John"); + qSeleniumLib.waitForSelectorContaining("B", "John"); + qSeleniumLib.waitForSelectorContaining("LI", "Last Name: Removed value Doe"); + qSeleniumLib.waitForSelectorContaining("LI", "clientId: Changed from BetaMax to ACME"); + qSeleniumLib.waitForSelectorContaining("B", "ACME"); + qSeleniumLib.waitForSelectorContaining("DIV", "Audit message here"); + qSeleniumLib.waitForSelectorContaining("LI", "This is a detail message"); + } + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testOpenAuditsFromRecordReSortList() + { + String auditQueryPath = "/data/audit/query"; + qSeleniumJavalin.withRouteToFile(auditQueryPath, "data/audit/query.json"); + qSeleniumJavalin.restart(); + + qSeleniumLib.gotoAndWaitForBreadcrumbHeader("/peopleApp/greetingsApp/person/1701", "John Doe"); + + qSeleniumLib.waitForSelectorContaining("BUTTON", "Actions").click(); + qSeleniumLib.waitForSelectorContaining("LI", "Audit").click(); + qSeleniumLib.waitForSelectorContaining("DIV", "Audit for Person: John Doe"); + + ///////////////////////////////////////////////////////////////////////////////////////// + // make sure clicking the re-sort buttons works (fires a new request w/ opposite sort) // + ///////////////////////////////////////////////////////////////////////////////////////// + qSeleniumJavalin.beginCapture(); + WebElement sortAscButton = qSeleniumLib.waitForSelectorContaining("BUTTON", "arrow_upward"); + assertEquals("false", sortAscButton.getAttribute("aria-pressed")); + sortAscButton.click(); + qSeleniumJavalin.waitForCapturedPath(auditQueryPath); + qSeleniumJavalin.endCapture(); + List captured = qSeleniumJavalin.getCaptured(); + captured = captured.stream().filter(cc -> cc.getPath().equals(auditQueryPath)).toList(); + assertEquals(1, captured.size()); + assertThat(captured.get(0).getBody()).contains("\"isAscending\":true"); + + sortAscButton = qSeleniumLib.waitForSelectorContaining("BUTTON", "arrow_upward"); + assertEquals("true", sortAscButton.getAttribute("aria-pressed")); + + qSeleniumJavalin.beginCapture(); + qSeleniumLib.waitForSelectorContaining("BUTTON", "arrow_downward").click(); + qSeleniumJavalin.waitForCapturedPath(auditQueryPath); + qSeleniumJavalin.endCapture(); + captured = qSeleniumJavalin.getCaptured(); + captured = captured.stream().filter(cc -> cc.getPath().equals(auditQueryPath)).toList(); + assertEquals(1, captured.size()); + assertThat(captured.get(0).getBody()).contains("\"isAscending\":false"); + + qSeleniumLib.takeScreenshotToFile(); + } + +} diff --git a/src/test/java/com/kingsrook/qqq/materialdashbaord/tests/QueryScreenTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/QueryScreenTest.java similarity index 96% rename from src/test/java/com/kingsrook/qqq/materialdashbaord/tests/QueryScreenTest.java rename to src/test/java/com/kingsrook/qqq/materialdashboard/tests/QueryScreenTest.java index fb64dde..bd182c1 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashbaord/tests/QueryScreenTest.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/QueryScreenTest.java @@ -19,13 +19,13 @@ * along with this program. If not, see . */ -package com.kingsrook.qqq.materialdashbaord.tests; +package com.kingsrook.qqq.materialdashboard.tests; -import com.kingsrook.qqq.materialdashbaord.lib.QBaseSeleniumTest; -import com.kingsrook.qqq.materialdashbaord.lib.QQQMaterialDashboardSelectors; -import com.kingsrook.qqq.materialdashbaord.lib.javalin.CapturedContext; -import com.kingsrook.qqq.materialdashbaord.lib.javalin.QSeleniumJavalin; +import com.kingsrook.qqq.materialdashboard.lib.QBaseSeleniumTest; +import com.kingsrook.qqq.materialdashboard.lib.QQQMaterialDashboardSelectors; +import com.kingsrook.qqq.materialdashboard.lib.javalin.CapturedContext; +import com.kingsrook.qqq.materialdashboard.lib.javalin.QSeleniumJavalin; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; diff --git a/src/test/resources/fixtures/data/audit/query-empty.json b/src/test/resources/fixtures/data/audit/query-empty.json new file mode 100644 index 0000000..efde9b0 --- /dev/null +++ b/src/test/resources/fixtures/data/audit/query-empty.json @@ -0,0 +1,3 @@ +{ + "records": [] +} diff --git a/src/test/resources/fixtures/data/audit/query.json b/src/test/resources/fixtures/data/audit/query.json new file mode 100644 index 0000000..f40206f --- /dev/null +++ b/src/test/resources/fixtures/data/audit/query.json @@ -0,0 +1,245 @@ +{ + "records": [ + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 623577, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Inserted", + "timestamp": "2023-02-17T14:11:16Z", + "clientId": 107, + "auditDetail.id": 278660, + "auditDetail.auditId": 623577, + "auditDetail.message": "Set First Name to John", + "auditDetail.fieldName": "firstName", + "auditDetail.newValue": "John" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "623577", + "recordId": "1191682", + "message": "Record was Inserted", + "timestamp": "2023-02-17T14:11:16Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 623577, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Inserted", + "timestamp": "2023-02-17T14:11:16Z", + "clientId": 107, + "auditDetail.id": 278661, + "auditDetail.auditId": 623577, + "auditDetail.message": "Removed Doe from Last Name", + "auditDetail.fieldName": "lastName", + "auditDetail.oldValue": "Doe" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "623577", + "recordId": "1191682", + "message": "Record was Inserted", + "timestamp": "2023-02-17T14:11:16Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 623577, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Inserted", + "timestamp": "2023-02-17T14:11:16Z", + "clientId": 107, + "auditDetail.id": 278662, + "auditDetail.auditId": 623577, + "auditDetail.message": "Set Client to ACME", + "auditDetail.fieldName": "clientId", + "auditDetail.oldValue": "BetaMax", + "auditDetail.newValue": "ACME" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "623577", + "recordId": "1191682", + "message": "Record was Inserted", + "timestamp": "2023-02-17T14:11:16Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 624804, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Edited", + "timestamp": "2023-02-17T14:13:16Z", + "clientId": 107, + "auditDetail.id": 278990, + "auditDetail.auditId": 624804, + "auditDetail.message": "Set SLA Expected Service Days to 2", + "auditDetail.fieldName": "slaExpectedServiceDays", + "auditDetail.newValue": "2" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "624804", + "recordId": "1191682", + "message": "Record was Edited", + "timestamp": "2023-02-17T14:13:16Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 624804, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Edited", + "timestamp": "2023-02-17T14:13:16Z", + "clientId": 107, + "auditDetail.id": 278991, + "auditDetail.auditId": 624804, + "auditDetail.message": "Set SLA Status to \"Pending\"", + "auditDetail.fieldName": "slaStatusId", + "auditDetail.newValue": "Pending" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "624804", + "recordId": "1191682", + "message": "Record was Edited", + "timestamp": "2023-02-17T14:13:16Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 624809, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Audit message here", + "timestamp": "2023-02-17T14:13:16Z", + "clientId": 107, + "auditDetail.id": 279000, + "auditDetail.auditId": 624809, + "auditDetail.message": "This is a detail message" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "624809", + "recordId": "1191682", + "message": "Audit message here", + "timestamp": "2023-02-17T14:13:16Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 737694, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Edited", + "timestamp": "2023-02-17T17:22:08Z", + "clientId": 107, + "auditDetail.id": 299222, + "auditDetail.auditId": 737694, + "auditDetail.message": "Set Estimated Delivery Date Time to 2023-02-18 07:00:00 PM EST", + "auditDetail.fieldName": "estimatedDeliveryDateTime", + "auditDetail.newValue": "2023-02-18 07:00:00 PM EST" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "737694", + "recordId": "1191682", + "message": "Record was Edited", + "timestamp": "2023-02-17T17:22:08Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 737694, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Record was Edited", + "timestamp": "2023-02-17T17:22:08Z", + "clientId": 107, + "auditDetail.id": 299223, + "auditDetail.auditId": 737694, + "auditDetail.message": "Changed Parcel Tracking Status from \"Unknown\" to \"Pre Transit\"", + "auditDetail.fieldName": "parcelTrackingStatusId", + "auditDetail.oldValue": "Unknown", + "auditDetail.newValue": "Pre Transit" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "737694", + "recordId": "1191682", + "message": "Record was Edited", + "timestamp": "2023-02-17T17:22:08Z" + } + }, + { + "tableName": "audit", + "recordLabel": "Parcel 1191682", + "values": { + "id": 737695, + "auditTableId": 4, + "auditUserId": 2, + "recordId": 1191682, + "message": "Updating Parcel based on updated tracking details", + "timestamp": "2023-02-17T17:22:09Z", + "clientId": 107, + "auditDetail.id": 299224, + "auditDetail.auditId": 737695, + "auditDetail.message": "Set Parcel Tracking Status to Pre Transit based on most recent tracking update: Shipment information sent to FedEx" + }, + "displayValues": { + "auditTableId": "Parcel", + "auditUserId": "QQQ User", + "clientId": "ACME", + "id": "737695", + "recordId": "1191682", + "message": "Updating Parcel based on updated tracking details", + "timestamp": "2023-02-17T17:22:09Z" + } + } + ] +} \ No newline at end of file diff --git a/src/test/resources/fixtures/data/person/1701.json b/src/test/resources/fixtures/data/person/1701.json new file mode 100644 index 0000000..54ceece --- /dev/null +++ b/src/test/resources/fixtures/data/person/1701.json @@ -0,0 +1,16 @@ +{ + "tableName": "person", + "recordLabel": "John Doe", + "values": { + "name": "John Doe", + "id": 1710, + "createDate": "2022-08-30T00:31:00Z", + "modifyDate": "2022-08-30T00:31:00Z" + }, + "displayValues": { + "name": "John Doe", + "id": 1710, + "createDate": "2022-08-30T00:31:00Z", + "modifyDate": "2022-08-30T00:31:00Z" + } +} \ No newline at end of file diff --git a/src/test/resources/fixtures/metaData/index.json b/src/test/resources/fixtures/metaData/index.json index 947343b..1968683 100644 --- a/src/test/resources/fixtures/metaData/index.json +++ b/src/test/resources/fixtures/metaData/index.json @@ -53,6 +53,21 @@ "TABLE_INSERT", "TABLE_DELETE" ] + }, + "audit": { + "name": "audit", + "label": "Audits", + "isHidden": true, + "iconName": "location_city", + "deletePermission": false, + "editPermission": false, + "insertPermission": false, + "readPermission": true, + "capabilities": [ + "TABLE_COUNT", + "TABLE_GET", + "TABLE_QUERY" + ] } }, "processes": { diff --git a/src/test/resources/log4j2.xml b/src/test/resources/log4j2.xml new file mode 100644 index 0000000..870d61f --- /dev/null +++ b/src/test/resources/log4j2.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +