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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+