├── server ├── .eslintignore ├── index.js ├── src │ ├── index.ts │ ├── public │ │ ├── favicon.ico │ │ ├── img │ │ │ ├── loader-circle.png │ │ │ └── tricolon.svg │ │ ├── webfonts │ │ │ ├── fa-solid-900.eot │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-brands-400.eot │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff │ │ │ ├── fa-regular-400.eot │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-solid-900.woff │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.woff │ │ │ └── fa-regular-400.woff2 │ │ └── css │ │ │ └── session.css │ ├── start.ts │ ├── test │ │ ├── repo │ │ │ └── tests │ │ │ │ └── Dummy.yaml │ │ └── unit │ │ │ └── helpers.test.ts │ ├── lib │ │ ├── express-session.ts │ │ ├── build-info.ts │ │ ├── db-manager.ts │ │ ├── constants.ts │ │ ├── log-manager.ts │ │ ├── file-walker.ts │ │ ├── dirs.ts │ │ └── websocket-notifier.ts │ └── controllers │ │ └── ui.ts ├── bin │ └── opentest-server.js ├── .eslintrc ├── .gitlab-ci.yml ├── README.md ├── tsconfig.json ├── .npmignore ├── .vscode │ ├── settings.json │ └── launch.json ├── .gitignore └── server.sample.yaml ├── actor ├── actor │ ├── src │ │ └── main │ │ │ ├── resources │ │ │ └── run.bat │ │ │ ├── README.md │ │ │ └── assembly │ │ │ └── maven-assembly.xml │ └── .gitignore ├── selenium │ ├── src │ │ ├── main │ │ │ └── java │ │ │ │ └── org │ │ │ │ └── getopentest │ │ │ │ └── selenium │ │ │ │ ├── HandleAlert.java │ │ │ │ ├── ReadCurrentUrl.java │ │ │ │ ├── ActionsMoveToElement.java │ │ │ │ ├── CloseWindow.java │ │ │ │ ├── NavigateBack.java │ │ │ │ ├── NavigateForward.java │ │ │ │ ├── CloseBrowser.java │ │ │ │ ├── ReadPageSource.java │ │ │ │ ├── ActionsPause.java │ │ │ │ ├── TakeScreenshot.java │ │ │ │ ├── NavigateTo.java │ │ │ │ ├── ActionsMoveByOffset.java │ │ │ │ ├── ReadElementCount.java │ │ │ │ ├── SwitchToDefaultContent.java │ │ │ │ ├── ActionsPerform.java │ │ │ │ ├── ReadPageTitle.java │ │ │ │ ├── ReadCookie.java │ │ │ │ ├── ReadCssProperty.java │ │ │ │ ├── ActionsRelease.java │ │ │ │ ├── GetActiveElement.java │ │ │ │ ├── AssertElementNotPresent.java │ │ │ │ ├── AssertElementPresent.java │ │ │ │ ├── AssertElementVisible.java │ │ │ │ ├── AssertElementNotVisible.java │ │ │ │ ├── AssertElementSelected.java │ │ │ │ ├── DeleteCookie.java │ │ │ │ ├── AssertElementNotSelected.java │ │ │ │ ├── ReadElementText.java │ │ │ │ ├── AssertElementDisabled.java │ │ │ │ ├── AssertElementEnabled.java │ │ │ │ ├── ActionsSendKeys.java │ │ │ │ ├── AssertElementNotReadOnly.java │ │ │ │ ├── AssertElementReadOnly.java │ │ │ │ ├── ReadElementAttribute.java │ │ │ │ ├── ActionsMoveTo.java │ │ │ │ ├── AssertElementHasAttribute.java │ │ │ │ ├── ReadBrowserLogs.java │ │ │ │ ├── AddCookie.java │ │ │ │ ├── SwitchToLastWindow.java │ │ │ │ ├── AssertElementFocused.java │ │ │ │ ├── SwitchToFrame.java │ │ │ │ ├── AssertCssProperty.java │ │ │ │ ├── ActionsDragAndDropBy.java │ │ │ │ ├── AssertElementHasClass.java │ │ │ │ ├── ActionsClick.java │ │ │ │ ├── ExecuteScript.java │ │ │ │ ├── ActionsClickAndHold.java │ │ │ │ ├── ActionsKeyUp.java │ │ │ │ ├── ActionsDoubleClick.java │ │ │ │ ├── ActionsContextClick.java │ │ │ │ ├── ReadUrl.java │ │ │ │ ├── SetBrowserAspect.java │ │ │ │ ├── GetElements.java │ │ │ │ ├── ActionsDragAndDrop.java │ │ │ │ ├── SelectListOption.java │ │ │ │ ├── DeselectListOption.java │ │ │ │ ├── SwitchToWindow.java │ │ │ │ ├── ClearContent.java │ │ │ │ ├── Click.java │ │ │ │ ├── core │ │ │ │ └── ElementWrapper.java │ │ │ │ ├── AssertElementText.java │ │ │ │ ├── AssertPageTitle.java │ │ │ │ ├── SendKeys.java │ │ │ │ ├── ReadElementAspect.java │ │ │ │ └── AssertUrl.java │ │ └── test │ │ │ └── java │ │ │ └── org │ │ │ └── getopentest │ │ │ └── selenium │ │ │ └── core │ │ │ └── SeleniumHelperNGTest.java │ └── .gitignore ├── base │ ├── src │ │ ├── test │ │ │ └── java │ │ │ │ └── org │ │ │ │ └── getopentest │ │ │ │ ├── base │ │ │ │ └── DummyClass.java │ │ │ │ ├── logging │ │ │ │ └── TestLogger.java │ │ │ │ └── util │ │ │ │ ├── EncryptorNGTest.java │ │ │ │ └── StringUtilNGTest.java │ │ └── main │ │ │ ├── java │ │ │ └── org │ │ │ │ └── getopentest │ │ │ │ ├── annotations │ │ │ │ ├── TestActionClass.java │ │ │ │ ├── TestActionOutputs.java │ │ │ │ ├── TestActionArguments.java │ │ │ │ ├── Type.java │ │ │ │ ├── TestActionOutput.java │ │ │ │ └── TestActionArgument.java │ │ │ │ ├── actions │ │ │ │ ├── ReadTextFile.java │ │ │ │ ├── visual │ │ │ │ │ └── ClickImage.java │ │ │ │ ├── Log.java │ │ │ │ ├── Delay.java │ │ │ │ ├── codecs │ │ │ │ │ ├── EncodeUtf8.java │ │ │ │ │ └── DecodeUtf8.java │ │ │ │ ├── Assert.java │ │ │ │ ├── Format.java │ │ │ │ ├── SampleAction.java │ │ │ │ ├── db │ │ │ │ │ └── JdbcUpdate.java │ │ │ │ ├── files │ │ │ │ │ ├── WriteTextFile.java │ │ │ │ │ └── ReadTextFile.java │ │ │ │ └── GetTestAsset.java │ │ │ │ ├── base │ │ │ │ ├── TestActorEvents.java │ │ │ │ ├── MacroAction.java │ │ │ │ ├── SessionStatusResponse.java │ │ │ │ ├── TestActionInfo.java │ │ │ │ ├── ScriptAction.java │ │ │ │ └── TestSessionStatus.java │ │ │ │ ├── contracts │ │ │ │ ├── IAutomator.java │ │ │ │ ├── ILogger.java │ │ │ │ └── IImageFinder.java │ │ │ │ ├── exceptions │ │ │ │ ├── SkipTestException.java │ │ │ │ ├── CheckpointException.java │ │ │ │ ├── IntentionalFailException.java │ │ │ │ ├── ArgumentException.java │ │ │ │ └── ImageNotFoundException.java │ │ │ │ ├── logging │ │ │ │ ├── LogEntry.java │ │ │ │ ├── LogLevel.java │ │ │ │ ├── NullLogger.java │ │ │ │ ├── ConsoleLogger.java │ │ │ │ └── Logger.java │ │ │ │ ├── visual │ │ │ │ ├── Circle.java │ │ │ │ ├── MatchingMethod.java │ │ │ │ ├── ImageFinderResult.java │ │ │ │ └── CvHelper.java │ │ │ │ ├── testdef │ │ │ │ ├── TestDefSegment.java │ │ │ │ ├── TestDefActor.java │ │ │ │ ├── TestDefAction.java │ │ │ │ ├── TestDefinition.java │ │ │ │ └── MacroDefinition.java │ │ │ │ ├── http │ │ │ │ ├── HttpDeleteWithBody.java │ │ │ │ ├── ContentType.java │ │ │ │ ├── HttpVerb.java │ │ │ │ ├── NoopTrustManager.java │ │ │ │ └── HttpRequestOptions.java │ │ │ │ ├── serialization │ │ │ │ ├── json │ │ │ │ │ ├── TrimmableMap.java │ │ │ │ │ ├── DoubleSerializer.java │ │ │ │ │ ├── BufferedImageSerializer.java │ │ │ │ │ ├── ScriptObjectMirrorSerializer.java │ │ │ │ │ └── DuplicateFieldExclusionStrategy.java │ │ │ │ └── yaml │ │ │ │ │ └── SkipNullRepresenter.java │ │ │ │ └── util │ │ │ │ ├── RegexUtil.java │ │ │ │ ├── MainUtil.java │ │ │ │ ├── ServerRequest.java │ │ │ │ ├── ImageCompareResult.java │ │ │ │ ├── StringUtil.java │ │ │ │ └── TypeUtil.java │ │ │ └── resources │ │ │ ├── actor.test.yaml │ │ │ └── actor.test.properties │ ├── nb-configuration.xml │ └── .gitignore └── appium │ ├── src │ └── main │ │ └── java │ │ └── org │ │ └── getopentest │ │ └── appium │ │ ├── AssertElementDisabled.java │ │ ├── AssertElementUnchecked.java │ │ ├── ResetApp.java │ │ ├── TapByCoordinates.java │ │ ├── ReadPageSource.java │ │ ├── TakeScreenshot.java │ │ ├── RunAppInBackground.java │ │ ├── HideKeyboard.java │ │ ├── NavigateBack.java │ │ ├── core │ │ ├── SwipeCoordinates.java │ │ ├── Condition.java │ │ ├── WaitingAction.java │ │ ├── SwipingWaitingAction.java │ │ ├── CustomConditions.java │ │ └── ElementWrapper.java │ │ ├── ActionsRelease.java │ │ ├── ActionsWait.java │ │ ├── ReadElementText.java │ │ ├── CloseApp.java │ │ ├── ExecuteScript.java │ │ ├── ReadElementAttribute.java │ │ ├── LaunchApp.java │ │ ├── TouchAndMove.java │ │ ├── ActionsPause.java │ │ ├── SwitchContext.java │ │ ├── serialization │ │ └── AppiumDriverSerializer.java │ │ ├── ActionsPerform.java │ │ ├── SwitchToFrame.java │ │ ├── ReadScreenSize.java │ │ ├── AssertElementNotVisible.java │ │ ├── AssertElementPresent.java │ │ ├── AssertElementNotEnabled.java │ │ ├── AssertElementVisible.java │ │ ├── GetElements.java │ │ ├── AssertElementEnabled.java │ │ ├── AssertElementChecked.java │ │ ├── AssertElementNotChecked.java │ │ └── Tap.java │ └── .gitignore ├── .vscode ├── settings.json └── launch.json ├── .github ├── ISSUE_TEMPLATE.md └── stale.yml ├── .gitattributes ├── LICENSE ├── package.json └── .gitignore /server/.eslintignore: -------------------------------------------------------------------------------- 1 | src/public/js/lib/* -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/service'); -------------------------------------------------------------------------------- /server/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as syncService from './service'; 2 | 3 | module.exports = syncService; -------------------------------------------------------------------------------- /actor/actor/src/main/resources/run.bat: -------------------------------------------------------------------------------- 1 | title ACTOR 2 | java -cp "*;jars/*;dependency-jars/*" org.getopentest.Main -------------------------------------------------------------------------------- /server/src/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/favicon.ico -------------------------------------------------------------------------------- /server/src/start.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as syncService from './service'; 3 | 4 | syncService.start(); -------------------------------------------------------------------------------- /server/src/public/img/loader-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/img/loader-circle.png -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /server/bin/opentest-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | const syncService = require("./dist/service"); 4 | syncService.start(); -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /server/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6 4 | }, 5 | "rules": { 6 | "semi": "warn" 7 | } 8 | } -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/HEAD/server/src/public/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/HandleAlert.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | @Deprecated 4 | public class HandleAlert extends HandleModal { 5 | } 6 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadCurrentUrl.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | @Deprecated 4 | public class ReadCurrentUrl extends ReadUrl { 5 | } 6 | -------------------------------------------------------------------------------- /server/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: node:6.9.5 2 | 3 | stages: 4 | - build 5 | 6 | transpile_job: 7 | stage: build 8 | script: 9 | - npm install 10 | - npm run build -------------------------------------------------------------------------------- /actor/base/src/test/java/org/getopentest/base/DummyClass.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | public class DummyClass { 4 | public int dummyMethod() { 5 | return 1; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /server/src/test/repo/tests/Dummy.yaml: -------------------------------------------------------------------------------- 1 | description: Dummy test 2 | actors: 3 | - actor: ACTOR1 4 | segments: 5 | - segment: 1 6 | actions: 7 | - script: $log("Do nothing"); -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/annotations/TestActionClass.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | public @interface TestActionClass { 4 | String description() default ""; 5 | } 6 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/annotations/TestActionOutputs.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | public @interface TestActionOutputs { 4 | TestActionOutput[] value(); 5 | } 6 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsMoveToElement.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | @Deprecated 4 | public class ActionsMoveToElement extends ActionsMoveTo { 5 | } 6 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementDisabled.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | @Deprecated 4 | public class AssertElementDisabled extends AssertElementNotEnabled { 5 | } 6 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/ReadTextFile.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | @Deprecated 4 | public class ReadTextFile extends org.getopentest.actions.files.ReadTextFile { 5 | } 6 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/annotations/TestActionArguments.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | public @interface TestActionArguments { 4 | TestActionArgument[] value(); 5 | } 6 | -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | OpenTest is a functional test automation framework for web, mobile and REST APIs. For installation instructions and documentation please see the [OpenTest repo](https://github.com/mcdcorp/opentest) on GitHub. -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "outDir": "dist", 6 | "sourceMap": true, 7 | "target": "es6" 8 | } 9 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/base/TestActorEvents.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | public enum TestActorEvents { 4 | SESSION_STARTED, 5 | SESSION_COMPLETED, 6 | TEST_STARTED, 7 | TEST_COMPLETED, 8 | } 9 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/annotations/Type.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | public enum Type { 4 | ARRAY, 5 | BOOLEAN, 6 | DOUBLE, 7 | INTEGER, 8 | LOCATOR, 9 | MAP, 10 | OBJECT, 11 | STRING 12 | } 13 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementUnchecked.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | /** 4 | * Verifies that a UI element's checked attribute is false. 5 | */ 6 | @Deprecated 7 | public class AssertElementUnchecked extends AssertElementNotChecked { 8 | } 9 | -------------------------------------------------------------------------------- /server/.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | /coverage/ 3 | /db/ 4 | /node_modules/ 5 | /logs/ 6 | /src/ 7 | /typings/ 8 | .eslintignore 9 | .eslintrc 10 | .gitlab-ci.yml 11 | gulpfile.js 12 | npm-debug.* 13 | /opentest*.tar 14 | /opentest*.tgz 15 | OSS.txt 16 | server.yaml 17 | TODO.txt 18 | tsconfig.json -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/contracts/IAutomator.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.contracts; 2 | 3 | public interface IAutomator { 4 | public void mouseClick(int x, int y); 5 | 6 | public void mouseMove(int x, int y); 7 | 8 | public void mouseMove(int x, int y, int mouseMoveTimeMs); 9 | } 10 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/annotations/TestActionOutput.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | import java.lang.annotation.Repeatable; 4 | 5 | @Repeatable(TestActionOutputs.class) 6 | public @interface TestActionOutput { 7 | String name(); 8 | Type type(); 9 | String description() default ""; 10 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/exceptions/SkipTestException.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.exceptions; 2 | 3 | /** 4 | * Thrown when a script calls the $skipTest function. 5 | */ 6 | public class SkipTestException extends RuntimeException { 7 | public SkipTestException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/exceptions/CheckpointException.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.exceptions; 2 | 3 | /** 4 | * Wraps exceptions returned from checkpoint actions. 5 | */ 6 | public class CheckpointException extends RuntimeException { 7 | public CheckpointException(Throwable cause) { 8 | super(cause); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ResetApp.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | 5 | public class ResetApp extends AppiumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | driver.resetApp(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/CloseWindow.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class CloseWindow extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | driver.close(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/TapByCoordinates.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | /** 4 | * The TapByCoordinates action has been deprecated and will be removed in future 5 | * versions of OpenTest. Please use the Tap action instead. 6 | * 7 | * @deprecated 8 | */ 9 | @Deprecated 10 | public class TapByCoordinates extends Tap { 11 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/logging/LogEntry.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.logging; 2 | 3 | import java.time.Instant; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | public class LogEntry { 10 | 11 | private LogLevel logLevel; 12 | private String text; 13 | private Instant timestamp; 14 | } 15 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/NavigateBack.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class NavigateBack extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | this.driver.navigate().back(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /server/src/lib/express-session.ts: -------------------------------------------------------------------------------- 1 | import * as expressSession from 'express-session'; 2 | 3 | export let sessionSettings = expressSession({ 4 | cookie: { 5 | // Expire session 8 hours after last activity 6 | maxAge: 8 * 60 * 60 * 1000 7 | }, 8 | name: 'sid', 9 | resave: false, 10 | rolling: true, 11 | saveUninitialized: true, 12 | secret: '2Pdkf87H8hS2g9JdO6Mz' 13 | }); -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/NavigateForward.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class NavigateForward extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | this.driver.navigate().forward(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/exceptions/IntentionalFailException.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.exceptions; 2 | 3 | /** 4 | * Thrown when a script calls the $fail function to deliberately fail a test. 5 | */ 6 | public class IntentionalFailException extends RuntimeException { 7 | public IntentionalFailException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/logging/LogLevel.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.logging; 2 | 3 | public enum LogLevel { 4 | TRACE(1), 5 | DEBUG(2), 6 | INFO(3), 7 | WARN(4), 8 | ERROR(5); 9 | 10 | private int value; 11 | 12 | LogLevel(int value) { 13 | this.value = value; 14 | } 15 | 16 | public int getValue() { 17 | return value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/annotations/TestActionArgument.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | import java.lang.annotation.Repeatable; 4 | 5 | @Repeatable(TestActionArguments.class) 6 | public @interface TestActionArgument { 7 | String defaultValue() default "N/A"; 8 | String name(); 9 | Type type(); 10 | String description() default ""; 11 | boolean optional(); 12 | } 13 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/visual/ClickImage.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions.visual; 2 | 3 | import org.getopentest.base.TestAction; 4 | 5 | /** 6 | * Finds an image on the screen and clicks it. 7 | */ 8 | public class ClickImage extends TestAction { 9 | 10 | @Override 11 | public void run() { 12 | super.run(); 13 | 14 | // Work in progress 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/exceptions/ArgumentException.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.exceptions; 2 | 3 | /** 4 | * Thrown when there's a problem with a test action's argument (missing 5 | * mandatory argument, wrong argument data type, etc.). 6 | */ 7 | public class ArgumentException extends RuntimeException { 8 | public ArgumentException(String message) { 9 | super(message); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/visual/Circle.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.visual; 2 | 3 | /** 4 | * Stores the coordinates and radius of a circle. 5 | */ 6 | public class Circle { 7 | 8 | public int x; 9 | public int y; 10 | public int radius; 11 | 12 | public Circle(int x, int y, int radius) { 13 | this.x = x; 14 | this.y = y; 15 | this.radius = radius; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ReadPageSource.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | 5 | public class ReadPageSource extends AppiumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | String pageSource = driver.getPageSource(); 12 | 13 | this.writeOutput("pageSource", pageSource); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/CloseBrowser.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.getopentest.selenium.core.SeleniumHelper; 5 | 6 | public class CloseBrowser extends SeleniumTestAction{ 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | SeleniumHelper.discardDriver(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadPageSource.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class ReadPageSource extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | String pageSource = driver.getPageSource(); 12 | 13 | this.writeOutput("pageSource", pageSource); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/TakeScreenshot.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.appium.core.AppiumTestAction; 5 | 6 | @TestActionClass(description = "Takes a screenshot.") 7 | 8 | public class TakeScreenshot extends AppiumTestAction { 9 | 10 | public TakeScreenshot() { 11 | this.writeArgument("$screenshot", "true"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/Log.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | import org.getopentest.base.TestAction; 4 | 5 | /** 6 | * An action to log information using the test actor's logger. 7 | */ 8 | public class Log extends TestAction { 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | String text = this.readStringArgument("text"); 14 | 15 | this.log.info(text); 16 | } 17 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/base/MacroAction.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | import org.getopentest.base.TestAction; 4 | 5 | /** 6 | * Represents the action that corresponds to the "macro" node in an actions list. 7 | */ 8 | public class MacroAction extends TestAction { 9 | 10 | @Override 11 | public void run() { 12 | // Nothing here yet, because script execution is handled by the 13 | // test actor class. 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsPause.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class ActionsPause extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | Integer durationMs = this.readIntArgument("durationMs"); 12 | 13 | SeleniumTestAction.getActionsInstance().pause(durationMs); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/testdef/TestDefSegment.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.testdef; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Represents a test segment section in a test definition file. 7 | */ 8 | public class TestDefSegment { 9 | 10 | public List actions; 11 | 12 | @Deprecated 13 | public Integer index; 14 | 15 | @Deprecated 16 | public Integer step; 17 | 18 | public Integer segment; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/TakeScreenshot.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | 6 | @TestActionClass(description = "Takes a screenshot of the current browser window.") 7 | 8 | public class TakeScreenshot extends SeleniumTestAction { 9 | 10 | public TakeScreenshot() { 11 | this.writeArgument("$screenshot", "true"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/RunAppInBackground.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import java.time.Duration; 4 | import org.getopentest.appium.core.AppiumTestAction; 5 | 6 | public class RunAppInBackground extends AppiumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | Integer seconds = this.readIntArgument("seconds"); 13 | 14 | driver.runAppInBackground(Duration.ofSeconds(seconds)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/http/HttpDeleteWithBody.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.http; 2 | 3 | import java.net.URI; 4 | import org.apache.http.client.methods.HttpPost; 5 | 6 | public class HttpDeleteWithBody extends HttpPost { 7 | 8 | HttpDeleteWithBody(String uri) { 9 | super(uri); 10 | } 11 | 12 | HttpDeleteWithBody(URI uri) { 13 | super(uri); 14 | } 15 | 16 | @Override 17 | public String getMethod() { 18 | return "DELETE"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/logging/NullLogger.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.logging; 2 | 3 | import java.time.Instant; 4 | 5 | /** 6 | * A logger that doesn't do anything with the log entries. This is 7 | * used when we need to avoid logging sensitive information. 8 | */ 9 | public class NullLogger extends BaseLogger { 10 | 11 | @Override 12 | protected void writeLogEntry(String text, org.getopentest.logging.LogLevel level, Instant timestamp) { 13 | // Nothing to do here. 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/NavigateTo.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumHelper; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | 6 | public class NavigateTo extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | String url = this.readStringArgument("url"); 13 | 14 | SeleniumHelper.verifyDriverIsValid(); 15 | driver.get(url); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /actor/actor/src/main/README.md: -------------------------------------------------------------------------------- 1 | There's no Java code in here, because the actor project is only defining dependencies to the projects containing the actual code (base, selenium, appium, etc.) 2 | 3 | This project also contains an "actor.sample.yaml" file in its resources, which is used as the template config file by the command-line tools. 4 | 5 | If you create an "actor.yaml" file in the project's resources, and if there's no actor.yaml config file on disk in the root of the project, this file will be used by default when debugging Java code. -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/serialization/json/TrimmableMap.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.serialization.json; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * A HasMap whose values can be "trimmed" if they exceed a certain length when 8 | * serialized to JSON. 9 | */ 10 | public class TrimmableMap extends HashMap { 11 | 12 | public TrimmableMap() { 13 | } 14 | 15 | public TrimmableMap(Map map) { 16 | super(map); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /actor/base/src/test/java/org/getopentest/logging/TestLogger.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.logging; 2 | 3 | import java.time.Instant; 4 | 5 | /** Unit test helper class */ 6 | public class TestLogger extends BaseLogger { 7 | 8 | public LogLevel lastLogLevel; 9 | 10 | public String lastLogText = null; 11 | 12 | @Override 13 | protected void writeLogEntry(String text, LogLevel level, Instant timestamp) { 14 | this.lastLogLevel = level; 15 | this.lastLogText = text; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/http/ContentType.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.http; 2 | 3 | public class ContentType { 4 | 5 | public static final String APPLICATION_JAVASCRIPT = "application/javascript"; 6 | public static final String APPLICATION_JSON = "application/json"; 7 | public static final String APPLICATION_XML = "application/xml"; 8 | public static final String TEXT_CSV = "text/csv"; 9 | public static final String TEXT_HTML = "text/html"; 10 | public static final String TEXT_PLAIN = "text/plain"; 11 | } 12 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/testdef/TestDefActor.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.testdef; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Represents an actor section in a test definition file. 7 | */ 8 | public class TestDefActor { 9 | 10 | public String actor; 11 | 12 | /** 13 | * Alternative name for the "actor" property. 14 | */ 15 | @Deprecated 16 | public String actorType; 17 | 18 | public List segments; 19 | 20 | @Deprecated 21 | public List steps; 22 | } 23 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/HideKeyboard.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | 5 | public class HideKeyboard extends AppiumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | String keyName = this.readStringArgument("keyName", null); 12 | 13 | if (keyName == null) { 14 | this.hideKeyboard(); 15 | } else { 16 | this.hideKeyboard(keyName); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/Delay.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | import org.getopentest.base.TestAction; 4 | 5 | /** 6 | * An action that delays execution of the test scenario. 7 | */ 8 | public class Delay extends TestAction { 9 | 10 | @Override 11 | public void run() { 12 | super.run(); 13 | 14 | int seconds = readIntArgument("seconds"); 15 | 16 | try { 17 | Thread.sleep(seconds * 1000); 18 | } catch (InterruptedException ex) { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/NavigateBack.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | import org.getopentest.annotations.TestActionClass; 5 | 6 | @TestActionClass(description = "Performs a \"navigate back\" action.") 7 | 8 | /** 9 | * Performs a "navigate back" action. 10 | */ 11 | public class NavigateBack extends AppiumTestAction { 12 | 13 | @Override 14 | public void run() { 15 | super.run(); 16 | 17 | this.driver.navigate().back(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/core/SwipeCoordinates.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.core; 2 | 3 | /** 4 | * Stores the two pairs of coordinates necessary to perform a swipe. 5 | */ 6 | public class SwipeCoordinates { 7 | 8 | public int fromX; 9 | public int fromY; 10 | public int toX; 11 | public int toY; 12 | 13 | public SwipeCoordinates(int fromX, int fromY, int toX, int toY) { 14 | this.fromX = fromX; 15 | this.fromY = fromY; 16 | this.toX = toX; 17 | this.toY = toY; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsMoveByOffset.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class ActionsMoveByOffset extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | Integer xOffset = this.readIntArgument("xOffset", 0); 12 | Integer yOffset = this.readIntArgument("yOffset", 0); 13 | 14 | SeleniumTestAction.getActionsInstance().moveByOffset(xOffset, yOffset); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/http/HttpVerb.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.http; 2 | 3 | public enum HttpVerb { 4 | DELETE, 5 | /** 6 | * Will actually use DELETE verb, but also allow a payload to be sent. This 7 | * is to work around the Apache HTTP client removing the payload for DELETE 8 | * requests. This value is for internal use only and not to be used directly 9 | * when calling the HttpRequest action. 10 | */ 11 | DELETE_WITH_BODY, 12 | GET, 13 | HEAD, 14 | OPTIONS, 15 | PATCH, 16 | POST, 17 | PUT 18 | } -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/core/Condition.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.core; 2 | 3 | /** 4 | * Represents the types of conditions we might want to check for on a target UI 5 | * element. 6 | */ 7 | public enum Condition { 8 | /** 9 | * The element is present and visible on the screen. 10 | */ 11 | VISIBILITY, 12 | /** 13 | * The element is present but not necessarily visible on the screen. 14 | */ 15 | PRESENCE, 16 | /** 17 | * The element is not visible on the screen. 18 | */ 19 | INVISIBILITY 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.enabledLanguageIds": [ 3 | "asciidoc", 4 | "c", 5 | "cpp", 6 | "csharp", 7 | "go", 8 | "handlebars", 9 | "javascript", 10 | "javascriptreact", 11 | "json", 12 | "latex", 13 | "markdown", 14 | "php", 15 | "plaintext", 16 | "python", 17 | "restructuredtext", 18 | "text", 19 | "typescript", 20 | "typescriptreact", 21 | "yml" 22 | ], 23 | "java.configuration.updateBuildConfiguration": "disabled" 24 | } -------------------------------------------------------------------------------- /actor/base/src/test/java/org/getopentest/util/EncryptorNGTest.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import static org.testng.Assert.*; 4 | import org.testng.annotations.Test; 5 | 6 | public class EncryptorNGTest { 7 | 8 | @Test 9 | public void testEncryptDecrypt() { 10 | String secret = "secret"; 11 | 12 | Encryptor encryptor = new Encryptor("password"); 13 | String encrypted = encryptor.encrypt("secret"); 14 | String decrypted = encryptor.decrypt(encrypted); 15 | 16 | assertEquals(secret, decrypted); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadElementCount.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class ReadElementCount extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | By locator = this.readLocatorArgument("locator"); 13 | 14 | this.waitForAsyncCallsToFinish(); 15 | 16 | this.writeOutput("count", this.getElements(locator).size()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ActionsRelease.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.appium.core.AppiumTestAction; 5 | 6 | @TestActionClass( 7 | description = "Release the current touching implement from the screen. " 8 | + "Withdraw your touch.") 9 | 10 | public class ActionsRelease extends AppiumTestAction { 11 | 12 | @Override 13 | public void run() { 14 | super.run(); 15 | 16 | AppiumTestAction.getActionsInstance().release(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SwitchToDefaultContent.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class SwitchToDefaultContent extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | try { 12 | this.driver.switchTo().defaultContent(); 13 | } catch (Exception ex) { 14 | throw new RuntimeException( 15 | "Failed to switch back to the main page content", ex); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ActionsWait.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.touch.WaitOptions; 4 | import java.time.Duration; 5 | import org.getopentest.appium.core.AppiumTestAction; 6 | 7 | public class ActionsWait extends AppiumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | Double seconds = this.readDoubleArgument("seconds"); 14 | 15 | AppiumTestAction.getActionsInstance().waitAction(WaitOptions.waitOptions(Duration.ofMillis((long)(seconds * 1000)))); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/exceptions/ImageNotFoundException.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.exceptions; 2 | 3 | import java.awt.Rectangle; 4 | 5 | /** 6 | * Thrown to indicate an image find operation failed. 7 | */ 8 | public class ImageNotFoundException extends RuntimeException { 9 | Double accuracy; 10 | 11 | public Rectangle foundRect; 12 | 13 | public ImageNotFoundException(String message, Rectangle foundRect, Double accuracy) { 14 | super(message); 15 | 16 | this.accuracy = accuracy; 17 | this.foundRect = foundRect; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsPerform.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class ActionsPerform extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | this.waitForAsyncCallsToFinish(); 10 | 11 | try { 12 | SeleniumTestAction.getActionsInstance().perform(); 13 | } catch (Exception ex) { 14 | throw ex; 15 | } finally { 16 | SeleniumTestAction.discardActionsObject(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/base/SessionStatusResponse.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | public class SessionStatusResponse { 4 | 5 | public int currentDataRecordIndex = -1; 6 | 7 | public int currentIteration; 8 | 9 | public int currentSegmentIndex; 10 | 11 | @Deprecated 12 | public int currentStepIndex; 13 | 14 | public int currentTestIndex; 15 | 16 | public String currentTestPath; 17 | 18 | public String currentTestName; 19 | 20 | public String environment; 21 | 22 | public String result; 23 | 24 | public String status; 25 | } 26 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/visual/MatchingMethod.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.visual; 2 | 3 | /** 4 | * List of template matching methods for the OpenCV algorithm. We are always 5 | * using the "_NORMED" version of the methods. 6 | */ 7 | public enum MatchingMethod { 8 | /** 9 | * Normalized correlation coefficient. 10 | */ 11 | MM_CORELLATION_COEFF, 12 | 13 | /** 14 | * Normalized cross correlation. 15 | */ 16 | MM_CROSS_CORELLATION, 17 | 18 | /** 19 | * Sum of squared differences between pixel values. 20 | */ 21 | MM_SQUARE_DIFFERENCE 22 | } 23 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ReadElementText.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.SwipingAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class ReadElementText extends SwipingAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | By locator = this.readLocatorArgument("locator"); 13 | 14 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 15 | 16 | String elementText = this.getElement(locator).getText(); 17 | 18 | this.writeOutput("text", elementText); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadPageTitle.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | 5 | public class ReadPageTitle extends SeleniumTestAction { 6 | 7 | @Override 8 | public void run() { 9 | super.run(); 10 | 11 | this.waitForAsyncCallsToFinish(); 12 | 13 | this.writeOutput("title", driver.getTitle()); 14 | 15 | // The output "value" is deprecated in favor of "title", 16 | // and will eventually be removed 17 | this.writeOutput("value", driver.getTitle()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/CloseApp.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | import org.getopentest.annotations.TestActionClass; 5 | 6 | @TestActionClass( 7 | description = "Closes the application. Internally uses the " 8 | + "AppiumDriver.closeApp() method.") 9 | 10 | /** 11 | * Closes the app. Internally uses the AppiumDriver.closeApp() method. 12 | */ 13 | public class CloseApp extends AppiumTestAction { 14 | 15 | @Override 16 | public void run() { 17 | super.run(); 18 | 19 | driver.closeApp(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ExecuteScript.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import java.util.Map; 4 | import org.getopentest.appium.core.AppiumTestAction; 5 | 6 | /** 7 | * Executes a mobile script. 8 | */ 9 | public class ExecuteScript extends AppiumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | String script = this.readStringArgument("script"); 14 | Map scriptArgs = this.readMapArgument("scriptArgs", null); 15 | 16 | Object result = this.driver.executeScript(script, scriptArgs); 17 | 18 | this.writeOutput("result", result); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /server/src/public/css/session.css: -------------------------------------------------------------------------------- 1 | /*table tbody tr td.actions { 2 | padding: 0px; 3 | }*/ 4 | 5 | table.actions { 6 | margin: 0px; 7 | margin-top: -5px; 8 | } 9 | 10 | table.actions > tbody > tr > td { 11 | padding-bottom: 2px; 12 | padding-top: 2px; 13 | vertical-align: top; 14 | } 15 | 16 | table.actions > tbody > tr.top > td { 17 | border-bottom-width: 0px; 18 | } 19 | 20 | table.actions > tbody > tr.bottom > td { 21 | border-top-width: 0px; 22 | } 23 | 24 | table.actions td.failed { 25 | color: #D12730; 26 | font-weight: bold; 27 | } 28 | 29 | .ekko-lightbox .modal-title { 30 | text-transform: none; 31 | } -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadCookie.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.Cookie; 6 | 7 | @TestActionClass(description = "Reads the value of a cookie.") 8 | 9 | public class ReadCookie extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | super.run(); 14 | 15 | String name = this.readStringArgument("name"); 16 | 17 | Cookie cookie = driver.manage().getCookieNamed(name); 18 | this.writeOutput("value", cookie.getValue()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/util/RegexUtil.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | public class RegexUtil { 7 | 8 | /** 9 | * Parses and returns the flags portion of a JS-style regular expression. 10 | */ 11 | public static String getRegexFlags(String regex) { 12 | Pattern parserPattern = Pattern.compile("^\\/(.*?)\\/(.*)?$"); 13 | Matcher matcher = parserPattern.matcher(regex); 14 | 15 | if (matcher.find()) { 16 | return matcher.group(2).replaceAll("^/+", ""); 17 | } else { 18 | return ""; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /server/src/lib/build-info.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | 4 | let version; 5 | let buildDate; 6 | let commitSha; 7 | 8 | export function refreshBuildInfo() { 9 | const buildInfoJson = JSON.parse(fs.readFileSync(path.join(__dirname, "../../build-info.json"), 'utf8')); 10 | const pkJson = JSON.parse(fs.readFileSync(path.join(__dirname, "../../package.json"), 'utf8')); 11 | buildDate = buildInfoJson.buildDate; 12 | commitSha = buildInfoJson.commitSha; 13 | version = pkJson.version; 14 | } 15 | 16 | export function getBuildInfo() { 17 | return { 18 | version: version, 19 | buildDate: buildDate, 20 | commitSha: commitSha 21 | }; 22 | } 23 | 24 | refreshBuildInfo(); -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ReadElementAttribute.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.SwipingAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class ReadElementAttribute extends SwipingAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | By locator = this.readLocatorArgument("locator"); 13 | String attribute = this.readStringArgument("attribute"); 14 | 15 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 16 | 17 | String attributeValue = this.getElement(locator).getAttribute(attribute); 18 | 19 | this.writeOutput("text", attributeValue); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadCssProperty.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class ReadCssProperty extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | By locator = this.readLocatorArgument("locator"); 12 | String property = this.readStringArgument("property"); 13 | 14 | this.waitForAsyncCallsToFinish(); 15 | 16 | WebElement element = this.getElement(locator); 17 | 18 | this.writeOutput("value", element.getCssValue(property)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/LaunchApp.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | import org.getopentest.annotations.TestActionClass; 5 | 6 | @TestActionClass( 7 | description = "Launches the app that was provided in desired capabilities. " 8 | + "Internally uses the AppiumDriver.launchApp() method.") 9 | 10 | /** 11 | * Launches the app that was provided in desired capabilities at 12 | * session creation. Internally uses the AppiumDriver.launchApp() method. 13 | */ 14 | public class LaunchApp extends AppiumTestAction { 15 | 16 | @Override 17 | public void run() { 18 | super.run(); 19 | 20 | driver.launchApp(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OpenTest version number: X.X.X 5 | 6 | 7 | 8 | Steps to reproduce: 9 | 10 | 1. (describe step 1 here) 11 | 2. (describe step 2 here) 12 | 13 | 14 | 15 | Relevant log information: 16 | ``` 17 | (paste log contents here) 18 | ``` 19 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsRelease.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class ActionsRelease extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | By locator = this.readLocatorArgument("locator", null); 14 | 15 | if (locator != null) { 16 | WebElement element = this.getElement(locator); 17 | SeleniumTestAction.getActionsInstance().release(element); 18 | } else { 19 | SeleniumTestAction.getActionsInstance().release(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 120 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | - feature-request 10 | # Label to use when marking an issue as stale 11 | staleLabel: stale 12 | # Comment to post when marking an issue as stale. Set to `false` to disable 13 | markComment: > 14 | This issue has been automatically marked as stale because it has not had 15 | recent activity. It will be closed if no further activity occurs. Thank you 16 | for your contributions. 17 | # Comment to post when closing a stale issue. Set to `false` to disable 18 | closeComment: false -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/testdef/TestDefAction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package org.getopentest.testdef; 7 | 8 | import java.util.Map; 9 | 10 | /** 11 | * Represents an action in a test definition file. 12 | */ 13 | public class TestDefAction { 14 | public String action; 15 | 16 | public Map args; 17 | 18 | public String description; 19 | 20 | public String macro; 21 | 22 | public String script; 23 | 24 | @Deprecated 25 | public Map sharedData; 26 | 27 | @Deprecated 28 | public String type; 29 | } 30 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/GetActiveElement.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.selenium.core.ElementWrapper; 5 | import org.getopentest.selenium.core.SeleniumTestAction; 6 | import org.openqa.selenium.WebElement; 7 | 8 | @TestActionClass(description = "Returns the currently focused UI element.") 9 | 10 | public class GetActiveElement extends SeleniumTestAction { 11 | 12 | @Override 13 | public void run() { 14 | super.run(); 15 | 16 | this.waitForAsyncCallsToFinish(); 17 | 18 | WebElement activeElement = driver.switchTo().activeElement(); 19 | 20 | this.writeOutput("element", new ElementWrapper(activeElement)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/TouchAndMove.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | /** 4 | * The TouchAndMove action has been deprecated and will be removed in future 5 | * versions of OpenTest. Please use the Swipe action instead. 6 | * 7 | * @deprecated 8 | */ 9 | @Deprecated 10 | public class TouchAndMove extends Swipe { 11 | 12 | @Override 13 | public void run() { 14 | try { 15 | super.run(); 16 | } catch (Exception ex) { 17 | throw ex; 18 | } finally { 19 | this.log.error( 20 | "The TouchAndMove action has been deprecated and will be removed in " 21 | + "future versions of OpenTest. Please use the Swipe action instead."); 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/testdef/TestDefinition.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.testdef; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Represents the contents of a test definition file. 7 | */ 8 | public class TestDefinition { 9 | public List actors; 10 | 11 | /** 12 | * This property can be either a string that represents a JS expression evaluating 13 | * to a JS array or an objects that implements the List interface, when the dataSet 14 | * property is populated using a YAML sequence (list of items). 15 | */ 16 | public Object dataSet; 17 | 18 | @Deprecated 19 | public String format; 20 | 21 | public String description; 22 | 23 | public Object includes; 24 | 25 | public List tags; 26 | } 27 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementNotPresent.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.CustomConditions; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertElementNotPresent extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 20 | wait.until(CustomConditions.absenceOfElementLocated(locator)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementPresent.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertElementPresent extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 20 | wait.until(ExpectedConditions.presenceOfElementLocated(locator)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementVisible.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertElementVisible extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 20 | wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementNotVisible.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertElementNotVisible extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 20 | wait.until(ExpectedConditions.invisibilityOfElementLocated(locator)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementSelected.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertElementSelected extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 20 | wait.until(ExpectedConditions.elementSelectionStateToBe(locator, true)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/base/src/main/resources/actor.test.yaml: -------------------------------------------------------------------------------- 1 | # A string that will identify the type of actor that will be created. This 2 | # can be any string - as long as the same string is going to be used in the 3 | # test definition files - but it's recommended to use an uppecase 4 | # three-leter string (e.g. NP6, GMA, API, etc.) 5 | actorType: API 6 | 7 | # The HTTP proxy server to use when communicating with the sync server 8 | # httpProxy: http://localhost:8888 9 | 10 | # Possible values are: TRACE, DEBUG, INFO, WARN and ERROR 11 | logLevel: TRACE 12 | 13 | # The URL to the sync service 14 | syncServiceBaseUrl: http://localhost:3000 15 | 16 | # Defines whether screenshots will be taken only on failures or after every test 17 | # action. Possible values are: ON_FAILURE, ALWAYS. Default is ON_FAILURE. 18 | # takeScreenshot: ON_FAILURE -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/DeleteCookie.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | 8 | @TestActionClass(description = "Deletes a cookie.") 9 | @TestActionArgument( 10 | name = "name", type = Type.STRING, optional = false, 11 | description = "The name of the cookie to delete.") 12 | 13 | public class DeleteCookie extends SeleniumTestAction { 14 | 15 | @Override 16 | public void run() { 17 | super.run(); 18 | 19 | String name = this.readStringArgument("name"); 20 | 21 | driver.manage().deleteCookieNamed(name); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementNotSelected.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertElementNotSelected extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 20 | wait.until(ExpectedConditions.elementSelectionStateToBe(locator, false)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadElementText.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class ReadElementText extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | By locator = this.readLocatorArgument("locator"); 13 | 14 | this.waitForAsyncCallsToFinish(); 15 | 16 | String elementText = this.getElement(locator).getText(); 17 | 18 | this.writeOutput("text", elementText); 19 | 20 | // The output "value" is deprecated in favor of "text", 21 | // and will eventually be removed 22 | this.writeOutput("value", elementText); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ActionsPause.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.touch.WaitOptions; 4 | import java.time.Duration; 5 | import org.getopentest.annotations.TestActionClass; 6 | import org.getopentest.appium.core.AppiumTestAction; 7 | 8 | @TestActionClass( 9 | description = "Waits for specified amount of time to pass before " 10 | + "continuing with the next touch action.") 11 | 12 | public class ActionsPause extends AppiumTestAction { 13 | 14 | @Override 15 | public void run() { 16 | super.run(); 17 | 18 | Integer durationMs = this.readIntArgument("durationMs"); 19 | 20 | AppiumTestAction.getActionsInstance().waitAction( 21 | WaitOptions.waitOptions(Duration.ofMillis(durationMs))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/base/src/main/resources/actor.test.properties: -------------------------------------------------------------------------------- 1 | # A string that will identify the type of actor that will be created. This 2 | # can be any string - as long as the same string is going to be used in the 3 | # test definition files - but it's recommended to use an uppecase 4 | # three-leter string (e.g. NP6, GMA, API, etc.) 5 | actorType = API 6 | 7 | # The HTTP proxy server to use when communicating with the sync server 8 | # httpProxy = http://localhost:8888 9 | 10 | # Possible values are: TRACE, DEBUG, INFO, WARN and ERROR 11 | logLevel = TRACE 12 | 13 | # The URL to the sync service 14 | syncServiceBaseUrl = http://localhost:3000 15 | 16 | # Defines whether screenshots will be taken only on failures or after every test 17 | # action. Possible values are: ON_FAILURE, ALWAYS. Default is ON_FAILURE. 18 | # takeScreenshot = ON_FAILURE -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/http/NoopTrustManager.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.http; 2 | 3 | import java.security.cert.CertificateException; 4 | import java.security.cert.X509Certificate; 5 | import javax.net.ssl.X509TrustManager; 6 | 7 | /** 8 | * A trust manages that doesn't verify anything and will happily trust any 9 | * client, server and/or CA. 10 | */ 11 | public class NoopTrustManager implements X509TrustManager { 12 | 13 | @Override 14 | public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { 15 | } 16 | 17 | @Override 18 | public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { 19 | } 20 | 21 | @Override 22 | public X509Certificate[] getAcceptedIssuers() { 23 | return null; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/testdef/MacroDefinition.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.testdef; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Represents the contents of a macro definition file. 7 | */ 8 | public class MacroDefinition { 9 | 10 | public List actions; 11 | 12 | public String description; 13 | 14 | @Deprecated 15 | public String format; 16 | 17 | /** 18 | * The fully qualified name of the macro which includes parent directory and 19 | * the macro definition file name. This property is for internal use only, 20 | * namely to store the name and relative path of a macro when the macro 21 | * definition is passed across the call stack. 22 | */ 23 | public String fullName; 24 | 25 | public Object includes; 26 | 27 | public List tags; 28 | } 29 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/codecs/EncodeUtf8.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions.codecs; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.charset.StandardCharsets; 5 | import java.util.Arrays; 6 | import org.getopentest.base.TestAction; 7 | 8 | public class EncodeUtf8 extends TestAction { 9 | 10 | @Override 11 | public void run() { 12 | super.run(); 13 | 14 | String string = this.readStringArgument("sourceString"); 15 | 16 | ByteBuffer encodedBytesBuffer = StandardCharsets.UTF_8.encode(string); 17 | byte[] encodedBytes = Arrays.copyOfRange( 18 | encodedBytesBuffer.array(), 19 | encodedBytesBuffer.arrayOffset(), 20 | encodedBytesBuffer.limit()); 21 | 22 | this.writeOutput("encodedBytes", encodedBytes); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /server/src/lib/db-manager.ts: -------------------------------------------------------------------------------- 1 | import * as configLoader from '../lib/config-loader'; 2 | import * as helpers from '../lib/helpers'; 3 | import { DbAdapter } from './types'; 4 | import { NedbAdapter } from './nedb-adapter' 5 | 6 | export interface DbOptions { 7 | adapter?: 'nedb' | 'mongodb' 8 | } 9 | 10 | let db: DbAdapter = null; 11 | 12 | export function getDb() { 13 | return db; 14 | } 15 | 16 | export function initDb() { 17 | const config = configLoader.getConfig(); 18 | const dbAdapter = config.dbAdapter || 'nedb'; 19 | 20 | if (dbAdapter === 'nedb') { 21 | db = new NedbAdapter(); 22 | db.initDb(); 23 | } else { 24 | throw new Error(helpers.format( 25 | 'Unknown database adapter: "{0}". Check the "dbAdapter" parameter in your configuration file', 26 | dbAdapter)); 27 | } 28 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/base/TestActionInfo.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | 6 | /** 7 | * Stores summary information about a test action that will be sent to the sync 8 | * server to be used for reporting and troubleshooting purposes. 9 | */ 10 | public class TestActionInfo { 11 | 12 | public String action; 13 | 14 | public String actorType; 15 | 16 | public HashMap args; 17 | 18 | public boolean isCheckpoint; 19 | 20 | public String description; 21 | 22 | public int durationMs; 23 | 24 | public String macro; 25 | 26 | public List macroStack; 27 | 28 | public String result; 29 | 30 | public String screenshot; 31 | 32 | public int segment; 33 | 34 | public String stackTrace; 35 | } 36 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/serialization/yaml/SkipNullRepresenter.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.serialization.yaml; 2 | 3 | import org.yaml.snakeyaml.introspector.Property; 4 | import org.yaml.snakeyaml.nodes.NodeTuple; 5 | import org.yaml.snakeyaml.nodes.Tag; 6 | import org.yaml.snakeyaml.representer.Representer; 7 | 8 | /** 9 | * A SnakeYAML representer that ignores properties with null values. 10 | */ 11 | public class SkipNullRepresenter extends Representer { 12 | 13 | @Override 14 | protected NodeTuple representJavaBeanProperty(Object javaBean, Property property, Object propertyValue, Tag customTag) { 15 | if (propertyValue == null) { 16 | return null; 17 | } else { 18 | return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/SwitchContext.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | import java.util.Set; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | public class SwitchContext extends AppiumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | String context = this.readStringArgument("context"); 14 | try { 15 | this.driver.context(context); 16 | } catch (Exception ex) { 17 | Set contexts = this.driver.getContextHandles(); 18 | throw new RuntimeException(String.format("Failed switching context to %s. The available contexts were %s.", 19 | context, 20 | StringUtils.join(contexts, ", ")), ex); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/serialization/json/DoubleSerializer.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.serialization.json; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonPrimitive; 5 | import com.google.gson.JsonSerializationContext; 6 | import com.google.gson.JsonSerializer; 7 | 8 | /** 9 | * Custom Gson serializer for Double numbers. This is necessary to avoid the 10 | * ".0" suffix for numbers that have no decimal part. 11 | */ 12 | public class DoubleSerializer implements JsonSerializer { 13 | 14 | @Override 15 | public JsonElement serialize(Double src, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) { 16 | if (src == Math.ceil(src)) { 17 | return new JsonPrimitive(src.intValue()); 18 | } else { 19 | return new JsonPrimitive(src); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/contracts/ILogger.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.contracts; 2 | 3 | import org.getopentest.logging.LogLevel; 4 | 5 | public interface ILogger { 6 | 7 | public void addSecret(String secret); 8 | 9 | public void addSecretByRegex(String secretRegex); 10 | 11 | public void clearSecrets(); 12 | 13 | public void debug(String text); 14 | 15 | public void error(String text); 16 | 17 | public void error(String message, Throwable exception); 18 | 19 | public void info(String text); 20 | 21 | public void setLevel(LogLevel level); 22 | 23 | public void setMaskSecrets(boolean isMaskSecrets); 24 | 25 | public void trace(String text); 26 | 27 | public void warning(String text); 28 | 29 | public void warning(String message, Throwable exception); 30 | } 31 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementDisabled.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.CustomConditions; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | public class AssertElementDisabled extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | 14 | super.run(); 15 | 16 | By locator = this.readLocatorArgument("locator"); 17 | 18 | this.waitForAsyncCallsToFinish(); 19 | 20 | WebElement element = this.getElement(locator); 21 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 22 | wait.until(CustomConditions.elementToBeDisabled(element)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementEnabled.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.CustomConditions; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | public class AssertElementEnabled extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | 14 | super.run(); 15 | 16 | By locator = this.readLocatorArgument("locator"); 17 | 18 | this.waitForAsyncCallsToFinish(); 19 | 20 | WebElement element = this.getElement(locator); 21 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 22 | wait.until(CustomConditions.elementToBeEnabled(element)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/serialization/AppiumDriverSerializer.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.serialization; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonObject; 5 | import com.google.gson.JsonSerializationContext; 6 | import com.google.gson.JsonSerializer; 7 | import io.appium.java_client.AppiumDriver; 8 | 9 | public class AppiumDriverSerializer implements JsonSerializer { 10 | 11 | public AppiumDriverSerializer() { 12 | super(); 13 | } 14 | 15 | @Override 16 | public JsonElement serialize(AppiumDriver src, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) { 17 | JsonObject jsonObject = new JsonObject(); 18 | // TODO: Add all the relevant properties here 19 | jsonObject.addProperty("class", "AppiumDriver"); 20 | return jsonObject; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsSendKeys.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.Keys; 5 | 6 | public class ActionsSendKeys extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | String text = this.readStringArgument("text", null); 13 | String key = this.readStringArgument("key", null); 14 | 15 | if (text != null) { 16 | SeleniumTestAction.getActionsInstance().sendKeys(text); 17 | } else if (key != null) { 18 | SeleniumTestAction.getActionsInstance().sendKeys(Keys.valueOf(key.toUpperCase())); 19 | } else { 20 | throw new RuntimeException("Neither the \"text\" argument, nor the \"key\" argument were provided."); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ActionsPerform.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.appium.core.AppiumTestAction; 5 | 6 | @TestActionClass( 7 | description = "Performs the chain of gestures that was specified so far using the set " 8 | + "of keywords prefixed with \"Actions\". As soon as this action executes, a new chain " 9 | + "of actions can be built in the same way.") 10 | 11 | public class ActionsPerform extends AppiumTestAction { 12 | 13 | @Override 14 | public void run() { 15 | super.run(); 16 | 17 | try { 18 | AppiumTestAction.getActionsInstance().perform(); 19 | } catch (Exception ex) { 20 | throw ex; 21 | } finally { 22 | AppiumTestAction.discardActionsObject(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/serialization/json/BufferedImageSerializer.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.serialization.json; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonPrimitive; 5 | import com.google.gson.JsonSerializationContext; 6 | import com.google.gson.JsonSerializer; 7 | import java.awt.image.BufferedImage; 8 | 9 | public class BufferedImageSerializer implements JsonSerializer { 10 | 11 | public BufferedImageSerializer() { 12 | super(); 13 | } 14 | 15 | @Override 16 | public JsonElement serialize(BufferedImage src, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) { 17 | JsonPrimitive jsonString = new JsonPrimitive(String.format( 18 | "\"Image, res: %s x %s\"", 19 | src.getWidth(), 20 | src.getHeight())); 21 | return jsonString; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementNotReadOnly.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class AssertElementNotReadOnly extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | 12 | super.run(); 13 | 14 | By locator = this.readLocatorArgument("locator"); 15 | 16 | this.waitForAsyncCallsToFinish(); 17 | 18 | WebElement element = this.getElement(locator); 19 | String readonly = element.getAttribute("readonly"); 20 | if (readonly != null) { 21 | throw new RuntimeException(String.format( 22 | "Assertion failed: the \"readonly\" attribute was set on element %s", 23 | locator)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementReadOnly.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class AssertElementReadOnly extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | 12 | super.run(); 13 | 14 | By locator = this.readLocatorArgument("locator"); 15 | 16 | this.waitForAsyncCallsToFinish(); 17 | 18 | WebElement element = this.getElement(locator); 19 | String readonly = element.getAttribute("readonly"); 20 | if (readonly == null) { 21 | throw new RuntimeException(String.format( 22 | "Assertion failed: the \"readonly\" attribute was not set on element %s", 23 | locator)); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadElementAttribute.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class ReadElementAttribute extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | By locator = this.readLocatorArgument("locator"); 13 | String attribute = this.readStringArgument("attribute"); 14 | 15 | this.waitForAsyncCallsToFinish(); 16 | 17 | String attributeValue = this.getElement(locator).getAttribute(attribute); 18 | 19 | this.writeOutput("text", attributeValue); 20 | 21 | // The output "value" is deprecated in favor of "text", 22 | // and will eventually be removed 23 | this.writeOutput("value", attributeValue); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/visual/ImageFinderResult.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.visual; 2 | 3 | import java.awt.Rectangle; 4 | 5 | /** 6 | * Stores the found rectangle and the accuracy of an image find operation. 7 | */ 8 | public class ImageFinderResult { 9 | 10 | private double accuracy; 11 | 12 | private Rectangle foundRect; 13 | 14 | public ImageFinderResult(Rectangle foundRect, double accuracy) { 15 | this.foundRect = foundRect; 16 | this.accuracy = accuracy; 17 | } 18 | 19 | /** 20 | * Returns the accuracy of the image find operation, as a number between 0 21 | * and 1. 22 | */ 23 | public double getAccuracy() { 24 | return accuracy; 25 | } 26 | 27 | /** 28 | * Returns the rectangle where a template image was found in a source image. 29 | */ 30 | public Rectangle getFoundRect() { 31 | return foundRect; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsMoveTo.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class ActionsMoveTo extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | By locator = this.readLocatorArgument("locator"); 14 | Integer xOffset = this.readIntArgument("xOffset", null); 15 | Integer yOffset = this.readIntArgument("yOffset", null); 16 | 17 | WebElement element = this.getElement(locator); 18 | 19 | if (xOffset != null && yOffset != null) { 20 | SeleniumTestAction.getActionsInstance().moveToElement(element, xOffset, yOffset); 21 | } else { 22 | SeleniumTestAction.getActionsInstance().moveToElement(element); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server/src/public/img/tricolon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | image/svg+xml 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/Assert.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | import org.getopentest.base.TestAction; 4 | import org.getopentest.util.TypeConverter; 5 | 6 | /** 7 | * An action that fails the current test. 8 | */ 9 | public class Assert extends TestAction { 10 | 11 | @Override 12 | public void run() { 13 | String condition = this.readStringArgument("condition"); 14 | String failMessage = this.readStringArgument("failMessage", "Assertion failed"); 15 | String passMessage = this.readStringArgument("passMessage"); 16 | 17 | Boolean conditionResult = TypeConverter.toBooolean(this.getActor().evalScript(condition)); 18 | if (!conditionResult) { 19 | throw new RuntimeException(failMessage); 20 | } else { 21 | if (passMessage != null) { 22 | this.log.info(passMessage); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementHasAttribute.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.CustomConditions; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | public class AssertElementHasAttribute extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | String attribute = this.readStringArgument("attribute"); 17 | 18 | this.waitForAsyncCallsToFinish(); 19 | 20 | WebElement element = this.getElement(locator); 21 | 22 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 23 | wait.until(CustomConditions.elementAttributeToBePresent(element, attribute)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Handle line endings automatically for files detected as text 2 | # and leave all files detected as binary untouched. 3 | * text=auto 4 | 5 | # These files are text and should be normalized (Convert crlf => lf) 6 | *.css text 7 | *.htm text 8 | *.html text 9 | *.java text 10 | *.js text 11 | *.json text 12 | *.properties text 13 | *.sh text 14 | *.tld text 15 | *.ts text 16 | *.txt text 17 | *.xml text 18 | *.yml text 19 | *.yaml text 20 | 21 | # These files are binary and should be left untouched 22 | # (binary is a macro for -text -diff) 23 | *.class binary 24 | *.dll binary 25 | *.ear binary 26 | *.gif binary 27 | *.ico binary 28 | *.jar binary 29 | *.jpg binary 30 | *.jpeg binary 31 | *.png binary 32 | *.so binary 33 | *.war binary 34 | 35 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadBrowserLogs.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import org.getopentest.selenium.core.SeleniumTestAction; 6 | import org.openqa.selenium.UnsupportedCommandException; 7 | import org.openqa.selenium.logging.LogEntry; 8 | 9 | public class ReadBrowserLogs extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | this.waitForAsyncCallsToFinish(); 14 | 15 | try { 16 | List logEntries = driver.manage().logs().get("browser").getAll(); 17 | this.writeOutput("entries", this.getActor().toJsArray(logEntries)); 18 | } catch (UnsupportedCommandException exc) { 19 | // Some browsers don't implement the logging API. If so, we'll just 20 | // return an empty array. 21 | this.writeOutput("entries", this.getActor().toJsArray(new ArrayList())); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AddCookie.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.Cookie; 6 | 7 | @TestActionClass(description = "Adds a cookie.") 8 | 9 | public class AddCookie extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | super.run(); 14 | 15 | String name = this.readStringArgument("name"); 16 | String value = this.readStringArgument("value"); 17 | String domain = this.readStringArgument("domain", null); 18 | String path = this.readStringArgument("path", null); 19 | Boolean isSecure = this.readBooleanArgument("isSecure", false); 20 | Boolean isHttpOnly = this.readBooleanArgument("isHttpOnly", false); 21 | 22 | Cookie cookie = new Cookie(name, value, domain, path, null, isSecure, isHttpOnly); 23 | driver.manage().addCookie(cookie); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/core/WaitingAction.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.core; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.Type; 5 | 6 | @TestActionArgument(name = "explicitWaitSec", type = Type.INTEGER, optional = true, 7 | description = "The time to wait for a conditon to be realized (e.g. an element to " 8 | + "become visible, an element's attribute to take a certain value, etc), in seconds.") 9 | /** 10 | * Base class for actions that need the ability to read the explicit wait 11 | * argument. 12 | */ 13 | public abstract class WaitingAction extends AppiumTestAction { 14 | 15 | /** 16 | * Returns the number of seconds provided in the explicitWaitSec argument, 17 | * or the default value specified in the appium.explicitWaitSec config 18 | * parameter. 19 | */ 20 | public int getExplicitWait() { 21 | return this.readIntArgument("explicitWaitSec", AppiumHelper.getExplicitWaitSec()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/SwitchToFrame.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.appium.core.AppiumTestAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class SwitchToFrame extends AppiumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | String frameName = this.readStringArgument("frameName", null); 11 | By locator = this.readLocatorArgument("locator", null); 12 | Integer frameIndex = this.readIntArgument("frameIndex", null); 13 | 14 | if (frameName != null) { 15 | this.driver.switchTo().frame(frameName); 16 | } else if (locator != null) { 17 | this.driver.switchTo().frame(this.getElement(locator)); 18 | } else if (frameIndex != null) { 19 | this.driver.switchTo().frame(frameIndex); 20 | } else { 21 | throw new RuntimeException( 22 | "You must provide at least one of the following arguments: frameName, locator, frameIndex."); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/util/MainUtil.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import org.getopentest.logging.Logger; 4 | import java.io.File; 5 | import java.security.CodeSource; 6 | 7 | public class MainUtil { 8 | public static Class getMainClass() throws ClassNotFoundException { 9 | StackTraceElement[] elements = new Exception().getStackTrace(); 10 | return Class.forName(elements[elements.length - 1].getClassName()); 11 | } 12 | 13 | public static File getMainJar() { 14 | try { 15 | Class mainClass = getMainClass(); 16 | 17 | CodeSource codeSource = mainClass.getProtectionDomain().getCodeSource(); 18 | File jarFile = new File(codeSource.getLocation().toURI().getPath()); 19 | Logger.trace(String.format("The main JAR file is %s", jarFile.getCanonicalPath())); 20 | 21 | return jarFile; 22 | } catch (Exception ex) { 23 | throw new RuntimeException("Could not locate main JAR file", ex); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SwitchToLastWindow.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.getopentest.logging.Logger; 5 | 6 | public class SwitchToLastWindow extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | this.waitForAsyncCallsToFinish(); 13 | 14 | String[] windowHandles = driver.getWindowHandles().stream() 15 | .toArray(String[]::new); 16 | 17 | try { 18 | driver.switchTo().window(windowHandles[windowHandles.length - 1]); 19 | 20 | Logger.info(String.format( 21 | "Successfully switched to last window (number %s)", 22 | windowHandles.length)); 23 | } catch (Exception ex) { 24 | throw new RuntimeException(String.format( 25 | "Failed to switch to last window (number %s)", 26 | windowHandles.length), ex); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/core/SwipingWaitingAction.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.core; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.Type; 5 | 6 | @TestActionArgument(name = "explicitWaitSec", type = Type.INTEGER, optional = true, 7 | description = "The time to wait for a conditon to be realized (e.g. an element to " 8 | + "become visible, an element's attribute to take a certain value, etc), in seconds.") 9 | /** 10 | * Base class for actions that need the ability to read both swipe-related 11 | * arguments and the explicit wait argument. 12 | */ 13 | public abstract class SwipingWaitingAction extends SwipingAction { 14 | 15 | /** 16 | * Returns the number of seconds provided in the explicitWaitSec argument, 17 | * or the default value specified in the appium.explicitWaitSec config 18 | * parameter. 19 | */ 20 | public int getExplicitWaitSec() { 21 | return this.readIntArgument("explicitWaitSec", AppiumHelper.getExplicitWaitSec()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/core/CustomConditions.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.core; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.openqa.selenium.WebDriver; 5 | import org.openqa.selenium.support.ui.ExpectedCondition; 6 | 7 | public class CustomConditions { 8 | 9 | /** 10 | * Returns an ExpectedCondition instance to check whether an element's 11 | * attribute is equal to the specified value. 12 | */ 13 | public static ExpectedCondition attributeValueToBe(MobileElement element, String attribute, String value) { 14 | return new ExpectedCondition() { 15 | @Override 16 | public Boolean apply(WebDriver driver) { 17 | return element.getAttribute(attribute).equals(value); 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return String.format("attribute %s to be equal to %s for element %s", 23 | attribute, value, element.toString()); 24 | } 25 | }; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /actor/base/nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | JDK_1.8 17 | 18 | 19 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/Format.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | import org.getopentest.base.TestAction; 6 | 7 | /** 8 | * Builds a string, starting from an initial template that interpolates JS 9 | * expressions and substituting the expressions with their evaluated result. 10 | */ 11 | public class Format extends TestAction { 12 | 13 | @Override 14 | public void run() { 15 | super.run(); 16 | 17 | String template = this.readStringArgument("template"); 18 | 19 | Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); 20 | Matcher matcher = pattern.matcher(template); 21 | StringBuffer sb = new StringBuffer(template.length()); 22 | while (matcher.find()) { 23 | String text = matcher.group(1); 24 | matcher.appendReplacement(sb, Matcher.quoteReplacement(this.getActor().evalScript(text).toString())); 25 | } 26 | matcher.appendTail(sb); 27 | 28 | this.writeOutput("text", sb.toString()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/logging/ConsoleLogger.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.logging; 2 | 3 | import java.time.Instant; 4 | import java.time.LocalTime; 5 | import java.time.ZoneId; 6 | import java.time.format.DateTimeFormatter; 7 | 8 | /** 9 | * A logger that outputs to the console. 10 | */ 11 | public class ConsoleLogger extends BaseLogger { 12 | 13 | @Override 14 | protected void writeLogEntry(String text, org.getopentest.logging.LogLevel level, Instant timestamp) { 15 | if (timestamp == null) { 16 | timestamp = Instant.now(); 17 | } 18 | 19 | if (text != null && !text.isEmpty()) { 20 | DateTimeFormatter isoTimeFormatter = DateTimeFormatter.ofPattern("HH.mm.ss"); 21 | String timeOfLogEntry = LocalTime.from(timestamp.atZone(ZoneId.systemDefault())).format(isoTimeFormatter); 22 | String message = String.format("%s %s%s", timeOfLogEntry, getPrefixForLevel(level), text); 23 | System.out.println(message); 24 | } else { 25 | System.out.println(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementFocused.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.CustomConditions; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | public class AssertElementFocused extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | 14 | super.run(); 15 | 16 | By locator = this.readLocatorArgument("locator"); 17 | Boolean negate = this.readBooleanArgument("negate", Boolean.FALSE); 18 | 19 | this.waitForAsyncCallsToFinish(); 20 | 21 | WebElement element = this.getElement(locator); 22 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 23 | 24 | if (!negate) { 25 | wait.until(CustomConditions.elementToBeActive(element)); 26 | } else { 27 | wait.until(CustomConditions.elementToNotBeActive(element)); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/util/ServerRequest.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import org.getopentest.http.HttpRequest; 4 | import org.getopentest.http.HttpRequestOptions; 5 | 6 | /** 7 | * HTTP request to the OpenTest server that is automatically configured as per 8 | * the passed-in Config instance for proxy, authentication, etc. 9 | */ 10 | public class ServerRequest extends HttpRequest { 11 | 12 | public ServerRequest(HttpRequestOptions options, Config config) { 13 | super(options); 14 | 15 | // Set HTTP basic auth, if credentials present in config 16 | String serverLogin = config.getString("serverLogin", null); 17 | if (serverLogin != null) { 18 | String serverPassword = config.getString("serverPassword", null); 19 | if (serverPassword != null) { 20 | this.setBasicAuth(serverLogin, serverPassword); 21 | } 22 | } 23 | 24 | String httpProxy = config.getString("httpProxy", null); 25 | if (httpProxy != null) { 26 | this.setProxy(httpProxy); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2017, McDonald's Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to use, 8 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 9 | Software, and to permit persons to whom the Software is furnished to do so, subject 10 | to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 16 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 17 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 18 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/http/HttpRequestOptions.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.http; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import org.getopentest.contracts.ILogger; 6 | 7 | public class HttpRequestOptions { 8 | 9 | public String basicAuthLogin; 10 | 11 | public String basicAuthPassword; 12 | 13 | public String clientCertificate; 14 | 15 | public String clientCertificatePassword; 16 | 17 | public Map headers; 18 | 19 | public boolean ignoreCert; 20 | 21 | public ILogger logger; 22 | 23 | public HttpVerb httpVerb; 24 | 25 | public String proxy; 26 | 27 | public String url; 28 | 29 | public HttpRequestOptions(String url, HttpVerb httpVerb) { 30 | this.basicAuthLogin = null; 31 | this.basicAuthPassword = null; 32 | this.clientCertificate = null; 33 | this.clientCertificatePassword = null; 34 | this.url = url; 35 | this.httpVerb = httpVerb; 36 | this.logger = null; 37 | this.proxy = null; 38 | this.headers = new HashMap<>(); 39 | this.ignoreCert = false; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opentest-master", 3 | "version": "1.4.2", 4 | "description": "Functional test automation framework for web, mobile and REST APIs", 5 | "author": "Adrian Theodorescu", 6 | "homepage": "https://getopentest.org/", 7 | "license": "MIT", 8 | "private": true, 9 | "scripts": { 10 | "build": "npm-run-all pull-projects build-projects make-modules", 11 | "pull-projects": "node build/tasks/pull-projects.js", 12 | "build-projects": "node build/tasks/build-projects.js", 13 | "make-modules": "node build/tasks/make-modules.js", 14 | "package": "node build/tasks/package.js", 15 | "publish-local": "node build/tasks/publish-modules.js --registry http://localhost:4873 --tag=latest", 16 | "publish-npm-beta": "node build/tasks/publish-modules.js --tag beta --registry https://registry.npmjs.org", 17 | "publish-npm-latest": "node build/tasks/publish-modules.js --tag=latest --registry https://registry.npmjs.org", 18 | "update-version": "node build/tasks/update-version.js" 19 | }, 20 | "dependencies": { 21 | "npm-run-all": "^4.1.1", 22 | "shelljs": "^0.8.4", 23 | "yargs": "^15.1.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/ReadScreenSize.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionClass; 4 | import org.getopentest.annotations.TestActionOutput; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.appium.core.SwipingAction; 7 | import org.openqa.selenium.Dimension; 8 | 9 | @TestActionClass( 10 | description = "Reads the screen size of the device we are currently running on.") 11 | @TestActionOutput(name = "width", type = Type.INTEGER, 12 | description = "The width of the screen.") 13 | @TestActionOutput(name = "height", type = Type.INTEGER, 14 | description = "The height of the screen.") 15 | 16 | /** 17 | * Reads the screen size of the device we are currently running on. 18 | */ 19 | public class ReadScreenSize extends SwipingAction { 20 | 21 | @Override 22 | public void run() { 23 | super.run(); 24 | 25 | Dimension screenSize = screenSize = driver.manage().window().getSize(); 26 | 27 | this.writeOutput("screenWidth", screenSize.width); 28 | this.writeOutput("screenHeight", screenSize.height); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SwitchToFrame.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | 6 | public class SwitchToFrame extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | String frameName = this.readStringArgument("frameName", null); 13 | By locator = this.readLocatorArgument("locator", null); 14 | Integer frameIndex = this.readIntArgument("frameIndex", null); 15 | 16 | this.waitForAsyncCallsToFinish(); 17 | 18 | if (frameName != null) { 19 | this.driver.switchTo().frame(frameName); 20 | } else if (locator != null) { 21 | this.driver.switchTo().frame(this.getElement(locator)); 22 | } else if (frameIndex != null) { 23 | this.driver.switchTo().frame(frameIndex); 24 | } else { 25 | throw new RuntimeException( 26 | "You must provide at least one of the following arguments: frameName, locator, frameIndex."); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/SampleAction.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | import org.getopentest.base.TestAction; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.InputStream; 8 | 9 | /** 10 | * A sample action. 11 | */ 12 | public class SampleAction extends TestAction { 13 | // Override the "initialize" method to do execute any initialization logi 14 | // that needs to happen before the action is ran, but after the action's 15 | // arguments have been populated 16 | @Override 17 | public void initialize() { 18 | // Nothing to do here for now 19 | } 20 | 21 | @Override 22 | public void run() { 23 | super.run(); 24 | 25 | String arg1 = readStringArgument("arg1", ""); 26 | this.writeOutput("out1", "*** " + arg1 + " ***"); 27 | } 28 | 29 | @Override 30 | public InputStream takeScreenshot() { 31 | try { 32 | return new FileInputStream(new File("test-image.png")); 33 | } catch (FileNotFoundException ex) { 34 | return null; 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementNotVisible.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.appium.core.Condition; 7 | import org.getopentest.appium.core.SwipeOptions; 8 | import org.getopentest.appium.core.SwipingAction; 9 | import org.openqa.selenium.By; 10 | 11 | @TestActionClass( 12 | description = "Verifies that a UI element is not currently visible.") 13 | @TestActionArgument(name = "locator", type = Type.MAP, optional = false, 14 | description = "The locator of the UI element.") 15 | 16 | /** 17 | * Verifies that a UI element is currently not visible. 18 | */ 19 | public class AssertElementNotVisible extends SwipingAction { 20 | 21 | @Override 22 | public void run() { 23 | By locator = this.readLocatorArgument("locator"); 24 | 25 | SwipeOptions options = this.getSwipeOptions(); 26 | options.targetElement = locator; 27 | options.condition = Condition.INVISIBILITY; 28 | 29 | this.swipe(options); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementPresent.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.appium.core.Condition; 7 | import org.getopentest.appium.core.SwipeOptions; 8 | import org.getopentest.appium.core.SwipingAction; 9 | import org.openqa.selenium.By; 10 | 11 | @TestActionClass( 12 | description = "Verifies that a UI element is currently present.") 13 | @TestActionArgument(name = "locator", type = Type.MAP, optional = false, 14 | description = "The locator of the UI element.") 15 | 16 | /** 17 | * Verifies that a UI element is currently present. 18 | */ 19 | public class AssertElementPresent extends SwipingAction { 20 | 21 | @Override 22 | public void run() { 23 | super.run(); 24 | 25 | By locator = this.readLocatorArgument("locator"); 26 | 27 | SwipeOptions options = this.getSwipeOptions(); 28 | options.targetElement = locator; 29 | options.condition = Condition.PRESENCE; 30 | 31 | this.swipe(options); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertCssProperty.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class AssertCssProperty extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | By locator = this.readLocatorArgument("locator"); 14 | String property = this.readStringArgument("property", null); 15 | String expectedValue = this.readStringArgument("value", null); 16 | 17 | this.waitForAsyncCallsToFinish(); 18 | 19 | WebElement element = this.getElement(locator); 20 | 21 | String actualValue = element.getCssValue(property); 22 | 23 | if (!actualValue.equals(expectedValue)) { 24 | throw new RuntimeException(String.format( 25 | "Assertion failed for CSS property %s of element %s. Expected value: %s. Actual value: %s.", 26 | property, 27 | locator, 28 | expectedValue, 29 | actualValue)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/src/lib/constants.ts: -------------------------------------------------------------------------------- 1 | export let error = { 2 | /** No tests were found that match the provided criteria. */ 3 | NO_MATCHING_TESTS: 'no-matching-tests' 4 | } 5 | 6 | export let testSessionStatus = { 7 | ACQUIRING_ACTORS: 'acquiring-actors', 8 | COMPLETED: 'completed', 9 | STARTED: 'started' 10 | }; 11 | 12 | export let testSessionResult = { 13 | CANCELLED: 'cancelled', 14 | FAILED: 'failed', 15 | PASSED: 'passed', 16 | PENDING: 'pending' 17 | }; 18 | 19 | export let segmentStatus = { 20 | COMPLETED: 'completed', 21 | PENDING: 'pending', 22 | STARTED: 'started' 23 | }; 24 | 25 | export let segmentResult = { 26 | FAILED: 'failed', 27 | PASSED: 'passed', 28 | PENDING: 'pending', 29 | SKIPPED: 'skipped' 30 | }; 31 | 32 | export let testStatus = { 33 | COMPLETED: 'completed', 34 | PENDING: 'pending', 35 | STARTED: 'started' 36 | }; 37 | 38 | export let testResult = { 39 | CANCELLED: 'cancelled', 40 | FAILED: 'failed', 41 | PASSED: 'passed', 42 | PENDING: 'pending', 43 | SKIPPED: 'skipped' 44 | }; 45 | 46 | export let actionResult = { 47 | FAILED: 'failed', 48 | PASSED: 'passed', 49 | SKIPPED: 'skipped' 50 | }; -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/base/ScriptAction.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.function.BiConsumer; 6 | 7 | /** 8 | * Represents the action that corresponds to the "script" node in an actions 9 | * list. 10 | */ 11 | public class ScriptAction extends TestAction { 12 | 13 | private TestActor actor; 14 | 15 | private String script; 16 | 17 | public ScriptAction(TestActor actor, String script) { 18 | this.actor = actor; 19 | this.script = script; 20 | } 21 | 22 | @Override 23 | public void run() { 24 | Map scriptOutput = new HashMap<>(); 25 | actor.injectVariable("$writeOutput", new BiConsumer() { 26 | @Override 27 | public void accept(String outputName, Object outputValue) { 28 | scriptOutput.put(outputName, outputValue); 29 | } 30 | }); 31 | 32 | actor.evalScript(script); 33 | 34 | for (Map.Entry entry : scriptOutput.entrySet()) { 35 | this.writeOutput(entry.getKey(), entry.getValue()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /actor/base/src/test/java/org/getopentest/util/StringUtilNGTest.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import org.getopentest.util.StringUtil; 4 | import java.util.regex.Matcher; 5 | import static org.testng.Assert.*; 6 | import org.testng.annotations.Test; 7 | 8 | public class StringUtilNGTest { 9 | 10 | @Test 11 | public void testExecuteRegex() { 12 | String text = "prefix-content-suffix"; 13 | Matcher matcher = StringUtil.executeRegex(text, "^(.+)-(.+)-(.+)$"); 14 | assertEquals(matcher.groupCount(), 3); 15 | assertEquals(matcher.group(1), "prefix"); 16 | assertEquals(matcher.group(2), "content"); 17 | assertEquals(matcher.group(3), "suffix"); 18 | } 19 | 20 | @Test 21 | public void testSubstringByRegexWithGroup() { 22 | String text = "prefix-content-suffix"; 23 | String prefix = StringUtil.substringByRegex(text, "^([^-]+)"); 24 | assertEquals(prefix, "prefix"); 25 | } 26 | 27 | @Test 28 | public void testSubstringByRegexWithoutGroup() { 29 | String text = "prefix-content-suffix"; 30 | String prefix = StringUtil.substringByRegex(text, "^[^-]+"); 31 | assertEquals(prefix, "prefix"); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/src/lib/log-manager.ts: -------------------------------------------------------------------------------- 1 | import * as Logger from 'bunyan'; 2 | import * as dirs from '../lib/dirs'; 3 | import * as mkdirp from 'mkdirp'; 4 | import * as path from 'path'; 5 | import * as _ from 'underscore'; 6 | 7 | var appLog = Logger.createLogger({ name: 'app' }); 8 | var sessionLogs = {}; 9 | 10 | export function getSessionLog(sessionId: any): Logger { 11 | // Ensure the "logs" directory exists 12 | mkdirp.sync(path.join(dirs.workingDir(), 'logs')); 13 | 14 | let log; 15 | sessionId = sessionId.toString(); 16 | 17 | if (!sessionLogs[sessionId]) { 18 | log = Logger.createLogger({ 19 | name: sessionId, 20 | streams: [{ 21 | level: 'trace', 22 | path: path.join(dirs.workingDir(), 'logs', sessionId + '.log') 23 | }] 24 | }); 25 | sessionLogs[sessionId] = log; 26 | } else { 27 | log = sessionLogs[sessionId]; 28 | } 29 | 30 | // Provide a method for clients to flush the write 31 | // stream to ensure all data was persisted 32 | log.flushStreams = _.debounce( 33 | log.reopenFileStreams.bind(log), 34 | 5000, 35 | true 36 | ); 37 | 38 | return log; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /server/src/test/unit/helpers.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | import * as helpers from '../../lib/helpers'; 3 | 4 | describe('helpers module', function () { 5 | it('format should support object variable', function () { 6 | let objectString = helpers.format('pre {0} post', { foo: 1, bar: "abc" }); 7 | assert.equal(objectString, 'pre {"foo":1,"bar":"abc"} post'); 8 | }); 9 | 10 | it('format should support string variable', function () { 11 | let objectString = helpers.format('pre {0} post', 'abc'); 12 | assert.equal(objectString, 'pre abc post'); 13 | }); 14 | 15 | it('format should support number variable', function () { 16 | let objectString = helpers.format('pre {0} post', 123); 17 | assert.equal(objectString, 'pre 123 post'); 18 | }); 19 | 20 | it('format should support boolean variable', function () { 21 | let objectString = helpers.format('pre {0} post', true); 22 | assert.equal(objectString, 'pre true post'); 23 | }); 24 | 25 | it('format should support undefined variable', function () { 26 | let objectString = helpers.format('pre {0} post'); 27 | assert.equal(objectString, 'pre {0} post'); 28 | }); 29 | }); -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/contracts/IImageFinder.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.contracts; 2 | 3 | import org.getopentest.visual.ImageFinderResult; 4 | import org.getopentest.visual.MatchingMethod; 5 | import java.awt.Rectangle; 6 | import java.awt.image.BufferedImage; 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | public interface IImageFinder { 11 | 12 | ImageFinderResult findImage(Rectangle sourceScreenRect, BufferedImage templateImage, double desiredAccuracy); 13 | 14 | /** 15 | * Find one of multiple template images in the source image. 16 | */ 17 | ImageFinderResult findAnyImage(BufferedImage sourceImage, Rectangle sourceRect, List templateImages, double desiredAccuracy); 18 | 19 | ImageFinderResult findImage(BufferedImage sourceImage, Rectangle sourceRect, BufferedImage templateImage, double desiredAccuracy); 20 | 21 | ImageFinderResult findImage(File sourceImage, File templateImage, double desiredAccuracy); 22 | 23 | ImageFinderResult findImage(Rectangle sourceScreenRect, File templateImage, double desiredAccuracy); 24 | 25 | public MatchingMethod getMatchingMethod(); 26 | 27 | public void setMatchingMethod(MatchingMethod matchingMethod); 28 | } 29 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/util/ImageCompareResult.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import java.awt.image.BufferedImage; 4 | 5 | /** 6 | * Stores the result of an image compare operation. 7 | */ 8 | public class ImageCompareResult { 9 | 10 | private BufferedImage diffImage; 11 | 12 | private long diffPixelCount = 0; 13 | 14 | private double similarity; 15 | 16 | public ImageCompareResult(BufferedImage diffImage, double similarity, long diffPixelCount) { 17 | this.diffImage = diffImage; 18 | this.similarity = similarity; 19 | this.diffPixelCount = diffPixelCount; 20 | } 21 | 22 | /** 23 | * Returns the similarity between two images as a percent. 24 | */ 25 | public double getSimilarity() { 26 | return similarity; 27 | } 28 | 29 | /** 30 | * Returns an image highlighting the differences between the two source 31 | * images. 32 | */ 33 | public BufferedImage getDiffImage() { 34 | return diffImage; 35 | } 36 | 37 | /** 38 | * Returns the number of pixels that were different between the two images. 39 | */ 40 | public long getDiffPixelCount() { 41 | return diffPixelCount; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /server/src/lib/file-walker.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import * as path from 'path'; 3 | import * as thenify from 'thenify'; 4 | 5 | const readdir = thenify(fs.readdir); 6 | const stat = thenify(fs.stat); 7 | 8 | /** Walk a directory recursively and call a callback function for each file or directory found. */ 9 | export async function walkRecursive( 10 | rootDirPath: string, 11 | callback: (parentDirName: string, fileName: string, fileStats: fs.Stats) => void): Promise { 12 | 13 | return new Promise(async function (resolve, reject) { 14 | try { 15 | const files: string[] = await readdir(rootDirPath); 16 | 17 | for (let file of files) { 18 | try { 19 | const fileFullPath = path.join(rootDirPath, file); 20 | const fileStats = await stat(fileFullPath); 21 | await callback(rootDirPath, file, fileStats); 22 | 23 | if (fileStats.isDirectory()) { 24 | await walkRecursive(fileFullPath, callback); 25 | } 26 | } catch { } 27 | } 28 | 29 | resolve(); 30 | } catch (err) { 31 | reject(err); 32 | } 33 | }); 34 | } -------------------------------------------------------------------------------- /actor/appium/.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | 12 | # Eclipse 13 | .metadata 14 | bin/ 15 | tmp/ 16 | *.tmp 17 | *.bak 18 | *.swp 19 | *~.nib 20 | local.properties 21 | .settings/ 22 | .loadpath 23 | .recommenders 24 | 25 | # Eclipse Core 26 | .project 27 | 28 | # External tool builders 29 | .externalToolBuilders/ 30 | 31 | # Locally stored "Eclipse launch configurations" 32 | *.launch 33 | 34 | # PyDev specific (Python IDE for Eclipse) 35 | *.pydevproject 36 | 37 | # CDT-specific (C/C++ Development Tooling) 38 | .cproject 39 | 40 | # JDT-specific (Eclipse Java Development Tools) 41 | .classpath 42 | 43 | # Java annotation processor (APT) 44 | .factorypath 45 | 46 | # PDT-specific (PHP Development Tools) 47 | .buildpath 48 | 49 | # sbteclipse plugin 50 | .target 51 | 52 | # Tern plugin 53 | .tern-project 54 | 55 | # TeXlipse plugin 56 | .texlipse 57 | 58 | # STS (Spring Tool Suite) 59 | .springBeans 60 | 61 | # Code Recommenders 62 | .recommenders/ 63 | 64 | #NetBeans 65 | nbproject/private/ 66 | build/ 67 | nbbuild/ 68 | dist/ 69 | nbdist/ 70 | nbactions.xml 71 | .nb-gradle/ -------------------------------------------------------------------------------- /actor/base/.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | 12 | # Eclipse 13 | .metadata 14 | bin/ 15 | tmp/ 16 | *.tmp 17 | *.bak 18 | *.swp 19 | *~.nib 20 | local.properties 21 | .settings/ 22 | .loadpath 23 | .recommenders 24 | 25 | # Eclipse Core 26 | .project 27 | 28 | # External tool builders 29 | .externalToolBuilders/ 30 | 31 | # Locally stored "Eclipse launch configurations" 32 | *.launch 33 | 34 | # PyDev specific (Python IDE for Eclipse) 35 | *.pydevproject 36 | 37 | # CDT-specific (C/C++ Development Tooling) 38 | .cproject 39 | 40 | # JDT-specific (Eclipse Java Development Tools) 41 | .classpath 42 | 43 | # Java annotation processor (APT) 44 | .factorypath 45 | 46 | # PDT-specific (PHP Development Tools) 47 | .buildpath 48 | 49 | # sbteclipse plugin 50 | .target 51 | 52 | # Tern plugin 53 | .tern-project 54 | 55 | # TeXlipse plugin 56 | .texlipse 57 | 58 | # STS (Spring Tool Suite) 59 | .springBeans 60 | 61 | # Code Recommenders 62 | .recommenders/ 63 | 64 | #NetBeans 65 | nbproject/private/ 66 | build/ 67 | nbbuild/ 68 | dist/ 69 | nbdist/ 70 | nbactions.xml 71 | .nb-gradle/ -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementNotEnabled.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.getopentest.annotations.TestActionArgument; 5 | import org.getopentest.annotations.TestActionClass; 6 | import org.getopentest.annotations.Type; 7 | import org.getopentest.appium.core.SwipingAction; 8 | import org.openqa.selenium.By; 9 | 10 | @TestActionClass( 11 | description = "Verifies that a UI element is not enabled.") 12 | @TestActionArgument(name = "locator", type = Type.STRING, optional = false, 13 | description = "The locator of the UI element.") 14 | 15 | /** 16 | * Verifies that a UI element is not enabled. 17 | */ 18 | public class AssertElementNotEnabled extends SwipingAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator"); 25 | 26 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 27 | 28 | MobileElement element = this.getElement(locator); 29 | 30 | if (element.isEnabled()) { 31 | throw new RuntimeException(String.format( 32 | "Element %s was enabled", locator)); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementVisible.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.appium.core.SwipingAction; 7 | import org.openqa.selenium.By; 8 | 9 | @TestActionClass( 10 | description = "Verifies that a UI element is currently visible.") 11 | @TestActionArgument(name = "locator", type = Type.MAP, optional = false, 12 | description = "The locator of the UI element.") 13 | @TestActionArgument(name = "direction", type = Type.STRING, optional = true, 14 | description = "Specifies whether the test actor should perform swipe" 15 | + " gestures to find the element in case it is not currently visible." 16 | + " Valid values are: up, down, left, right.") 17 | 18 | /** 19 | * Verifies that a UI element is currently visible. 20 | */ 21 | public class AssertElementVisible extends SwipingAction { 22 | 23 | @Override 24 | public void run() { 25 | super.run(); 26 | 27 | By locator = this.readLocatorArgument("locator"); 28 | 29 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/node_modules": true, 4 | "dist": true, 5 | "coverage": true, 6 | "**/logs": true 7 | }, 8 | "cSpell.words": [ 9 | "autocompaction", 10 | "autoload", 11 | "bgcolor", 12 | "classname", 13 | "datafile", 14 | "datastore", 15 | "ekko", 16 | "junit", 17 | "lightbox", 18 | "originalname", 19 | "prepend", 20 | "subtest", 21 | "testcase", 22 | "testsuite", 23 | "unannounce", 24 | "xmlbuilder" 25 | ], 26 | "cSpell.enabledLanguageIds": [ 27 | "asciidoc", 28 | "c", 29 | "cpp", 30 | "csharp", 31 | "css", 32 | "go", 33 | "handlebars", 34 | "html", 35 | "jade", 36 | "javascript", 37 | "javascriptreact", 38 | "json", 39 | "latex", 40 | "less", 41 | "markdown", 42 | "php", 43 | "plaintext", 44 | "pub", 45 | "python", 46 | "restructuredtext", 47 | "rust", 48 | "scss", 49 | "text", 50 | "typescript", 51 | "typescriptreact", 52 | "yaml", 53 | "yml" 54 | ] 55 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/base/TestSessionStatus.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.base; 2 | 3 | public class TestSessionStatus { 4 | 5 | public String id; 6 | 7 | public int currentDataRecordIndex; 8 | 9 | public int currentIteration; 10 | 11 | public int currentSegmentIndex; 12 | 13 | public int currentTestIndex; 14 | 15 | public String currentTestName; 16 | 17 | public String currentTestPath; 18 | 19 | public String environment; 20 | 21 | public TestSessionStatus(String testSessionId) { 22 | this.id = testSessionId; 23 | this.currentDataRecordIndex = -1; 24 | this.currentIteration = 1; 25 | this.currentSegmentIndex = -1; 26 | this.currentTestIndex = -1; 27 | this.currentTestName = null; 28 | this.currentTestPath = null; 29 | this.environment = null; 30 | } 31 | 32 | public TestSessionStatus(TestSessionStatus session) { 33 | this.id = session.id; 34 | this.currentSegmentIndex = session.currentSegmentIndex; 35 | this.currentTestIndex = session.currentTestIndex; 36 | this.currentTestName = session.currentTestName; 37 | this.currentTestPath = session.currentTestPath; 38 | this.environment = session.environment; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsDragAndDropBy.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | @TestActionClass(description = "Clicks an UI element or the current mouse location.") 11 | @TestActionArgument( 12 | name = "locator", type = Type.OBJECT, optional = true, 13 | description = "Locator object that identifies the element to click on. If " 14 | + "this argument is ommitted, we will click at the current mouse location.") 15 | 16 | public class ActionsDragAndDropBy extends SeleniumTestAction { 17 | 18 | @Override 19 | public void run() { 20 | super.run(); 21 | 22 | By locator = this.readLocatorArgument("locator"); 23 | Integer xOffset = this.readIntArgument("xOffset", 0); 24 | Integer yOffset = this.readIntArgument("yOffset", 0); 25 | 26 | WebElement element = this.getElement(locator); 27 | 28 | SeleniumTestAction.getActionsInstance().dragAndDropBy(element, xOffset, yOffset); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementHasClass.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.CustomConditions; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.WebDriverWait; 8 | 9 | public class AssertElementHasClass extends SeleniumTestAction { 10 | 11 | @Override 12 | public void run() { 13 | super.run(); 14 | 15 | By locator = this.readLocatorArgument("locator"); 16 | String className = this.readStringArgument("class"); 17 | 18 | this.waitForAsyncCallsToFinish(); 19 | 20 | WebElement element = this.getElement(locator); 21 | 22 | try { 23 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 24 | wait.until(CustomConditions.elementToHaveClass(element, className)); 25 | } catch (Exception ex) { 26 | throw new RuntimeException(String.format( 27 | "Failed to find class \"%s\" on element. The value of the element's class attribute was \"%s\"", 28 | className, 29 | element.getAttribute("class")), ex); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/codecs/DecodeUtf8.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions.codecs; 2 | 3 | import java.nio.ByteBuffer; 4 | import java.nio.charset.StandardCharsets; 5 | import jdk.nashorn.api.scripting.ScriptObjectMirror; 6 | import org.getopentest.base.TestAction; 7 | import org.getopentest.util.TypeUtil; 8 | 9 | public class DecodeUtf8 extends TestAction { 10 | 11 | @Override 12 | public void run() { 13 | super.run(); 14 | 15 | Object sourceBytesObj = this.readArgument("sourceBytes"); 16 | 17 | byte[] sourceBytes; 18 | 19 | if (sourceBytesObj instanceof byte[]) { 20 | sourceBytes = (byte[]) sourceBytesObj; 21 | } else if (sourceBytesObj instanceof ScriptObjectMirror) { 22 | sourceBytes = TypeUtil.jsNumberArrayToJavaByteArray( 23 | (ScriptObjectMirror) sourceBytesObj); 24 | } else { 25 | throw new RuntimeException( 26 | "The \"sourceBytes\" argument must be either a Java " 27 | + "native byte array or a JavaScript number array."); 28 | } 29 | 30 | String decodedString = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(sourceBytes)).toString(); 31 | 32 | this.writeOutput("decodedString", decodedString); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/GetElements.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import org.getopentest.annotations.TestActionArgument; 7 | import org.getopentest.annotations.TestActionClass; 8 | import org.getopentest.annotations.Type; 9 | import org.getopentest.appium.core.AppiumTestAction; 10 | import org.getopentest.appium.core.ElementWrapper; 11 | import org.openqa.selenium.By; 12 | 13 | @TestActionClass(description = "Collects and returns a list of UI elements.") 14 | @TestActionArgument( 15 | name = "locator", type = Type.OBJECT, optional = false, 16 | description = "Locator object that identifies the elements to return.") 17 | 18 | public class GetElements extends AppiumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | By locator = this.readLocatorArgument("locator"); 23 | 24 | List elements = this.getElements(locator); 25 | List wrappedElements = elements 26 | .stream() 27 | .map(e -> new ElementWrapper(e)) 28 | .collect(Collectors.toList()); 29 | this.writeOutput("elements", this.getActor().toJsArray(wrappedElements)); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsClick.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | @TestActionClass( 11 | description = "Clicks at the current mouse location or in the middle of " 12 | + "the specified element.") 13 | @TestActionArgument( 14 | name = "locator", type = Type.OBJECT, optional = true, 15 | description = "Locator object that identifies the element to click on. If " 16 | + "this argument is ommitted, we will click at the current mouse location.") 17 | 18 | public class ActionsClick extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator", null); 25 | 26 | if (locator != null) { 27 | WebElement element = this.getElement(locator); 28 | SeleniumTestAction.getActionsInstance().click(element); 29 | } else { 30 | SeleniumTestAction.getActionsInstance().click(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/db/JdbcUpdate.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions.db; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DriverManager; 5 | import java.sql.SQLException; 6 | import java.sql.Statement; 7 | import org.getopentest.base.TestAction; 8 | 9 | /** 10 | * An action that executes a SQL update statement against a database using JDBC. 11 | */ 12 | public class JdbcUpdate extends TestAction { 13 | 14 | @Override 15 | public void run() { 16 | String jdbcUrl = this.readStringArgument("jdbcUrl"); 17 | String user = this.readStringArgument("user", null); 18 | String password = this.readStringArgument("password", null); 19 | String sql = this.readStringArgument("sql"); 20 | 21 | try { 22 | Connection conn; 23 | 24 | if (user != null && password != null) { 25 | conn = DriverManager.getConnection(jdbcUrl, user, password); 26 | } else { 27 | conn = DriverManager.getConnection(jdbcUrl); 28 | } 29 | 30 | Statement statement = conn.createStatement(); 31 | int updateCount = statement.executeUpdate(sql); 32 | 33 | this.writeOutput("updateCount", updateCount); 34 | } catch (SQLException ex) { 35 | throw new RuntimeException(ex); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /actor/selenium/.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | 12 | # Eclipse 13 | .metadata 14 | bin/ 15 | tmp/ 16 | *.tmp 17 | *.bak 18 | *.swp 19 | *~.nib 20 | local.properties 21 | .settings/ 22 | .loadpath 23 | .recommenders 24 | 25 | # Eclipse Core 26 | .project 27 | 28 | # External tool builders 29 | .externalToolBuilders/ 30 | 31 | # Locally stored "Eclipse launch configurations" 32 | *.launch 33 | 34 | # PyDev specific (Python IDE for Eclipse) 35 | *.pydevproject 36 | 37 | # CDT-specific (C/C++ Development Tooling) 38 | .cproject 39 | 40 | # JDT-specific (Eclipse Java Development Tools) 41 | .classpath 42 | 43 | # Java annotation processor (APT) 44 | .factorypath 45 | 46 | # PDT-specific (PHP Development Tools) 47 | .buildpath 48 | 49 | # sbteclipse plugin 50 | .target 51 | 52 | # Tern plugin 53 | .tern-project 54 | 55 | # TeXlipse plugin 56 | .texlipse 57 | 58 | # STS (Spring Tool Suite) 59 | .springBeans 60 | 61 | # Code Recommenders 62 | .recommenders/ 63 | 64 | # NetBeans 65 | nbproject/private/ 66 | build/ 67 | nbbuild/ 68 | dist/ 69 | nbdist/ 70 | nbactions.xml 71 | nb-configuration.xml 72 | .nb-gradle/ 73 | 74 | # Project-specific Stuff 75 | /src/main/resources/web.properties -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ExecuteScript.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.TimeUnit; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.JavascriptExecutor; 8 | 9 | public class ExecuteScript extends SeleniumTestAction{ 10 | 11 | @Override 12 | public void run() { 13 | super.run(); 14 | 15 | String script = this.readStringArgument("script"); 16 | List scriptArgs = this.readArrayArgument("scriptArgs", Object.class, new ArrayList()); 17 | Boolean async = this.readBooleanArgument("async", false); 18 | Integer timeoutSec = this.readIntArgument("timeoutSec", 20); 19 | 20 | this.waitForAsyncCallsToFinish(); 21 | 22 | driver.manage().timeouts().setScriptTimeout(timeoutSec, TimeUnit.SECONDS); 23 | JavascriptExecutor jsExecutor = (JavascriptExecutor)driver; 24 | if (async) { 25 | Object result = jsExecutor.executeAsyncScript(script, scriptArgs.toArray()); 26 | this.writeOutput("result", result); 27 | } else { 28 | Object result = jsExecutor.executeScript(script, scriptArgs.toArray()); 29 | this.writeOutput("result", result); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsClickAndHold.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | @TestActionClass( 11 | description = "Clicks (without releasing) at the current mouse location " 12 | + "or in the middle of the specified element.") 13 | @TestActionArgument( 14 | name = "locator", type = Type.OBJECT, optional = true, 15 | description = "Locator object that identifies the element to click on. If " 16 | + "this argument is ommitted, we will click at the current mouse location.") 17 | 18 | public class ActionsClickAndHold extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator", null); 25 | 26 | if (locator != null) { 27 | WebElement element = this.getElement(locator); 28 | SeleniumTestAction.getActionsInstance().clickAndHold(element); 29 | } else { 30 | SeleniumTestAction.getActionsInstance().clickAndHold(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsKeyUp.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.Keys; 6 | import org.openqa.selenium.WebElement; 7 | 8 | public class ActionsKeyUp extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | super.run(); 13 | 14 | By locator = this.readLocatorArgument("locator", null); 15 | String keyValue = this.readStringArgument("key", null); 16 | String charValue = this.readStringArgument("char", null); 17 | 18 | CharSequence key = null; 19 | if (keyValue != null) { 20 | key = Keys.valueOf(keyValue); 21 | } else if (charValue != null) { 22 | key = charValue; 23 | } else { 24 | throw new RuntimeException( 25 | "You must either provide the \"key\" argument or the \"char\" " 26 | + "argument to specify the key you want to press."); 27 | } 28 | 29 | if (locator != null) { 30 | WebElement element = this.getElement(locator); 31 | SeleniumTestAction.getActionsInstance().keyUp(element, key); 32 | } else { 33 | SeleniumTestAction.getActionsInstance().keyUp(key); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsDoubleClick.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | @TestActionClass( 11 | description = "Performs a double-click at the current mouse location or " 12 | + "at middle of the specified element.") 13 | @TestActionArgument( 14 | name = "locator", type = Type.OBJECT, optional = true, 15 | description = "Locator object that identifies the element to double-click on. If " 16 | + "this argument is ommitted, we will double-click at the current mouse location.") 17 | 18 | public class ActionsDoubleClick extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator", null); 25 | 26 | if (locator != null) { 27 | WebElement element = this.getElement(locator); 28 | SeleniumTestAction.getActionsInstance().doubleClick(element); 29 | } else { 30 | SeleniumTestAction.getActionsInstance().doubleClick(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Launch", 6 | "type": "node", 7 | "request": "launch", 8 | "program": "${workspaceFolder}/dist/start.js", 9 | "stopOnEntry": false, 10 | "args": [], 11 | "cwd": "${workspaceFolder}", 12 | "preLaunchTask": null, 13 | "runtimeExecutable": null, 14 | "runtimeArgs": [ 15 | "--nolazy" 16 | ], 17 | "env": { 18 | "NODE_ENV": "development" 19 | }, 20 | "console": "internalConsole", 21 | "sourceMaps": true, 22 | "outFiles": [ 23 | "${workspaceFolder}/dist/**/*.js" 24 | ] 25 | }, 26 | { 27 | "type": "node", 28 | "request": "launch", 29 | "name": "Debug unit tests", 30 | "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", 31 | "args": [ 32 | "-u", 33 | "tdd", 34 | "--timeout", 35 | "60000", 36 | "--colors", 37 | "${workspaceFolder}/dist/test/unit/**/*.js" 38 | ], 39 | "internalConsoleOptions": "openOnSessionStart" 40 | } 41 | ] 42 | } -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsContextClick.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | @TestActionClass( 11 | description = "Performs a context-click (right-click) at the current " 12 | + "mouse location or at middle of the specified element.") 13 | @TestActionArgument( 14 | name = "locator", type = Type.OBJECT, optional = true, 15 | description = "Locator object that identifies the element to click on. If " 16 | + "this argument is ommitted, we will click at the current mouse location.") 17 | 18 | public class ActionsContextClick extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator", null); 25 | 26 | if (locator != null) { 27 | WebElement element = this.getElement(locator); 28 | SeleniumTestAction.getActionsInstance().contextClick(element); 29 | } else { 30 | SeleniumTestAction.getActionsInstance().contextClick(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # Custom exclusions 61 | /coverage/ 62 | /db/ 63 | /db-*/ 64 | /dist/ 65 | /node_modules/ 66 | /logs/ 67 | /uploads/ 68 | /temp/ 69 | /typings/ 70 | build-info.json 71 | npm-debug.* 72 | /opentest*.tar 73 | server.yaml 74 | TODO.txt -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadUrl.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import java.net.URL; 5 | 6 | public class ReadUrl extends SeleniumTestAction { 7 | 8 | @Override 9 | public void run() { 10 | super.run(); 11 | 12 | try { 13 | String urlValue = driver.getCurrentUrl(); 14 | URL currentUrl = new URL(urlValue); 15 | 16 | this.writeOutput("anchor", currentUrl.getRef()); 17 | this.writeOutput("authority", currentUrl.getAuthority()); 18 | this.writeOutput("defaultPort", currentUrl.getDefaultPort()); 19 | this.writeOutput("file", currentUrl.getFile()); 20 | this.writeOutput("host", currentUrl.getHost()); 21 | this.writeOutput("path", currentUrl.getPath()); 22 | int port = currentUrl.getPort(); 23 | this.writeOutput("port", port > 0 ? port : null); 24 | this.writeOutput("protocol", currentUrl.getProtocol()); 25 | this.writeOutput("query", currentUrl.getQuery()); 26 | this.writeOutput("userInfo", currentUrl.getUserInfo()); 27 | this.writeOutput("url", urlValue); 28 | } catch (Throwable ex) { 29 | throw new RuntimeException("Failed reading the current URL", ex); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SetBrowserAspect.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.Dimension; 5 | import org.openqa.selenium.Point; 6 | 7 | public class SetBrowserAspect extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | Integer positionX = this.readIntArgument("positionX", null); 14 | Integer positionY = this.readIntArgument("positionY", null); 15 | Integer width = this.readIntArgument("width", null); 16 | Integer height = this.readIntArgument("height", null); 17 | 18 | boolean someWorkTookPlace = false; 19 | 20 | if (positionX != null && positionY != null) { 21 | driver.manage().window().setPosition(new Point(positionX, positionY)); 22 | someWorkTookPlace = true; 23 | } 24 | 25 | if (width != null && height != null) { 26 | driver.manage().window().setSize(new Dimension(width, height)); 27 | someWorkTookPlace = true; 28 | } 29 | 30 | if (!someWorkTookPlace) { 31 | throw new RuntimeException( 32 | "You must either specify the positionX and positionY pair of " 33 | + "arguments, or the width and height pair, or both."); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/util/StringUtil.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | public class StringUtil { 7 | 8 | /** 9 | * Returns the corresponding Matcher object if the regex matched, 10 | * or null otherwise. 11 | */ 12 | public static Matcher executeRegex(String text, String regexString) { 13 | Pattern pattern = Pattern.compile(regexString); 14 | Matcher matcher = pattern.matcher(text); 15 | if (matcher.find()) { 16 | return matcher; 17 | } else { 18 | return null; 19 | } 20 | } 21 | 22 | /** 23 | * If the regex contains at least one group, it returns the substring that 24 | * matched the first group. If there are no groups defined, it returns the 25 | * full match if the regex matched, or null otherwise. 26 | */ 27 | public static String substringByRegex(String text, String regexString) { 28 | Pattern pattern = Pattern.compile(regexString); 29 | Matcher matcher = pattern.matcher(text); 30 | if (matcher.find()) { 31 | if (matcher.groupCount() > 0) { 32 | return matcher.group(1); 33 | } else { 34 | return matcher.group(0); 35 | } 36 | } else { 37 | return null; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/GetElements.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | import org.getopentest.annotations.TestActionArgument; 6 | import org.getopentest.annotations.TestActionClass; 7 | import org.getopentest.annotations.Type; 8 | import org.getopentest.selenium.core.ElementWrapper; 9 | import org.getopentest.selenium.core.SeleniumTestAction; 10 | import org.openqa.selenium.By; 11 | import org.openqa.selenium.WebElement; 12 | 13 | @TestActionClass(description = "Collects and returns a list of UI elements.") 14 | @TestActionArgument( 15 | name = "locator", type = Type.OBJECT, optional = false, 16 | description = "Locator object that identifies the elements to return.") 17 | 18 | public class GetElements extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator"); 25 | 26 | this.waitForAsyncCallsToFinish(); 27 | 28 | List elements = this.getElements(locator); 29 | List wrappedElements = elements 30 | .stream() 31 | .map(e -> new ElementWrapper(e)) 32 | .collect(Collectors.toList()); 33 | this.writeOutput("elements", this.getActor().toJsArray(wrappedElements)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ActionsDragAndDrop.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | 10 | @TestActionClass( 11 | description = "Performs click-and-hold at the location of the source element, " 12 | + "moves to the location of the target element, then releases the mouse.") 13 | @TestActionArgument( 14 | name = "locator", type = Type.OBJECT, optional = true, 15 | description = "Locator object that identifies the element to click on. If " 16 | + "this argument is ommitted, we will click at the current mouse location.") 17 | 18 | public class ActionsDragAndDrop extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By sourceLocator = this.readLocatorArgument("source"); 25 | By targetLocator = this.readLocatorArgument("target"); 26 | 27 | WebElement sourceElement = this.getElement(sourceLocator); 28 | WebElement targetElement = this.getElement(targetLocator); 29 | 30 | SeleniumTestAction.getActionsInstance().dragAndDrop(sourceElement, targetElement); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # IntelliJ IDEA files 61 | **/.idea/ 62 | 63 | # Custom 64 | /custom/* 65 | /actor/plugins/* 66 | /dist/module-*/ 67 | /build/config*.json 68 | !/build/config.default.json 69 | !/build/config.sample.json 70 | /temp 71 | /actor/selenium/actor.yaml 72 | 73 | TODO.txt 74 | .DS_Store 75 | -------------------------------------------------------------------------------- /actor/actor/.gitignore: -------------------------------------------------------------------------------- 1 | # Maven 2 | target/ 3 | pom.xml.tag 4 | pom.xml.releaseBackup 5 | pom.xml.versionsBackup 6 | pom.xml.next 7 | release.properties 8 | dependency-reduced-pom.xml 9 | buildNumber.properties 10 | .mvn/timing.properties 11 | 12 | # Eclipse 13 | .metadata 14 | bin/ 15 | tmp/ 16 | *.tmp 17 | *.bak 18 | *.swp 19 | *~.nib 20 | local.properties 21 | .settings/ 22 | .loadpath 23 | .recommenders 24 | 25 | # Eclipse Core 26 | .project 27 | 28 | # External tool builders 29 | .externalToolBuilders/ 30 | 31 | # Locally stored "Eclipse launch configurations" 32 | *.launch 33 | 34 | # PyDev specific (Python IDE for Eclipse) 35 | *.pydevproject 36 | 37 | # CDT-specific (C/C++ Development Tooling) 38 | .cproject 39 | 40 | # JDT-specific (Eclipse Java Development Tools) 41 | .classpath 42 | 43 | # Java annotation processor (APT) 44 | .factorypath 45 | 46 | # PDT-specific (PHP Development Tools) 47 | .buildpath 48 | 49 | # sbteclipse plugin 50 | .target 51 | 52 | # Tern plugin 53 | .tern-project 54 | 55 | # TeXlipse plugin 56 | .texlipse 57 | 58 | # STS (Spring Tool Suite) 59 | .springBeans 60 | 61 | # Code Recommenders 62 | .recommenders/ 63 | 64 | #NetBeans 65 | nbproject/private/ 66 | build/ 67 | nbbuild/ 68 | dist/ 69 | nbdist/ 70 | nbactions.xml 71 | nb-configuration.xml 72 | .nb-gradle/ 73 | 74 | /screenshots/ 75 | 76 | /src/main/resources/actor.properties 77 | /src/main/resources/actor.yaml 78 | /tessdata* 79 | /out 80 | /user-jars -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/logging/Logger.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.logging; 2 | 3 | import org.getopentest.contracts.ILogger; 4 | 5 | public class Logger { 6 | 7 | private static ILogger INSTANCE; 8 | 9 | static { 10 | INSTANCE = new ConsoleLogger(); 11 | } 12 | 13 | public static ILogger getLogger() { 14 | return INSTANCE; 15 | } 16 | 17 | public static void debug(String text) { 18 | INSTANCE.debug(text); 19 | } 20 | 21 | public static void error(String text) { 22 | INSTANCE.error(text); 23 | } 24 | 25 | public static void error(Throwable exception) { 26 | INSTANCE.error(BaseLogger.getStackTrace(exception)); 27 | } 28 | 29 | public static void error(String message, Throwable exception) { 30 | INSTANCE.error(message, exception); 31 | } 32 | 33 | public static void info(String text) { 34 | INSTANCE.info(text); 35 | } 36 | 37 | public static void setLogger(ILogger loger) { 38 | INSTANCE = loger; 39 | } 40 | 41 | public static void trace(String text) { 42 | INSTANCE.trace(text); 43 | } 44 | 45 | public static void warning(String text) { 46 | INSTANCE.warning(text); 47 | } 48 | 49 | public static void warning(String message, Throwable exception) { 50 | INSTANCE.warning(message); 51 | INSTANCE.warning(BaseLogger.getStackTrace(exception)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SelectListOption.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.Select; 6 | 7 | public class SelectListOption extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | By locator = this.readLocatorArgument("locator"); 14 | String optionValue = this.readStringArgument("optionValue", null); 15 | String optionText = this.readStringArgument("optionText", null); 16 | Integer optionNumber = this.readIntArgument("optionNumber", null); 17 | 18 | this.waitForAsyncCallsToFinish(); 19 | 20 | Select dropdownElement = new Select(this.getElement(locator)); 21 | 22 | if (optionValue != null) { 23 | dropdownElement.selectByValue(optionValue); 24 | } else if (optionText != null) { 25 | dropdownElement.selectByVisibleText(optionText); 26 | } else if (optionNumber != null) { 27 | dropdownElement.selectByIndex(optionNumber - 1); 28 | } else { 29 | throw new RuntimeException( 30 | "You must identify the option you want to select from the " 31 | + "list by providing one of the following arguments: " 32 | + "optionValue, optionText or optionNumber."); 33 | } 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/DeselectListOption.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.support.ui.Select; 6 | 7 | public class DeselectListOption extends SeleniumTestAction { 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | By locator = this.readLocatorArgument("locator"); 14 | String optionValue = this.readStringArgument("optionValue", null); 15 | String optionText = this.readStringArgument("optionText", null); 16 | Integer optionNumber = this.readIntArgument("optionNumber", null); 17 | 18 | this.waitForAsyncCallsToFinish(); 19 | 20 | Select dropdownElement = new Select(this.getElement(locator)); 21 | 22 | if (optionValue != null) { 23 | dropdownElement.deselectByValue(optionValue); 24 | } else if (optionText != null) { 25 | dropdownElement.deselectByVisibleText(optionText); 26 | } else if (optionNumber != null) { 27 | dropdownElement.deselectByIndex(optionNumber - 1); 28 | } else { 29 | throw new RuntimeException( 30 | "You must identify the option you want to deselect from the " 31 | + "list by providing one of the following arguments: " 32 | + "optionValue, optionText or optionIndex."); 33 | } 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementEnabled.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.getopentest.annotations.TestActionArgument; 5 | import org.getopentest.annotations.TestActionClass; 6 | import org.getopentest.annotations.Type; 7 | import org.getopentest.appium.core.SwipingAction; 8 | import org.openqa.selenium.By; 9 | 10 | @TestActionClass( 11 | description = "Verifies that a UI element is enabled.") 12 | @TestActionArgument(name = "locator", type = Type.STRING, optional = false, 13 | description = "The locator of the UI element.") 14 | @TestActionArgument(name = "swipe", type = Type.STRING, optional = true, 15 | description = "Specifies whether the test actor should perform swipe" 16 | + " gestures to find the element in case it is not currently visible." 17 | + " Valid values are: up, down, left, right, none.") 18 | 19 | /** 20 | * Verifies that a UI element is enabled. 21 | */ 22 | public class AssertElementEnabled extends SwipingAction { 23 | 24 | @Override 25 | public void run() { 26 | super.run(); 27 | 28 | By locator = readLocatorArgument("locator"); 29 | 30 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 31 | 32 | MobileElement element = getElement(locator); 33 | if (!element.isEnabled()) { 34 | throw new RuntimeException(String.format("Element %s was not enabled", locator)); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SwitchToWindow.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.getopentest.logging.Logger; 5 | 6 | public class SwitchToWindow extends SeleniumTestAction { 7 | //should implement scroll up and scroll down instead of swipe 8 | 9 | @Override 10 | public void run() { 11 | super.run(); 12 | 13 | Integer windowNumber = this.readIntArgument("windowNumber"); 14 | 15 | String[] windowHandles = driver.getWindowHandles().stream() 16 | .toArray(String[]::new); 17 | 18 | try { 19 | if (windowNumber > windowHandles.length) { 20 | throw new RuntimeException(String.format( 21 | "The specified window number (%s) is greater than the " 22 | + "number of windows created (%s).", 23 | windowNumber, 24 | windowHandles.length)); 25 | } 26 | 27 | driver.switchTo().window(windowHandles[windowNumber - 1]); 28 | 29 | Logger.info(String.format( 30 | "Successfully switched to window number %s", 31 | windowNumber)); 32 | } catch (Exception ex) { 33 | throw new RuntimeException(String.format( 34 | "Failed to switch to window number %s. The total number of open windows was %s.", 35 | windowNumber, 36 | windowHandles.length), ex); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ClearContent.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.SeleniumTestAction; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.support.ui.ExpectedConditions; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | 12 | @TestActionClass(description = "Clears the cotent of a \"input\" or \"textarea\" element.") 13 | @TestActionArgument( 14 | name = "locator", type = Type.OBJECT, optional = false, 15 | description = "Locator object that identifies the \"input\" or \"textarea\" element.") 16 | 17 | public class ClearContent extends SeleniumTestAction { 18 | 19 | @Override 20 | public void run() { 21 | super.run(); 22 | 23 | By locator = this.readLocatorArgument("locator"); 24 | 25 | this.waitForAsyncCallsToFinish(); 26 | 27 | try { 28 | WebElement element = this.getElement(locator); 29 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 30 | wait.until(ExpectedConditions.elementToBeClickable(element)); 31 | 32 | element.clear(); 33 | } catch (Exception ex) { 34 | throw new RuntimeException(String.format( 35 | "Failed clicking on element %s", 36 | locator), ex); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/core/ElementWrapper.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium.core; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.openqa.selenium.Dimension; 5 | import org.openqa.selenium.Point; 6 | 7 | /** 8 | * Wraps a WebElement and exposes part of its API in a way that is safe to 9 | * access from JavaScript code. This class is what gets outputted by the 10 | * GetElements action. 11 | */ 12 | public class ElementWrapper { 13 | 14 | private transient MobileElement element; 15 | 16 | private String tag; 17 | 18 | public String text; 19 | 20 | public ElementWrapper(MobileElement element) { 21 | this.element = element; 22 | this.text = element.getText(); 23 | this.tag = element.getTagName(); 24 | } 25 | 26 | public String getAttribute(String attribute) { 27 | return element.getAttribute(attribute); 28 | } 29 | 30 | public Point getLocation() { 31 | return element.getLocation(); 32 | } 33 | 34 | public Dimension getSize() { 35 | return element.getSize(); 36 | } 37 | 38 | public String getTagName() { 39 | return element.getTagName(); 40 | } 41 | 42 | public String getText() { 43 | this.text = element.getText(); 44 | return this.text; 45 | } 46 | 47 | public boolean isDisplayed() { 48 | return element.isDisplayed(); 49 | } 50 | 51 | public boolean isEnabled() { 52 | return element.isEnabled(); 53 | } 54 | public boolean isSelected() { 55 | return element.isSelected(); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/Click.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.Type; 6 | import org.getopentest.selenium.core.CustomConditions; 7 | import org.getopentest.selenium.core.SeleniumTestAction; 8 | import org.openqa.selenium.By; 9 | import org.openqa.selenium.WebElement; 10 | import org.openqa.selenium.support.ui.ExpectedConditions; 11 | import org.openqa.selenium.support.ui.WebDriverWait; 12 | 13 | @TestActionClass(description = "Performs a click on a UI element.") 14 | @TestActionArgument( 15 | name = "locator", type = Type.OBJECT, optional = false, 16 | description = "Locator object that identifies the element to click on.") 17 | 18 | public class Click extends SeleniumTestAction { 19 | 20 | @Override 21 | public void run() { 22 | super.run(); 23 | 24 | By locator = this.readLocatorArgument("locator"); 25 | 26 | this.waitForAsyncCallsToFinish(); 27 | 28 | try { 29 | WebElement element = this.getElement(locator); 30 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 31 | wait.until(ExpectedConditions.elementToBeClickable(element)); 32 | wait.until(CustomConditions.elementWasClicked(element)); 33 | } catch (Exception ex) { 34 | throw new RuntimeException(String.format( 35 | "Failed clicking on element %s", 36 | locator), ex); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /server/server.sample.yaml: -------------------------------------------------------------------------------- 1 | # The path to the root of the test repository directory. If you're using 2 | # backslash characters in double quotes, you'll need to escape them. 3 | # (e.g. "C:\\opentest\\test-repo"). 4 | testRepoDir: "C:/opentest/test-repo" 5 | 6 | # The port the server listens on. 7 | serverPort: 3000 8 | 9 | # Maximum number of test sessions that will be stored in the server's DB 10 | sessionHistoryMaxCount: 500 11 | 12 | # Minimum number of test sessions that will be stored in the server's DB 13 | sessionHistoryMinCount: 50 14 | 15 | # Maximum age of test sessions that will be stored in the server's DB. Older 16 | # sessions will be removed when they exceed the specified age. 17 | sessionHistoryAgeDays: 60 18 | 19 | # Number of seconds a test session will wait to acquire the necessary 20 | # test actors before it is cancelled 21 | acquireActorsTimeoutSec: 1200 22 | 23 | # Number of seconds a test session will be cancelled after, when there is 24 | # no activity (no actors are making any progress executing test segments) 25 | noActivityTimeoutSec: 3600 26 | 27 | # The maximum size allowed for the content of server response messages, in 28 | # bytes. The default is 3MB. 29 | responseMaxSize: 3145728 30 | 31 | # Actor groups can be used to limit the number of actors that can run in 32 | # parallel at any given time. This is useful when running against a cloud 33 | # provider, to avoid starting more sessions than the provider allows. 34 | actorGroups: 35 | - name: BrowserStack 36 | actorTags: bs 37 | maxParallelSessions: 5 38 | 39 | - name: Compute-Intensive 40 | actorTags: compute 41 | maxParallelSessions: 2 -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/files/WriteTextFile.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions.files; 2 | 3 | import java.io.BufferedWriter; 4 | import java.io.FileOutputStream; 5 | import java.io.OutputStreamWriter; 6 | import org.getopentest.base.TestAction; 7 | 8 | public class WriteTextFile extends TestAction { 9 | 10 | @Override 11 | public void run() { 12 | super.run(); 13 | 14 | // The "file" argument was deprecated in favor of "targetFile" 15 | String targetFile = this.readStringArgument("file", null); 16 | if (targetFile == null) { 17 | targetFile = this.readStringArgument("targetFile"); 18 | } 19 | String text = this.readStringArgument("text"); 20 | 21 | // Valid encodings are the ones supported by java.nio.charset.Charset: 22 | // "US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16" 23 | String encoding = this.readStringArgument("encoding", "UTF-8"); 24 | Boolean append = this.readBooleanArgument("append", false); 25 | 26 | BufferedWriter out = null; 27 | 28 | try { 29 | out = new BufferedWriter(new OutputStreamWriter( 30 | new FileOutputStream(targetFile, append), encoding)); 31 | 32 | out.append(text); 33 | 34 | out.flush(); 35 | out.close(); 36 | } catch (Exception ex) { 37 | throw new RuntimeException(String.format( 38 | "Failed to write text file %s using the %s encoding", 39 | targetFile, 40 | encoding), ex); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /server/src/controllers/ui.ts: -------------------------------------------------------------------------------- 1 | import * as configLoader from '../lib/config-loader'; 2 | import * as dbManager from '../lib/db-manager'; 3 | import * as dirs from '../lib/dirs'; 4 | import * as express from 'express'; 5 | import * as fs from 'fs'; 6 | import * as helpers from '../lib/helpers'; 7 | import * as path from 'path'; 8 | import * as moment from 'moment'; 9 | import * as readline from 'readline'; 10 | 11 | export function createRouter(options?: any) { 12 | options = options || {}; 13 | const isReadOnlyRouter = options.readOnly || false; 14 | 15 | let uiRouter: express.Router = express.Router(); 16 | 17 | require('moment-timezone'); 18 | const config = configLoader.getConfig(); 19 | 20 | uiRouter.get('/', function (req, res) { 21 | res.render('home', { 22 | readOnlyView: isReadOnlyRouter, 23 | urlPrefix: config.urlPrefix 24 | }); 25 | }); 26 | 27 | uiRouter.get('/session/:sessionId', async function (req, res) { 28 | const db = dbManager.getDb(); 29 | const sessionId = parseInt(req.params.sessionId); 30 | const dbTestSession = await db.getSession(sessionId); 31 | 32 | if (dbTestSession) { 33 | const testSession = helpers.clone(dbTestSession); 34 | 35 | res.render('session', { 36 | moment: moment, 37 | readOnlyView: isReadOnlyRouter, 38 | session: testSession, 39 | urlPrefix: config.urlPrefix 40 | }); 41 | } else { 42 | res.status(404).send(helpers.format('Session {0} not found', sessionId)); 43 | } 44 | }); 45 | 46 | return uiRouter; 47 | } -------------------------------------------------------------------------------- /server/src/lib/dirs.ts: -------------------------------------------------------------------------------- 1 | import * as helpers from './helpers'; 2 | import * as path from 'path'; 3 | import * as yargs from 'yargs'; 4 | 5 | let appRootDirPath: string = path.resolve(path.join(__dirname, '..', '..')); 6 | let workingDirPath: string = process.cwd(); 7 | 8 | yargs.alias('w', 'workdir'); 9 | 10 | if (yargs.argv.workdir) { 11 | setWorkingDir(path.resolve(yargs.argv.workdir)); 12 | } 13 | 14 | /** Returns the root directory of the Node application. */ 15 | export function appRootDir(): string { 16 | return appRootDirPath; 17 | } 18 | 19 | /** Returns the logs directory. */ 20 | export function logsDir(): string { 21 | return path.join(appRootDirPath, 'logs'); 22 | } 23 | 24 | /** Returns the screenshots directory. */ 25 | export function screenshotDir(): string { 26 | return path.join(appRootDirPath, 'uploads', 'screenshots'); 27 | } 28 | 29 | /** Sets the working directory where the DB files and the log files are 30 | * stored and where the configuration file is read from. */ 31 | export function setWorkingDir(newWorkingDir: string) { 32 | let normalizedPath = path.normalize(newWorkingDir); 33 | if (!path.isAbsolute(normalizedPath)) { 34 | normalizedPath = path.resolve(normalizedPath); 35 | } 36 | 37 | if (helpers.directoryExists(normalizedPath)) { 38 | workingDirPath = normalizedPath; 39 | } else { 40 | throw new Error(`Can't set working dir to "${normalizedPath}". Path does not exist.`); 41 | } 42 | } 43 | 44 | /** Returns the working directory where the DB files and the log files are 45 | * stored and where the configuration file is read from. */ 46 | export function workingDir(): string { 47 | return workingDirPath; 48 | } -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/util/TypeUtil.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.util; 2 | 3 | import jdk.nashorn.api.scripting.ScriptObjectMirror; 4 | 5 | public class TypeUtil { 6 | 7 | public static byte[] jsNumberArrayToJavaByteArray(ScriptObjectMirror scriptObj) { 8 | if (scriptObj.isArray()) { 9 | byte[] javaByteArray = new byte[scriptObj.values().size()]; 10 | int currentIndex = 0; 11 | for (Object currentValue : scriptObj.values()) { 12 | if (currentValue instanceof Integer) { 13 | Integer intValue = (Integer) currentValue; 14 | if (intValue >= 0 && intValue <= 255) { 15 | javaByteArray[currentIndex] = (byte) intValue.intValue(); 16 | } else { 17 | throw new RuntimeException(String.format( 18 | "Failed to convert JS array to Java byte array because array " 19 | + "element %s is not a number between 0 and 255.", 20 | intValue)); 21 | } 22 | } else { 23 | throw new RuntimeException(String.format( 24 | "Failed to encode JS array to base64. Array " 25 | + "element %s is not a number.", 26 | currentValue)); 27 | } 28 | currentIndex++; 29 | } 30 | 31 | return javaByteArray; 32 | } else { 33 | throw new RuntimeException( 34 | "The provided JavaScript native value was not an array."); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Launch server", 9 | "type": "node", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/server/src/start.ts", 12 | "stopOnEntry": false, 13 | "args": [], 14 | "cwd": "${workspaceFolder}/server", 15 | "preLaunchTask": null, 16 | "runtimeExecutable": null, 17 | "runtimeArgs": [ 18 | "--nolazy" 19 | ], 20 | "env": { 21 | "NODE_ENV": "development" 22 | }, 23 | "console": "internalConsole", 24 | "sourceMaps": true, 25 | "outFiles": [ 26 | "${workspaceFolder}/server/dist/**/*.js" 27 | ] 28 | }, 29 | { 30 | "name": "Launch CLI", 31 | "type": "node", 32 | "request": "launch", 33 | "program": "${workspaceRoot}/build/module-opentest/opentest.js", 34 | "stopOnEntry": false, 35 | "args": ["actor", "init"], 36 | "cwd": "${workspaceFolder}", 37 | "preLaunchTask": null, 38 | "runtimeExecutable": null, 39 | "runtimeArgs": [ 40 | "--nolazy" 41 | ], 42 | "env": { 43 | "NODE_ENV": "development" 44 | }, 45 | "console": "internalConsole", 46 | } 47 | ] 48 | } -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/core/ElementWrapper.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium.core; 2 | 3 | import org.openqa.selenium.Dimension; 4 | import org.openqa.selenium.Point; 5 | import org.openqa.selenium.WebElement; 6 | 7 | /** 8 | * Wraps a WebElement and exposes part of its API in a way that is safe to 9 | * access from JavaScript code. This class is what gets outputted by the 10 | * GetElements action. 11 | */ 12 | public class ElementWrapper { 13 | 14 | private transient WebElement element; 15 | 16 | private String tag; 17 | 18 | public String text; 19 | 20 | public ElementWrapper(WebElement element) { 21 | this.element = element; 22 | this.text = element.getText(); 23 | this.tag = element.getTagName(); 24 | } 25 | 26 | public String getAttribute(String attribute) { 27 | return element.getAttribute(attribute); 28 | } 29 | 30 | public WebElement getElement() { 31 | return element; 32 | } 33 | 34 | public Point getLocation() { 35 | return element.getLocation(); 36 | } 37 | 38 | public Dimension getSize() { 39 | return element.getSize(); 40 | } 41 | 42 | public String getTagName() { 43 | return element.getTagName(); 44 | } 45 | 46 | public String getText() { 47 | this.text = element.getText(); 48 | return this.text; 49 | } 50 | 51 | public boolean isDisplayed() { 52 | return element.isDisplayed(); 53 | } 54 | 55 | public boolean isEnabled() { 56 | return element.isEnabled(); 57 | } 58 | public boolean isSelected() { 59 | return element.isSelected(); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementChecked.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.getopentest.annotations.TestActionArgument; 5 | import org.getopentest.annotations.TestActionClass; 6 | import org.getopentest.annotations.Type; 7 | import org.getopentest.appium.core.CustomConditions; 8 | import org.getopentest.appium.core.SwipingWaitingAction; 9 | import org.openqa.selenium.By; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | 12 | @TestActionClass( 13 | description = "Verifies that a UI element's checked attribute is true.") 14 | @TestActionArgument(name = "locator", type = Type.STRING, optional = false, 15 | description = "The locator of the UI element.") 16 | @TestActionArgument(name = "swipe", type = Type.STRING, optional = true, 17 | description = "Specifies whether the test actor should perform swipe" 18 | + " gestures to find the element in case it is not currently visible." 19 | + " Valid values are: up, down, left, right.") 20 | 21 | /** 22 | * Verifies that a UI element's checked attribute is true. 23 | */ 24 | public class AssertElementChecked extends SwipingWaitingAction { 25 | 26 | @Override 27 | public void run() { 28 | super.run(); 29 | 30 | By locator = readLocatorArgument("locator"); 31 | 32 | swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 33 | 34 | MobileElement element = getElement(locator, this.getExplicitWaitSec()); 35 | 36 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 37 | wait.until(CustomConditions.attributeValueToBe(element, "checked", "true")); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /actor/actor/src/main/assembly/maven-assembly.xml: -------------------------------------------------------------------------------- 1 | 4 | build 5 | true 6 | 7 | 8 | zip 9 | 10 | 11 | 12 | ${project.build.directory} 13 | . 14 | 15 | *.jar 16 | 17 | 18 | *tests.jar 19 | 20 | 21 | 22 | ${project.build.directory} 23 | . 24 | 25 | dependency-jars/* 26 | 27 | 28 | 29 | ${project.build.directory}/classes 30 | . 31 | 32 | run.bat 33 | 34 | 35 | 36 | 37 | 38 | ${project.build.directory}/classes/actor.sample.yaml 39 | / 40 | actor.yaml 41 | 42 | 43 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/serialization/json/ScriptObjectMirrorSerializer.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.serialization.json; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonSerializationContext; 7 | import com.google.gson.JsonSerializer; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | import jdk.nashorn.api.scripting.ScriptObjectMirror; 11 | import org.getopentest.util.Factory; 12 | 13 | /** 14 | * Custom Gson serializer for ScriptObjectMirror instances. Without using a 15 | * custom serializer, Gson will serialize JavaScript arrays as objects (the same 16 | * way it serializes Java maps). 17 | */ 18 | public class ScriptObjectMirrorSerializer implements JsonSerializer { 19 | 20 | private Gson gson; 21 | 22 | public ScriptObjectMirrorSerializer(boolean serializeNulls) { 23 | if (this.gson == null) { 24 | GsonBuilder builder = Factory.getGsonBuilder(); 25 | 26 | if (serializeNulls) { 27 | builder = builder.serializeNulls(); 28 | } 29 | 30 | this.gson = builder 31 | .registerTypeAdapter(ScriptObjectMirror.class, this) 32 | .create(); 33 | } 34 | } 35 | 36 | @Override 37 | public JsonElement serialize(ScriptObjectMirror src, java.lang.reflect.Type typeOfSrc, JsonSerializationContext context) { 38 | if (src.isArray()) { 39 | return this.gson.toJsonTree(src.values()); 40 | } else { 41 | Map map = new HashMap<>(); 42 | map.putAll(src); 43 | return this.gson.toJsonTree(map); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/AssertElementNotChecked.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import org.getopentest.annotations.TestActionArgument; 5 | import org.getopentest.annotations.TestActionClass; 6 | import org.getopentest.annotations.Type; 7 | import org.getopentest.appium.core.SwipingAction; 8 | import org.openqa.selenium.By; 9 | 10 | @TestActionClass( 11 | description = "Verifies that a UI element's checked attribute " 12 | + "is false.") 13 | @TestActionArgument(name = "locator", type = Type.MAP, optional = false, 14 | description = "The locator of the UI element.") 15 | @TestActionArgument(name = "swipe", type = Type.STRING, optional = true, 16 | description = "Specifies whether the test actor should perform swipe" 17 | + " gestures to find the element in case it is not currently visible." 18 | + " Valid values are: up, down, left, right, none.") 19 | 20 | /** 21 | * Verifies that a UI element's checked attribute is false. 22 | */ 23 | public class AssertElementNotChecked extends SwipingAction { 24 | 25 | @Override 26 | public void run() { 27 | super.run(); 28 | 29 | By locator = this.readLocatorArgument("locator"); 30 | 31 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 32 | 33 | MobileElement element = this.getElement(locator); 34 | 35 | String checkedState = element.getAttribute("checked"); 36 | if (!checkedState.equalsIgnoreCase("false")) { 37 | throw new RuntimeException(String.format( 38 | "Expected element's checked state to be \"false\", but it was" 39 | + "found to be \"%s\"", checkedState)); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertElementText.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import java.util.regex.Pattern; 4 | import org.getopentest.selenium.core.CustomConditions; 5 | import org.getopentest.selenium.core.SeleniumTestAction; 6 | import org.openqa.selenium.By; 7 | import org.openqa.selenium.WebElement; 8 | import org.openqa.selenium.support.ui.WebDriverWait; 9 | 10 | public class AssertElementText extends SeleniumTestAction { 11 | 12 | @Override 13 | public void run() { 14 | 15 | super.run(); 16 | 17 | By locator = this.readLocatorArgument("locator"); 18 | String text = this.readStringArgument("text", null); 19 | String textContains = this.readStringArgument("textContains", null); 20 | Pattern textMatches = this.readRegexArgument("textMatches", null); 21 | boolean caseInsensitive = this.readBooleanArgument("caseInsensitive", false); 22 | 23 | this.waitForAsyncCallsToFinish(); 24 | 25 | WebElement element = this.getElement(locator); 26 | 27 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 28 | 29 | if (text != null) { 30 | wait.until(CustomConditions.elementTextToBe(element, text, caseInsensitive)); 31 | } else if (textContains != null) { 32 | wait.until(CustomConditions.elementTextToContain(element, textContains, caseInsensitive)); 33 | } else if (textMatches != null) { 34 | wait.until(CustomConditions.elementTextToMatch(element, textMatches)); 35 | } else { 36 | throw new RuntimeException( 37 | "You must provide at least one of the following arguments: " 38 | + "text, textContains, textMatches."); 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/serialization/json/DuplicateFieldExclusionStrategy.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.serialization.json; 2 | 3 | import com.google.gson.ExclusionStrategy; 4 | import com.google.gson.FieldAttributes; 5 | import java.lang.reflect.Field; 6 | 7 | /** 8 | * Avoids serialization errors when duplicate fields exist in the inheritance 9 | * hierarchy. GSON will serialize all fields, including private fields. If the 10 | * same private field exists in more than one class along the inheritance hierarchy 11 | * of an object, this will result in a serialization error "CLASSNAME declares 12 | * multiple JSON fields named FIELDNAME". 13 | */ 14 | public class DuplicateFieldExclusionStrategy implements ExclusionStrategy { 15 | 16 | private boolean isFieldInSuperclass(Class subclass, String fieldName) { 17 | Class superclass = subclass.getSuperclass(); 18 | Field field; 19 | 20 | while (superclass != null) { 21 | field = getField(superclass, fieldName); 22 | 23 | if (field != null) { 24 | return true; 25 | } 26 | 27 | superclass = superclass.getSuperclass(); 28 | } 29 | 30 | return false; 31 | } 32 | 33 | private Field getField(Class theClass, String fieldName) { 34 | try { 35 | return theClass.getDeclaredField(fieldName); 36 | } catch (Exception e) { 37 | return null; 38 | } 39 | } 40 | 41 | @Override 42 | public boolean shouldSkipClass(Class arg0) { 43 | return false; 44 | } 45 | 46 | @Override 47 | public boolean shouldSkipField(FieldAttributes fieldAttributes) { 48 | String fieldName = fieldAttributes.getName(); 49 | Class theClass = fieldAttributes.getDeclaringClass(); 50 | 51 | return isFieldInSuperclass(theClass, fieldName); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/visual/CvHelper.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.visual; 2 | 3 | import java.awt.image.BufferedImage; 4 | import java.awt.image.DataBufferByte; 5 | import java.awt.image.WritableRaster; 6 | import org.opencv.core.CvType; 7 | import org.opencv.core.Mat; 8 | 9 | /** 10 | * OpenCV helper methods. 11 | */ 12 | public class CvHelper { 13 | 14 | public static BufferedImage convertToBufferedImage(Mat mat) { 15 | byte[] data = new byte[mat.cols() * mat.rows() * (int) mat.elemSize()]; 16 | mat.get(0, 0, data); 17 | 18 | BufferedImage image = new BufferedImage( 19 | mat.cols(), 20 | mat.rows(), 21 | mat.channels() == 1 22 | ? BufferedImage.TYPE_BYTE_GRAY 23 | : BufferedImage.TYPE_3BYTE_BGR); 24 | image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data); 25 | return image; 26 | } 27 | 28 | /** 29 | * Converts a BufferedImage to an OpenCV Mat object. 30 | */ 31 | public static Mat convertToMat(BufferedImage buffImg) { 32 | BufferedImage convertedImg = null; 33 | 34 | // Convert the image to TYPE_3BYTE_BGR, if necessary 35 | if (buffImg.getType() == BufferedImage.TYPE_3BYTE_BGR) { 36 | convertedImg = buffImg; 37 | } else { 38 | convertedImg = new BufferedImage(buffImg.getWidth(), buffImg.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 39 | } 40 | 41 | convertedImg.getGraphics().drawImage(buffImg, 0, 0, null); 42 | 43 | WritableRaster raster = convertedImg.getRaster(); 44 | DataBufferByte data = (DataBufferByte) raster.getDataBuffer(); 45 | byte[] pixels = data.getData(); 46 | 47 | Mat mat = new Mat(buffImg.getHeight(), buffImg.getWidth(), CvType.CV_8UC3); 48 | mat.put(0, 0, pixels); 49 | return mat; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/GetTestAsset.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions; 2 | 3 | import java.io.File; 4 | import java.io.InputStream; 5 | import java.nio.file.Files; 6 | import java.nio.file.Paths; 7 | import java.nio.file.StandardCopyOption; 8 | import org.getopentest.base.TestAction; 9 | 10 | /** 11 | * Reads a test asset from the sync service and saves it to a local file. 12 | */ 13 | public class GetTestAsset extends TestAction { 14 | 15 | @Override 16 | public void run() { 17 | super.run(); 18 | 19 | String assetType = this.readStringArgument("assetType"); 20 | String assetRelativePath = this.readStringArgument("assetRelativePath"); 21 | String targetFilePath = this.readStringArgument("targetFile"); 22 | Boolean overwrite = this.readBooleanArgument("overwrite", false); 23 | 24 | File targetFile = new File(targetFilePath); 25 | if (!targetFile.isAbsolute()) { 26 | targetFile = Paths.get(this.getActor().getTempDir().getAbsolutePath(), targetFilePath).toFile(); 27 | } 28 | 29 | targetFile.getParentFile().mkdirs(); 30 | 31 | try { 32 | InputStream assetStream = this.getActor().getTestAsset(assetType, assetRelativePath); 33 | 34 | if (overwrite) { 35 | Files.copy(assetStream, targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING); 36 | } else { 37 | Files.copy(assetStream, targetFile.toPath()); 38 | } 39 | 40 | assetStream.close(); 41 | 42 | this.writeOutput("targetFilePath", targetFile.getAbsolutePath()); 43 | } catch (Exception ex) { 44 | throw new RuntimeException(String.format( 45 | "Failed to transfer data from the test asset input stream into file %s", 46 | targetFilePath), ex); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /server/src/lib/websocket-notifier.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Socket.IO namespaces: 3 | * /actors 4 | * /session-status 5 | */ 6 | 7 | import * as configLoader from './config-loader'; 8 | import { Server } from 'http'; 9 | import { sessionSettings } from './express-session'; 10 | import * as socketIo from 'socket.io'; 11 | 12 | let io: SocketIO.Server = null; 13 | let ioActorsNs: SocketIO.Namespace = null 14 | let ioSessionStatusNs: SocketIO.Namespace = null 15 | 16 | export function initialize(httpServer: Server) { 17 | if (io) return; 18 | 19 | const config = configLoader.getConfig(); 20 | 21 | io = socketIo(httpServer, { 22 | path: `${config.urlPrefix}/socket.io` 23 | }); 24 | 25 | const ioSession = require('socket.io-express-session'); 26 | io.use(ioSession(sessionSettings)); 27 | 28 | io.on('connection', function (socket) { 29 | const session = (socket.handshake as any).session; 30 | if (session && session.id) { 31 | console.log('Established WebSocket connection for session ' + session.id); 32 | } 33 | }); 34 | 35 | ioActorsNs = io.of('/actors'); 36 | ioSessionStatusNs = io.of('/session-status'); 37 | } 38 | 39 | 40 | export function onActorsChanged(actorId: number) { 41 | if (!io) return; 42 | 43 | ioActorsNs.emit('actors-changed', { 44 | actorId: actorId 45 | }); 46 | } 47 | 48 | export function onSessionStatusChanged(sessionId: number, newStatus: string) { 49 | if (!io) return; 50 | 51 | ioSessionStatusNs.emit('status-changed', { 52 | sessionId: sessionId, 53 | newStatus: newStatus 54 | }); 55 | } 56 | 57 | interface IProgress { 58 | testsTotal: number, 59 | testsComplete: number, 60 | testsPassed: number 61 | } 62 | 63 | export function onSessionProgress(sessionId: number, eventData?: IProgress) { 64 | if (!io) return; 65 | 66 | ioSessionStatusNs.emit('progress', { 67 | sessionId: sessionId, 68 | ...eventData 69 | }); 70 | } -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertPageTitle.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.logging.Logger; 4 | import org.getopentest.selenium.core.SeleniumTestAction; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertPageTitle extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | String titleIs = this.readStringArgument("title", this.readStringArgument("titleIs", null)); 16 | String titleContains = this.readStringArgument("titleContains", null); 17 | 18 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 19 | 20 | if (titleIs != null) { 21 | try { 22 | wait.until(ExpectedConditions.titleIs(titleIs)); 23 | } catch (Exception ex) { 24 | throw new RuntimeException(String.format( 25 | "Failed to validate page title. We expected the title to be \"%s\"", 26 | titleIs), ex); 27 | } 28 | } else if (titleContains != null) { 29 | try { 30 | wait.until(ExpectedConditions.titleContains(titleContains)); 31 | Logger.trace(String.format("The current page title was \"%s\"", 32 | driver.getTitle())); 33 | } catch (Exception ex) { 34 | throw new RuntimeException(String.format( 35 | "Failed to validate page title. We expected the title to contain \"%s\"", 36 | titleContains), ex); 37 | } 38 | } else { 39 | throw new RuntimeException( 40 | "You must either provide the \"titleIs\" argument or the \"titleContains\" " 41 | + "argument to indicate the type of validation to perform on the page title."); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/SendKeys.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.selenium.core.SeleniumTestAction; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.Keys; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.ui.ExpectedConditions; 8 | import org.openqa.selenium.support.ui.WebDriverWait; 9 | 10 | public class SendKeys extends SeleniumTestAction { 11 | 12 | @Override 13 | public void run() { 14 | super.run(); 15 | 16 | By locator = this.readLocatorArgument("locator"); 17 | String text = this.readStringArgument("text", null); 18 | String key = this.readStringArgument("key", null); 19 | Boolean clearContent = this.readBooleanArgument("clearContent", Boolean.FALSE); 20 | Boolean sendEnter = this.readBooleanArgument("sendEnter", Boolean.FALSE); 21 | 22 | this.waitForAsyncCallsToFinish(); 23 | 24 | try { 25 | WebElement element = this.getElement(locator); 26 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 27 | wait.until(ExpectedConditions.elementToBeClickable(element)); 28 | 29 | if (clearContent) { 30 | element.clear(); 31 | } 32 | 33 | if (text != null) { 34 | element.sendKeys(text); 35 | } else if (key != null) { 36 | element.sendKeys(Keys.valueOf(key.toUpperCase())); 37 | } else { 38 | throw new RuntimeException("Neither the \"text\" argument, nor the \"key\" argument were provided."); 39 | } 40 | 41 | if (sendEnter) { 42 | element.sendKeys(Keys.ENTER); 43 | } 44 | } catch (Exception ex) { 45 | throw new RuntimeException(String.format( 46 | "Failed sending keys to element %s", 47 | locator), ex 48 | ); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /actor/selenium/src/test/java/org/getopentest/selenium/core/SeleniumHelperNGTest.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium.core; 2 | 3 | import java.awt.Rectangle; 4 | import java.nio.charset.StandardCharsets; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | import static org.testng.Assert.*; 11 | import org.testng.annotations.Test; 12 | 13 | public class SeleniumHelperNGTest { 14 | 15 | @Test 16 | public void parseResolution() { 17 | 18 | writeConfigFile("actor.yaml", ""); 19 | 20 | Rectangle resolution1 = SeleniumHelper.parseResolution("1024x768"); 21 | Rectangle resolution2 = SeleniumHelper.parseResolution("1024X768"); 22 | Rectangle resolution3 = SeleniumHelper.parseResolution("1024,768"); 23 | Rectangle resolution4 = SeleniumHelper.parseResolution("1024 , 768"); 24 | Rectangle resolution5 = SeleniumHelper.parseResolution("100,100,1024,768"); 25 | Rectangle resolution6 = SeleniumHelper.parseResolution(""); 26 | 27 | assertTrue(resolution1.equals(new Rectangle(0, 0, 1024, 768))); 28 | assertTrue(resolution2.equals(new Rectangle(0, 0, 1024, 768))); 29 | assertTrue(resolution3.equals(new Rectangle(0, 0, 1024, 768))); 30 | assertTrue(resolution4.equals(new Rectangle(0, 0, 1024, 768))); 31 | assertTrue(resolution5.equals(new Rectangle(100, 100, 1024, 768))); 32 | assertTrue(resolution6 == null); 33 | } 34 | 35 | /** 36 | * Writes the "actor.yaml" file in the working directory. 37 | */ 38 | public void writeConfigFile(String fileName, String fileContents) { 39 | try { 40 | String workDir = System.getProperty("user.dir"); 41 | Path yamlPath = Paths.get(workDir, fileName); 42 | List lines = Arrays.asList(fileContents); 43 | Files.write(yamlPath, lines, StandardCharsets.UTF_8); 44 | } catch (Exception exc) { 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /actor/base/src/main/java/org/getopentest/actions/files/ReadTextFile.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.actions.files; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.InputStream; 5 | import java.nio.charset.Charset; 6 | import org.apache.commons.io.IOUtils; 7 | import org.apache.commons.io.input.BOMInputStream; 8 | import org.getopentest.base.TestAction; 9 | 10 | public class ReadTextFile extends TestAction { 11 | 12 | @Override 13 | public void run() { 14 | super.run(); 15 | 16 | // The "file" argument was deprecated in favor of "sourceFile" 17 | String sourceFile = this.readStringArgument("file", null); 18 | if (sourceFile == null) { 19 | sourceFile = this.readStringArgument("sourceFile"); 20 | } 21 | 22 | // Valid encodings are the ones supported by java.nio.charset.Charset: 23 | // "US-ASCII", "ISO-8859-1", "UTF-8", "UTF-16BE", "UTF-16LE", "UTF-16" 24 | String encoding = this.readStringArgument("encoding", "UTF-8"); 25 | Boolean excludeBom = this.readBooleanArgument("excludeBom", Boolean.TRUE); 26 | 27 | try { 28 | FileInputStream fileInputStream = null; 29 | InputStream inputStream; 30 | 31 | if (excludeBom) { 32 | fileInputStream = new FileInputStream(sourceFile); 33 | inputStream = new BOMInputStream(fileInputStream); 34 | } else { 35 | inputStream = new FileInputStream(sourceFile); 36 | } 37 | 38 | 39 | 40 | String text = IOUtils.toString(inputStream, Charset.forName(encoding)); 41 | if (fileInputStream != null) { 42 | fileInputStream.close(); 43 | } 44 | inputStream.close(); 45 | 46 | this.writeOutput("text", text); 47 | } catch (Exception ex) { 48 | throw new RuntimeException(String.format( 49 | "Failed to read file %s using the %s encoding", 50 | sourceFile, 51 | encoding), ex); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/ReadElementAspect.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import org.getopentest.annotations.TestActionArgument; 4 | import org.getopentest.annotations.TestActionClass; 5 | import org.getopentest.annotations.TestActionOutput; 6 | import org.getopentest.annotations.Type; 7 | import org.getopentest.selenium.core.SeleniumTestAction; 8 | import org.openqa.selenium.By; 9 | import org.openqa.selenium.Dimension; 10 | import org.openqa.selenium.Point; 11 | import org.openqa.selenium.WebElement; 12 | 13 | @TestActionClass( 14 | description = "Reads the position and size of a UI element.") 15 | @TestActionArgument(name = "locator", type = Type.MAP, optional = false, 16 | description = "The locator of the UI element.") 17 | @TestActionOutput(name = "x", type = Type.INTEGER, 18 | description = "The x position of the upper-left corner of the UI element.") 19 | @TestActionOutput(name = "y", type = Type.INTEGER, 20 | description = "The y position of the upper-left corner of the UI element.") 21 | @TestActionOutput(name = "width", type = Type.INTEGER, 22 | description = "The width of the UI element.") 23 | @TestActionOutput(name = "height", type = Type.INTEGER, 24 | description = "The height of the UI element.") 25 | 26 | /** 27 | * Reads the position and size of a UI element. 28 | */ 29 | public class ReadElementAspect extends SeleniumTestAction { 30 | 31 | @Override 32 | public void run() { 33 | super.run(); 34 | 35 | By locator = this.readLocatorArgument("locator"); 36 | 37 | WebElement element = this.getElement(locator); 38 | Point point = element.getLocation(); 39 | 40 | int x = point.getX(); 41 | int y = point.getY(); 42 | 43 | Dimension size = element.getSize(); 44 | int width = size.width; 45 | int height = size.height; 46 | 47 | this.writeOutput("x", x); 48 | this.writeOutput("y", y); 49 | this.writeOutput("width", width); 50 | this.writeOutput("height", height); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /actor/appium/src/main/java/org/getopentest/appium/Tap.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.appium; 2 | 3 | import io.appium.java_client.MobileElement; 4 | import io.appium.java_client.TouchAction; 5 | import io.appium.java_client.touch.TapOptions; 6 | import io.appium.java_client.touch.offset.ElementOption; 7 | import io.appium.java_client.touch.offset.PointOption; 8 | import org.getopentest.appium.core.SwipingAction; 9 | import org.openqa.selenium.By; 10 | 11 | public class Tap extends SwipingAction { 12 | 13 | @Override 14 | public void run() { 15 | super.run(); 16 | 17 | By locator = this.readLocatorArgument("locator", null); 18 | Integer xOffset = this.readIntArgument("xOffset", null); 19 | Integer yOffset = this.readIntArgument("yOffset", null); 20 | Integer x = this.readIntArgument("x", null); 21 | Integer y = this.readIntArgument("y", null); 22 | 23 | if (locator != null) { 24 | this.swipeAndCheckElementVisible(locator, this.getSwipeOptions()); 25 | 26 | MobileElement element = this.getElement(locator); 27 | 28 | if (xOffset == null && yOffset == null) { 29 | element.click(); 30 | } else { 31 | xOffset = xOffset == null ? 0 : xOffset; 32 | yOffset = yOffset == null ? 0 : yOffset; 33 | 34 | (new TouchAction(driver)) 35 | .tap(TapOptions.tapOptions().withElement( 36 | ElementOption.element(element, xOffset, yOffset))) 37 | .perform(); 38 | } 39 | } else if (x != null && y != null) { 40 | (new TouchAction(driver)) 41 | .tap(PointOption.point(x, y)) 42 | .perform(); 43 | } else { 44 | throw new RuntimeException( 45 | "You must either provide the locator argument of the element to tap, " 46 | + "or the x and y arguments to indicate the exact coordinates to tap at."); 47 | } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /actor/selenium/src/main/java/org/getopentest/selenium/AssertUrl.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.selenium; 2 | 3 | import java.util.regex.Pattern; 4 | import org.getopentest.selenium.core.CustomConditions; 5 | import org.getopentest.selenium.core.SeleniumTestAction; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | public class AssertUrl extends SeleniumTestAction { 9 | 10 | @Override 11 | public void run() { 12 | 13 | super.run(); 14 | 15 | String urlIs = this.readStringArgument("urlIs", null); 16 | String urlContains = this.readStringArgument("urlContains", null); 17 | Pattern urlMatches = this.readRegexArgument("urlMatches", null); 18 | boolean caseInsensitive = this.readBooleanArgument("caseInsensitive", false); 19 | 20 | this.waitForAsyncCallsToFinish(); 21 | 22 | Pattern regexPattern = null; 23 | 24 | if (urlIs != null) { 25 | regexPattern = Pattern.compile("^" + Pattern.quote(urlIs) + "$"); 26 | } else if (urlContains != null) { 27 | regexPattern = Pattern.compile("^.*" + Pattern.quote(urlContains) + ".*$"); 28 | } else if (urlMatches != null) { 29 | regexPattern = urlMatches; 30 | } else { 31 | throw new RuntimeException( 32 | "You must indicate the way you want to validate the URL by providing exactly " 33 | + "one of the following arguments: urlIs, urlContains or urlMatches."); 34 | } 35 | 36 | if (caseInsensitive) { 37 | regexPattern = Pattern.compile(regexPattern.pattern(), regexPattern.flags() & Pattern.CASE_INSENSITIVE); 38 | } 39 | 40 | try { 41 | WebDriverWait wait = new WebDriverWait(this.driver, this.getExplicitWaitSec()); 42 | wait.until(CustomConditions.urlToMatch(regexPattern)); 43 | } catch (Exception ex) { 44 | throw new RuntimeException(String.format( 45 | "Failed to validate the current page URL. At the time of this error, the URL was %s", 46 | driver.getCurrentUrl()), ex); 47 | } 48 | } 49 | } 50 | --------------------------------------------------------------------------------