diff --git a/.circleci/config.yml b/.circleci/config.yml index 7e913d2..c6bf029 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2.1 orbs: node: circleci/node@5.1.0 - browser-tools: circleci/browser-tools@1.4.3 + browser-tools: circleci/browser-tools@1.4.5 executors: java17: diff --git a/pom.xml b/pom.xml index 83eb339..e3768cc 100644 --- a/pom.xml +++ b/pom.xml @@ -161,6 +161,20 @@ true + + + + maven-jar-plugin + + + package + + test-jar + + + + + diff --git a/src/qqq/pages/records/view/RecordView.tsx b/src/qqq/pages/records/view/RecordView.tsx index c9124e2..b7e4727 100644 --- a/src/qqq/pages/records/view/RecordView.tsx +++ b/src/qqq/pages/records/view/RecordView.tsx @@ -193,7 +193,7 @@ function RecordView({table, launchProcess}: Props): JSX.Element { document.removeEventListener("keydown", down) } - }, [dotMenuOpen, keyboardHelpOpen, showEditChildForm, showAudit, metaData]) + }, [dotMenuOpen, keyboardHelpOpen, showEditChildForm, showAudit, metaData, location]) const gotoCreate = () => { diff --git a/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java index 8f3ece1..649d82b 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QBaseSeleniumTest.java @@ -18,7 +18,7 @@ import org.openqa.selenium.chrome.ChromeOptions; *******************************************************************************/ public class QBaseSeleniumTest { - private static ChromeOptions chromeOptions; + protected static ChromeOptions chromeOptions; protected WebDriver driver; protected QSeleniumJavalin qSeleniumJavalin; @@ -52,15 +52,29 @@ public class QBaseSeleniumTest ** *******************************************************************************/ @BeforeEach - void beforeEach() + public void beforeEach() { driver = new ChromeDriver(chromeOptions); driver.manage().window().setSize(new Dimension(1700, 1300)); qSeleniumLib = new QSeleniumLib(driver); - qSeleniumJavalin = new QSeleniumJavalin(); - addJavalinRoutes(qSeleniumJavalin); - qSeleniumJavalin.start(); + if(useInternalJavalin()) + { + qSeleniumJavalin = new QSeleniumJavalin(); + addJavalinRoutes(qSeleniumJavalin); + qSeleniumJavalin.start(); + } + } + + + + /******************************************************************************* + ** control if the test needs to start its own javalin server, or if we're running + ** in an environment where an external web server is being used. + *******************************************************************************/ + protected boolean useInternalJavalin() + { + return (true); } @@ -75,6 +89,8 @@ public class QBaseSeleniumTest .withRouteToFile("/metaData/authentication", "metaData/authentication.json") .withRouteToFile("/metaData/table/person", "metaData/table/person.json") .withRouteToFile("/metaData/table/city", "metaData/table/person.json") + .withRouteToFile("/metaData/table/script", "metaData/table/script.json") + .withRouteToFile("/metaData/table/scriptRevision", "metaData/table/scriptRevision.json") .withRouteToFile("/processes/querySavedFilter/init", "processes/querySavedFilter/init.json"); } diff --git a/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java index 9bbc344..2b28423 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/lib/QSeleniumLib.java @@ -5,6 +5,7 @@ import java.io.File; import java.time.Duration; import java.util.List; import java.util.Objects; +import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -96,6 +97,17 @@ public class QSeleniumLib + /******************************************************************************* + ** Getter for BASE_URL + ** + *******************************************************************************/ + public String getBaseUrl() + { + return BASE_URL; + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -265,6 +277,31 @@ public class QSeleniumLib + /******************************************************************************* + ** + *******************************************************************************/ + public void waitForNumberOfWindowsToBe(int number) + { + LOG.debug("Waiting for number of windows (tabs) to be [" + number + "]"); + long start = System.currentTimeMillis(); + + do + { + if(driver.getWindowHandles().size() == number) + { + LOG.debug("Number of windows (tabs) is [" + number + "]"); + return; + } + + sleepABit(); + } + while(start + (1000 * WAIT_SECONDS) > System.currentTimeMillis()); + + fail("Failed waiting for number of windows (tabs) to be [" + number + "] after [" + WAIT_SECONDS + "] seconds."); + } + + + /******************************************************************************* ** *******************************************************************************/ @@ -293,6 +330,53 @@ public class QSeleniumLib + /******************************************************************************* + ** + *******************************************************************************/ + public void switchToSecondaryTab() + { + String originalWindow = driver.getWindowHandle(); + + waitForNumberOfWindowsToBe(2); + + Set windowHandles = driver.getWindowHandles(); + for(String windowHandle : windowHandles) + { + if(!windowHandle.equals(originalWindow)) + { + driver.switchTo().window(windowHandle); + return; + } + } + + fail("Failed to find a window handle not equal to the original window handle. Original=[" + originalWindow + "]. All=[" + windowHandles + "]"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + public void closeSecondaryTab() + { + String originalWindow = driver.getWindowHandle(); + driver.close(); + + Set windowHandles = driver.getWindowHandles(); + for(String windowHandle : windowHandles) + { + if(!windowHandle.equals(originalWindow)) + { + driver.switchTo().window(windowHandle); + return; + } + } + + fail("Failed to find a window handle not equal to the original window handle. Original=[" + originalWindow + "]. All=[" + windowHandles + "]"); + } + + + @FunctionalInterface public interface Code { diff --git a/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ClickLinkOnRecordThenEditShortcutTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ClickLinkOnRecordThenEditShortcutTest.java new file mode 100755 index 0000000..25ca3c9 --- /dev/null +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ClickLinkOnRecordThenEditShortcutTest.java @@ -0,0 +1,63 @@ +/* + * 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 com.kingsrook.qqq.materialdashboard.lib.QBaseSeleniumTest; +import com.kingsrook.qqq.materialdashboard.lib.javalin.QSeleniumJavalin; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +/******************************************************************************* + ** Test for Associated Record Scripts functionality. + *******************************************************************************/ +public class ClickLinkOnRecordThenEditShortcutTest extends QBaseSeleniumTest +{ + + /******************************************************************************* + ** + *******************************************************************************/ + @Override + protected void addJavalinRoutes(QSeleniumJavalin qSeleniumJavalin) + { + super.addJavalinRoutes(qSeleniumJavalin); + qSeleniumJavalin.withRouteToFile("/data/script/1", "data/script/1.json"); + qSeleniumJavalin.withRouteToFile("/data/scriptRevision/100", "data/scriptRevision/100.json"); + } + + + + /******************************************************************************* + ** + *******************************************************************************/ + @Test + void testClickLinkOnRecordThenEditShortcutTest() + { + qSeleniumLib.gotoAndWaitForBreadcrumbHeader("/developer/script/1", "Hello, Script"); + qSeleniumLib.waitForSelectorContaining("A", "100").click(); + + qSeleniumLib.waitForSelectorContaining("BUTTON", "actions").sendKeys("e"); + assertTrue(qSeleniumLib.driver.getCurrentUrl().endsWith("/scriptRevision/100/edit")); + } + +} diff --git a/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ScriptTableTest.java b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ScriptTableTest.java index 792ba85..c6d1e2b 100755 --- a/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ScriptTableTest.java +++ b/src/test/java/com/kingsrook/qqq/materialdashboard/tests/ScriptTableTest.java @@ -64,8 +64,6 @@ public class ScriptTableTest extends QBaseSeleniumTest qSeleniumLib.waitForSelectorContaining("DIV.ace_line", "var hello;"); qSeleniumLib.waitForSelectorContaining("DIV", "2nd commit"); qSeleniumLib.waitForSelectorContaining("DIV", "Initial checkin"); - - qSeleniumLib.waitForever(); } } diff --git a/src/test/resources/fixtures/data/scriptRevision/100.json b/src/test/resources/fixtures/data/scriptRevision/100.json index 8de0400..955ab34 100644 --- a/src/test/resources/fixtures/data/scriptRevision/100.json +++ b/src/test/resources/fixtures/data/scriptRevision/100.json @@ -1,14 +1,22 @@ { "tableName": "scriptRevision", + "recordLabel": "Hello, Script Revision", "values": { - "id": 100, + "id": "100", + "name": "Hello, Script Revision", + "sequenceNo": "22", "commitMessage": "Initial checkin", "author": "Jon Programmer", "createDate": "2023-02-18T00:47:51Z", "modifyDate": "2023-02-18T00:47:51Z" }, "displayValues": { - + "id": "1", + "name": "Hello, Script Revision", + "scriptId": "1", + "sequenceNo": "22", + "createDate": "2023-02-18T00:47:51Z", + "modifyDate": "2023-02-18T00:47:51Z" }, "associatedRecords": { "files": [ @@ -25,4 +33,4 @@ } ] } -} \ 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 8bfc77d..af09f14 100644 --- a/src/test/resources/fixtures/metaData/index.json +++ b/src/test/resources/fixtures/metaData/index.json @@ -131,7 +131,8 @@ "capabilities": [ "TABLE_COUNT", "TABLE_GET", - "TABLE_QUERY" + "TABLE_QUERY", + "TABLE_UPDATE" ], "readPermission": true, "insertPermission": true, diff --git a/src/test/resources/fixtures/metaData/table/scriptRevision.json b/src/test/resources/fixtures/metaData/table/scriptRevision.json new file mode 100644 index 0000000..78440da --- /dev/null +++ b/src/test/resources/fixtures/metaData/table/scriptRevision.json @@ -0,0 +1,152 @@ +{ + "table": { + "name": "scriptRevision", + "label": "Script Revision", + "isHidden": false, + "primaryKeyField": "id", + "iconName": "history_edu", + "fields": { + "scriptId": { + "name": "scriptId", + "label": "Script", + "type": "INTEGER", + "isRequired": false, + "isEditable": true, + "isHeavy": false, + "possibleValueSourceName": "script", + "displayFormat": "%s", + "adornments": [ + { + "type": "SIZE", + "values": { + "width": "large" + } + }, + { + "type": "LINK", + "values": { + "toRecordFromTable": "script" + } + } + ] + }, + "apiName": { + "name": "apiName", + "label": "API Name", + "type": "STRING", + "isRequired": false, + "isEditable": true, + "isHeavy": false, + "possibleValueSourceName": "apiName", + "displayFormat": "%s" + }, + "sequenceNo": { + "name": "sequenceNo", + "label": "Sequence No", + "type": "INTEGER", + "isRequired": false, + "isEditable": true, + "isHeavy": false, + "displayFormat": "%s" + }, + "apiVersion": { + "name": "apiVersion", + "label": "API Version", + "type": "STRING", + "isRequired": false, + "isEditable": true, + "isHeavy": false, + "possibleValueSourceName": "apiVersion", + "displayFormat": "%s" + }, + "commitMessage": { + "name": "commitMessage", + "label": "Commit Message", + "type": "STRING", + "isRequired": false, + "isEditable": true, + "isHeavy": false, + "displayFormat": "%s" + }, + "modifyDate": { + "name": "modifyDate", + "label": "Modify Date", + "type": "DATE_TIME", + "isRequired": false, + "isEditable": false, + "isHeavy": false, + "displayFormat": "%s" + }, + "author": { + "name": "author", + "label": "Author", + "type": "STRING", + "isRequired": false, + "isEditable": true, + "isHeavy": false, + "displayFormat": "%s" + }, + "id": { + "name": "id", + "label": "Id", + "type": "INTEGER", + "isRequired": false, + "isEditable": false, + "isHeavy": false, + "displayFormat": "%s" + }, + "createDate": { + "name": "createDate", + "label": "Create Date", + "type": "DATE_TIME", + "isRequired": false, + "isEditable": false, + "isHeavy": false, + "displayFormat": "%s" + } + }, + "sections": [ + { + "name": "identity", + "label": "Identity", + "tier": "T1", + "fieldNames": [ + "id", + "scriptId", + "sequenceNo" + ], + "icon": { + "name": "badge" + }, + "isHidden": false + }, + { + "name": "dates", + "label": "Dates", + "tier": "T3", + "fieldNames": [ + "createDate", + "modifyDate" + ], + "icon": { + "name": "calendar_month" + }, + "isHidden": false + } + ], + "exposedJoins": [], + "capabilities": [ + "TABLE_COUNT", + "TABLE_GET", + "TABLE_QUERY", + "TABLE_INSERT", + "TABLE_UPDATE", + "QUERY_STATS" + ], + "readPermission": true, + "insertPermission": true, + "editPermission": true, + "deletePermission": true, + "usesVariants": false + } +}