mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 12:50:43 +00:00
new test on audits; selenium upgrade to make usable by team hopefully
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -18,6 +18,7 @@ yalc.lock
|
||||
/build
|
||||
/lib
|
||||
/target
|
||||
/log
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
12
pom.xml
12
pom.xml
@ -94,6 +94,18 @@
|
||||
<version>20220924</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -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;
|
@ -1,4 +1,4 @@
|
||||
package com.kingsrook.qqq.materialdashbaord.lib;
|
||||
package com.kingsrook.qqq.materialdashboard.lib;
|
||||
|
||||
|
||||
/*******************************************************************************
|
@ -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<WebElement> 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<WebElement> 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<WebElement> 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<Boolean> 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> T waitLoop(String message, Code<T> 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
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
package com.kingsrook.qqq.materialdashbaord.lib.javalin;
|
||||
package com.kingsrook.qqq.materialdashboard.lib.javalin;
|
||||
|
||||
|
||||
import io.javalin.http.Context;
|
@ -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() + "]");
|
||||
}
|
||||
}
|
||||
}
|
@ -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<Pair<String, String>> 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<String, String> 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<String, String> 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);
|
||||
}
|
||||
}
|
@ -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<String> lines = IOUtils.readLines(getClass().getResourceAsStream("/fixtures/" + this.filePath), StandardCharsets.UTF_8);
|
||||
context.result(String.join("\n", lines));
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -19,12 +19,12 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
|
160
src/test/java/com/kingsrook/qqq/materialdashboard/tests/AuditTest.java
Executable file
160
src/test/java/com/kingsrook/qqq/materialdashboard/tests/AuditTest.java
Executable file
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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<CapturedContext> 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();
|
||||
}
|
||||
|
||||
}
|
@ -19,13 +19,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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;
|
3
src/test/resources/fixtures/data/audit/query-empty.json
Normal file
3
src/test/resources/fixtures/data/audit/query-empty.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"records": []
|
||||
}
|
245
src/test/resources/fixtures/data/audit/query.json
Normal file
245
src/test/resources/fixtures/data/audit/query.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
16
src/test/resources/fixtures/data/person/1701.json
Normal file
16
src/test/resources/fixtures/data/person/1701.json
Normal file
@ -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"
|
||||
}
|
||||
}
|
@ -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": {
|
||||
|
21
src/test/resources/log4j2.xml
Normal file
21
src/test/resources/log4j2.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration>
|
||||
<Appenders>
|
||||
<Console name="SystemOutAppender" target="SYSTEM_OUT">
|
||||
<LevelRangeFilter minLevel="ERROR" maxLevel="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="%highlight{%date{ISO8601} | %level | %threadName | %logger{1} | %message%n}"/>
|
||||
</Console>
|
||||
<File name="LogFileAppender" fileName="log/qqq.log">
|
||||
<LevelRangeFilter minLevel="ERROR" maxLevel="all" onMatch="ACCEPT" onMismatch="DENY"/>
|
||||
<PatternLayout pattern="%date{ISO8601} | %relative | %level | %threadName | %logger{1} | %message%n"/>
|
||||
</File>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<Logger name="org.apache.log4j.xml" additivity="false">
|
||||
</Logger>
|
||||
<Root level="all">
|
||||
<AppenderRef ref="SystemOutAppender"/>
|
||||
<!-- <AppenderRef ref="LogFileAppender"/> -->
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
Reference in New Issue
Block a user