├── .gitattributes ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── stale.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── README.adoc ├── actor ├── actor │ ├── .gitignore │ ├── pom.xml │ └── src │ │ └── main │ │ ├── README.md │ │ ├── assembly │ │ └── maven-assembly.xml │ │ └── resources │ │ ├── actor.sample.yaml │ │ └── run.bat ├── appium │ ├── .gitignore │ ├── pom.xml │ └── src │ │ └── main │ │ └── java │ │ └── org │ │ └── getopentest │ │ └── appium │ │ ├── ActionsLongPress.java │ │ ├── ActionsMoveTo.java │ │ ├── ActionsPause.java │ │ ├── ActionsPerform.java │ │ ├── ActionsPress.java │ │ ├── ActionsRelease.java │ │ ├── ActionsTap.java │ │ ├── ActionsWait.java │ │ ├── AssertElementChecked.java │ │ ├── AssertElementDisabled.java │ │ ├── AssertElementEnabled.java │ │ ├── AssertElementNotChecked.java │ │ ├── AssertElementNotEnabled.java │ │ ├── AssertElementNotVisible.java │ │ ├── AssertElementPresent.java │ │ ├── AssertElementText.java │ │ ├── AssertElementUnchecked.java │ │ ├── AssertElementVisible.java │ │ ├── CloseApp.java │ │ ├── ExecuteScript.java │ │ ├── GetElements.java │ │ ├── HideKeyboard.java │ │ ├── InitAppium.java │ │ ├── LaunchApp.java │ │ ├── LongPress.java │ │ ├── NavigateBack.java │ │ ├── ReadElementAspect.java │ │ ├── ReadElementAttribute.java │ │ ├── ReadElementText.java │ │ ├── ReadPageSource.java │ │ ├── ReadScreenSize.java │ │ ├── ResetApp.java │ │ ├── RunAppInBackground.java │ │ ├── SendKeys.java │ │ ├── Swipe.java │ │ ├── SwitchContext.java │ │ ├── SwitchToFrame.java │ │ ├── TakeScreenshot.java │ │ ├── Tap.java │ │ ├── TapByCoordinates.java │ │ ├── TouchAndMove.java │ │ ├── WaitForCondition.java │ │ ├── core │ │ ├── AppiumHelper.java │ │ ├── AppiumTestAction.java │ │ ├── Condition.java │ │ ├── CustomConditions.java │ │ ├── ElementWrapper.java │ │ ├── SwipeCoordinates.java │ │ ├── SwipeOptions.java │ │ ├── SwipingAction.java │ │ ├── SwipingWaitingAction.java │ │ └── WaitingAction.java │ │ └── serialization │ │ └── AppiumDriverSerializer.java ├── base │ ├── .gitignore │ ├── nb-configuration.xml │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── org │ │ │ │ └── getopentest │ │ │ │ ├── Main.java │ │ │ │ ├── actions │ │ │ │ ├── Assert.java │ │ │ │ ├── Delay.java │ │ │ │ ├── ExecuteRegex.java │ │ │ │ ├── Format.java │ │ │ │ ├── GetTestAsset.java │ │ │ │ ├── HttpRequest.java │ │ │ │ ├── Log.java │ │ │ │ ├── ReadCsv.java │ │ │ │ ├── ReadEmailImap.java │ │ │ │ ├── ReadTextFile.java │ │ │ │ ├── ReadXml.java │ │ │ │ ├── RunCommand.java │ │ │ │ ├── SampleAction.java │ │ │ │ ├── SendEmailSmtp.java │ │ │ │ ├── codecs │ │ │ │ │ ├── DecodeBase64.java │ │ │ │ │ ├── DecodeUtf8.java │ │ │ │ │ ├── EncodeBase64.java │ │ │ │ │ └── EncodeUtf8.java │ │ │ │ ├── compression │ │ │ │ │ ├── CompressGzip.java │ │ │ │ │ ├── ExtractGzip.java │ │ │ │ │ └── ExtractZip.java │ │ │ │ ├── db │ │ │ │ │ ├── JdbcQuery.java │ │ │ │ │ └── JdbcUpdate.java │ │ │ │ ├── files │ │ │ │ │ ├── DeleteFiles.java │ │ │ │ │ ├── GetFromSftp.java │ │ │ │ │ ├── ListFiles.java │ │ │ │ │ ├── PutToSftp.java │ │ │ │ │ ├── ReadTextFile.java │ │ │ │ │ └── WriteTextFile.java │ │ │ │ ├── s3 │ │ │ │ │ ├── GetS3Metadata.java │ │ │ │ │ ├── GetS3Object.java │ │ │ │ │ └── PutS3Object.java │ │ │ │ └── visual │ │ │ │ │ └── ClickImage.java │ │ │ │ ├── annotations │ │ │ │ ├── TestActionArgument.java │ │ │ │ ├── TestActionArguments.java │ │ │ │ ├── TestActionClass.java │ │ │ │ ├── TestActionOutput.java │ │ │ │ ├── TestActionOutputs.java │ │ │ │ └── Type.java │ │ │ │ ├── base │ │ │ │ ├── MacroAction.java │ │ │ │ ├── ScriptAction.java │ │ │ │ ├── SessionStatusResponse.java │ │ │ │ ├── TestAction.java │ │ │ │ ├── TestActionInfo.java │ │ │ │ ├── TestActor.java │ │ │ │ ├── TestActorEvents.java │ │ │ │ └── TestSessionStatus.java │ │ │ │ ├── contracts │ │ │ │ ├── IAutomator.java │ │ │ │ ├── IImageFinder.java │ │ │ │ ├── ILogger.java │ │ │ │ └── ITestActor.java │ │ │ │ ├── exceptions │ │ │ │ ├── ArgumentException.java │ │ │ │ ├── CheckpointException.java │ │ │ │ ├── ImageNotFoundException.java │ │ │ │ ├── IntentionalFailException.java │ │ │ │ └── SkipTestException.java │ │ │ │ ├── http │ │ │ │ ├── ContentType.java │ │ │ │ ├── HttpDeleteWithBody.java │ │ │ │ ├── HttpRequest.java │ │ │ │ ├── HttpRequestOptions.java │ │ │ │ ├── HttpVerb.java │ │ │ │ └── NoopTrustManager.java │ │ │ │ ├── logging │ │ │ │ ├── BaseLogger.java │ │ │ │ ├── ConsoleLogger.java │ │ │ │ ├── HttpLogger.java │ │ │ │ ├── LogEntry.java │ │ │ │ ├── LogLevel.java │ │ │ │ ├── Logger.java │ │ │ │ └── NullLogger.java │ │ │ │ ├── serialization │ │ │ │ ├── json │ │ │ │ │ ├── BufferedImageSerializer.java │ │ │ │ │ ├── DoubleSerializer.java │ │ │ │ │ ├── DuplicateFieldExclusionStrategy.java │ │ │ │ │ ├── ScriptObjectMirrorSerializer.java │ │ │ │ │ ├── TrimmableMap.java │ │ │ │ │ └── TrimmableMapSerializer.java │ │ │ │ └── yaml │ │ │ │ │ └── SkipNullRepresenter.java │ │ │ │ ├── testdef │ │ │ │ ├── MacroDefinition.java │ │ │ │ ├── TestDefAction.java │ │ │ │ ├── TestDefActor.java │ │ │ │ ├── TestDefSegment.java │ │ │ │ └── TestDefinition.java │ │ │ │ ├── util │ │ │ │ ├── Automator.java │ │ │ │ ├── Config.java │ │ │ │ ├── Encryptor.java │ │ │ │ ├── Factory.java │ │ │ │ ├── ImageCompareResult.java │ │ │ │ ├── ImageUtil.java │ │ │ │ ├── JarUtil.java │ │ │ │ ├── MainUtil.java │ │ │ │ ├── RegexUtil.java │ │ │ │ ├── ServerRequest.java │ │ │ │ ├── StringUtil.java │ │ │ │ ├── TesseractOcr.java │ │ │ │ ├── TypeConverter.java │ │ │ │ └── TypeUtil.java │ │ │ │ └── visual │ │ │ │ ├── Circle.java │ │ │ │ ├── CvHelper.java │ │ │ │ ├── Highlighter.java │ │ │ │ ├── ImageFinder.java │ │ │ │ ├── ImageFinderResult.java │ │ │ │ └── MatchingMethod.java │ │ └── resources │ │ │ ├── actor.test.properties │ │ │ ├── actor.test.yaml │ │ │ └── js │ │ │ └── helpers.js │ │ └── test │ │ └── java │ │ └── org │ │ └── getopentest │ │ ├── actions │ │ ├── ExecuteRegexNGTest.java │ │ └── ReadXmlNGTest.java │ │ ├── base │ │ ├── DummyClass.java │ │ ├── TestActionNGTest.java │ │ └── TestActorNGTest.java │ │ ├── logging │ │ ├── BaseLoggerNGTest.java │ │ └── TestLogger.java │ │ └── util │ │ ├── ConfigNGTest.java │ │ ├── EncryptorNGTest.java │ │ ├── StringUtilNGTest.java │ │ └── TypeConverterNGTest.java └── selenium │ ├── .gitignore │ ├── pom.xml │ └── src │ ├── main │ └── java │ │ └── org │ │ └── getopentest │ │ └── selenium │ │ ├── ActionsClick.java │ │ ├── ActionsClickAndHold.java │ │ ├── ActionsContextClick.java │ │ ├── ActionsDoubleClick.java │ │ ├── ActionsDragAndDrop.java │ │ ├── ActionsDragAndDropBy.java │ │ ├── ActionsKeyDown.java │ │ ├── ActionsKeyUp.java │ │ ├── ActionsMoveByOffset.java │ │ ├── ActionsMoveTo.java │ │ ├── ActionsMoveToElement.java │ │ ├── ActionsPause.java │ │ ├── ActionsPerform.java │ │ ├── ActionsRelease.java │ │ ├── ActionsSendKeys.java │ │ ├── AddCookie.java │ │ ├── AssertAttributeValue.java │ │ ├── AssertCssProperty.java │ │ ├── AssertElementDisabled.java │ │ ├── AssertElementEnabled.java │ │ ├── AssertElementFocused.java │ │ ├── AssertElementHasAttribute.java │ │ ├── AssertElementHasClass.java │ │ ├── AssertElementImage.java │ │ ├── AssertElementNotPresent.java │ │ ├── AssertElementNotReadOnly.java │ │ ├── AssertElementNotSelected.java │ │ ├── AssertElementNotVisible.java │ │ ├── AssertElementPresent.java │ │ ├── AssertElementReadOnly.java │ │ ├── AssertElementSelected.java │ │ ├── AssertElementText.java │ │ ├── AssertElementVisible.java │ │ ├── AssertListOption.java │ │ ├── AssertPageTitle.java │ │ ├── AssertUrl.java │ │ ├── ClearContent.java │ │ ├── Click.java │ │ ├── CloseBrowser.java │ │ ├── CloseWindow.java │ │ ├── DeleteCookie.java │ │ ├── DeselectListOption.java │ │ ├── ExecuteScript.java │ │ ├── GetActiveElement.java │ │ ├── GetElements.java │ │ ├── HandleAlert.java │ │ ├── HandleModal.java │ │ ├── NavigateBack.java │ │ ├── NavigateForward.java │ │ ├── NavigateTo.java │ │ ├── ReadBrowserLogs.java │ │ ├── ReadCookie.java │ │ ├── ReadCssProperty.java │ │ ├── ReadCurrentUrl.java │ │ ├── ReadElementAspect.java │ │ ├── ReadElementAttribute.java │ │ ├── ReadElementCount.java │ │ ├── ReadElementText.java │ │ ├── ReadPageSource.java │ │ ├── ReadPageTitle.java │ │ ├── ReadUrl.java │ │ ├── SelectListOption.java │ │ ├── SendKeys.java │ │ ├── SetBrowserAspect.java │ │ ├── SwitchToDefaultContent.java │ │ ├── SwitchToFrame.java │ │ ├── SwitchToLastWindow.java │ │ ├── SwitchToWindow.java │ │ ├── TakeScreenshot.java │ │ └── core │ │ ├── CustomConditions.java │ │ ├── ElementWrapper.java │ │ ├── SeleniumHelper.java │ │ └── SeleniumTestAction.java │ └── test │ └── java │ └── org │ └── getopentest │ └── selenium │ └── core │ └── SeleniumHelperNGTest.java ├── attribution ├── attribution-maven.txt ├── attribution-node.txt ├── attribution-other.txt └── manual.txt ├── build ├── README.md ├── config.default.json ├── config.sample.json ├── lib │ ├── config-loader.js │ ├── helpers.js │ └── root-dir.js ├── module-opentest-actor │ ├── README.md │ ├── bin │ │ └── opentest-actor.js │ ├── index.js │ ├── package-lock.json │ └── package.json ├── module-opentest │ ├── .vscode │ │ └── launch.json │ ├── README.md │ ├── helpers.js │ ├── opentest.js │ ├── package-lock.json │ ├── package.json │ ├── session.js │ └── test-repo │ │ ├── macros │ │ └── github │ │ │ └── AssertRepoHasNonEmptyWiki.yaml │ │ ├── scripts │ │ └── moment.min.js │ │ ├── templates │ │ ├── github │ │ │ └── GitHub tests.yaml │ │ └── other │ │ │ └── Quick start tests.yaml │ │ └── tests │ │ ├── api │ │ └── GitHub API test.yaml │ │ ├── mobile │ │ └── Mobile app test.yaml │ │ ├── other │ │ └── Using an external JavaScript file.yaml │ │ └── web │ │ ├── Find the React repo on GitHub's website.yaml │ │ └── Verify GitHub repos have non-empty wiki.yaml └── tasks │ ├── build-projects.js │ ├── make-modules.js │ ├── publish-modules.js │ ├── pull-projects.js │ └── update-version.js ├── package-lock.json ├── package.json └── server ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .gitlab-ci.yml ├── .npmignore ├── .vscode ├── launch.json └── settings.json ├── README.md ├── bin └── opentest-server.js ├── gulpfile.js ├── index.js ├── package-lock.json ├── package.json ├── server.sample.yaml ├── src ├── controllers │ ├── api.ts │ └── ui.ts ├── express-app.ts ├── index.ts ├── lib │ ├── actor-helper.ts │ ├── build-info.ts │ ├── config-loader.ts │ ├── constants.ts │ ├── db-manager.ts │ ├── dirs.ts │ ├── express-session.ts │ ├── file-walker.ts │ ├── helpers.ts │ ├── log-manager.ts │ ├── nedb-adapter.ts │ ├── session-helper.ts │ ├── test-repo.ts │ ├── types.ts │ └── websocket-notifier.ts ├── public │ ├── all.min.css │ ├── css │ │ ├── animate.min.css │ │ ├── bootstrap.min.css │ │ ├── ekko-lightbox.css │ │ ├── fontawesome-all.min.css │ │ ├── session.css │ │ └── style.css │ ├── favicon.ico │ ├── img │ │ ├── loader-circle.png │ │ ├── opentest.svg │ │ └── tricolon.svg │ ├── js │ │ ├── lib │ │ │ ├── angular.js │ │ │ ├── angular.min.js │ │ │ ├── angular.min.js.map │ │ │ ├── bootstrap-notify.min.js │ │ │ ├── bootstrap.min.js │ │ │ ├── ekko-lightbox.min.js │ │ │ ├── jquery.min.js │ │ │ ├── js.cookie.js │ │ │ ├── moment-timezone.min.js │ │ │ └── moment.min.js │ │ └── ng │ │ │ ├── home-ctrl.js │ │ │ ├── ng-app.js │ │ │ ├── root-ctrl.js │ │ │ └── session-ctrl.js │ └── webfonts │ │ ├── fa-brands-400.eot │ │ ├── fa-brands-400.svg │ │ ├── fa-brands-400.ttf │ │ ├── fa-brands-400.woff │ │ ├── fa-brands-400.woff2 │ │ ├── fa-regular-400.eot │ │ ├── fa-regular-400.svg │ │ ├── fa-regular-400.ttf │ │ ├── fa-regular-400.woff │ │ ├── fa-regular-400.woff2 │ │ ├── fa-solid-900.eot │ │ ├── fa-solid-900.svg │ │ ├── fa-solid-900.ttf │ │ ├── fa-solid-900.woff │ │ └── fa-solid-900.woff2 ├── service.ts ├── start.ts ├── test │ ├── integration │ │ └── api.test.ts │ ├── repo │ │ └── tests │ │ │ └── Dummy.yaml │ └── unit │ │ ├── config-loader.test.ts │ │ ├── helpers.test.ts │ │ ├── nedb-adapter.test.ts │ │ └── test-repo.test.ts └── views │ ├── home.pug │ ├── layout.pug │ └── session.pug └── tsconfig.json /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /.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 | } -------------------------------------------------------------------------------- /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/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/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/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/actor/src/main/resources/run.bat: -------------------------------------------------------------------------------- 1 | title ACTOR 2 | java -cp "*;jars/*;dependency-jars/*" org.getopentest.Main -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/base/nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | JDK_1.8 17 | 18 | 19 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/annotations/TestActionArguments.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | public @interface TestActionArguments { 4 | TestActionArgument[] value(); 5 | } 6 | -------------------------------------------------------------------------------- /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/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/annotations/TestActionOutputs.java: -------------------------------------------------------------------------------- 1 | package org.getopentest.annotations; 2 | 3 | public @interface TestActionOutputs { 4 | TestActionOutput[] value(); 5 | } 6 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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 | -------------------------------------------------------------------------------- /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/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/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/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/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/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/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/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/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/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/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/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/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/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 | -------------------------------------------------------------------------------- /build/README.md: -------------------------------------------------------------------------------- 1 | Build steps: 2 | * `npm run update-version 0.0.0` 3 | * Create commit: `chore: bump version to 0.0.0` 4 | * `npm run build` 5 | 6 | Publish commands (pick one): 7 | * Local: `npm run publish-local` 8 | * Beta: `npm run publish-npm-beta` 9 | * Latest: `npm run publish-npm-latest` 10 | 11 | Add Git tag: 12 | * `git tag v0.0.0` 13 | 14 | Publish beta version as latest: 15 | * `npm dist-tag add opentest-actor@0.0.0 latest` 16 | * `npm dist-tag add opentest-server@0.0.0 latest` 17 | * `npm dist-tag add opentest@0.0.0 latest` -------------------------------------------------------------------------------- /build/config.default.json: -------------------------------------------------------------------------------- 1 | { 2 | "actor": { 3 | "projectDir": "actor/actor" 4 | } 5 | } -------------------------------------------------------------------------------- /build/config.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "actor": { 3 | "projectDir": "custom/actor-custom" 4 | }, 5 | "customProjects": [ 6 | { 7 | "dirName": "actor-custom", 8 | "repoUrl": "" 9 | }, 10 | { 11 | "dirName": "plugin1", 12 | "repoUrl": "" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /build/lib/config-loader.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const shelljs = require('shelljs'); 4 | 5 | // If config file is missing, use default config 6 | const configFile = path.normalize(path.join(__dirname, '..', 'config.json')); 7 | const defaultConfigFile = path.normalize(path.join(__dirname, '..', 'config.default.json')); 8 | if (!fs.existsSync(configFile) && fs.existsSync(defaultConfigFile)) { 9 | shelljs.cp(defaultConfigFile, configFile); 10 | } 11 | 12 | module.exports.config = require(path.join('..', 'config.json')); 13 | -------------------------------------------------------------------------------- /build/lib/helpers.js: -------------------------------------------------------------------------------- 1 | /** Utility function for string formatting. 2 | * Example: format("{0}, {1}!", "Hello", "world") // "Hello, world!" 3 | */ 4 | exports.format = function(text) { 5 | const args = arguments; 6 | let arg; 7 | let argIndex; 8 | 9 | return text.replace( 10 | /\{(\d+)\}/g, 11 | function (match, index) { 12 | argIndex = Number(index) + 1; 13 | arg = args[argIndex]; 14 | switch (typeof arg) { 15 | case 'number': 16 | case 'string': return args[argIndex]; 17 | case 'object': return JSON.stringify(args[argIndex]); 18 | case 'undefined': return match; 19 | default: return args[argIndex]; 20 | } 21 | }); 22 | } 23 | 24 | /** Output text at the console in a distinctive way, as a means to mark 25 | * the start of a new section in the log and improve readability */ 26 | exports.logTitle = function(text) { 27 | const width = 80; 28 | console.log('\n' + '='.repeat(width)); 29 | console.log('' + text + ' '.repeat(width - text.length - 8) + ' '); 30 | console.log('='.repeat(width)); 31 | } -------------------------------------------------------------------------------- /build/lib/root-dir.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = path.join(__dirname, '..', '..'); -------------------------------------------------------------------------------- /build/module-opentest-actor/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 homepage](https://getopentest.org/). -------------------------------------------------------------------------------- /build/module-opentest-actor/bin/opentest-actor.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const spawn = require('child_process').spawn; 3 | const path = require('path'); 4 | const yargs = require('yargs'); 5 | 6 | yargs.alias('w', 'workdir'); 7 | 8 | const workDir = yargs.argv.workdir || process.cwd(); 9 | const classPath = path.join(__dirname, 'jars', '*').replace(/\\/g, '/') 10 | 11 | const newProcess = spawn( 12 | 'java', 13 | ['-cp', classPath, 'org.getopentest.Main', '--workdir', workDir], 14 | { stdio: 'inherit' }); 15 | 16 | newProcess.on('error', function (err) { 17 | console.log('ERROR: ' + err.message); 18 | if (err.code === 'ENOENT') { 19 | console.log('ERROR: Failed to start Java process. Please ensure that the Java runtime is properly installed.'); 20 | } 21 | }); -------------------------------------------------------------------------------- /build/module-opentest-actor/index.js: -------------------------------------------------------------------------------- 1 | const spawn = require('child_process').spawn; 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | const yargs = require('yargs'); 5 | 6 | yargs.alias('w', 'workdir'); 7 | 8 | module.exports = { 9 | start: start 10 | }; 11 | 12 | function start(options) { 13 | options = options || {}; 14 | 15 | const workDir = /** @type string */ (options.workDir || yargs.argv.workdir || process.cwd()); 16 | 17 | const opentestJarsPath = path.join(__dirname, 'jars', '*').replace(/\\/g, '/'); 18 | const actorJarsPath = path.join(workDir, 'user-jars', '*').replace(/\\/g, '/'); 19 | const classPath = `${actorJarsPath}${path.delimiter}${opentestJarsPath}`; 20 | 21 | options.args = options.args || []; 22 | 23 | let allArgs = ['-cp', classPath, 'org.getopentest.Main', '--workdir', workDir]; 24 | allArgs = allArgs.concat(options.args); 25 | 26 | const newProcess = spawn( 27 | 'java', 28 | allArgs, 29 | { stdio: 'inherit' }); 30 | 31 | newProcess.on('error', function (err) { 32 | console.log('ERROR: ' + err.message); 33 | if (err.code === 'ENOENT') { 34 | console.log('ERROR: Failed to start Java process. Please ensure that the Java runtime is properly installed.'); 35 | } 36 | }); 37 | 38 | // Write server process ID to disk. This can be used later to easily kill 39 | // the process from a CI pipeline or other automation tools. 40 | const pid = newProcess.pid || 0; 41 | try { 42 | fs.writeFileSync(path.join(workDir, 'actor.pid'), String(pid)); 43 | } catch { 44 | // Nothing to do here 45 | } 46 | 47 | console.log(`Test actor PID: ${pid}`); 48 | 49 | return pid; 50 | } -------------------------------------------------------------------------------- /build/module-opentest-actor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opentest-actor", 3 | "version": "1.4.2", 4 | "description": "This is the OpenTest actor module. For installation instructions and documentation please see the project website at https://getopentest.org.", 5 | "author": "Adrian Theodorescu", 6 | "homepage": "https://getopentest.org/", 7 | "license": "MIT", 8 | "bin": { 9 | "opentest-actor": "./bin/opentest-actor.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/mcdcorp/opentest.git" 14 | }, 15 | "dependencies": { 16 | "yargs": "^10.0.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /build/module-opentest/.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 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/opentest.js", 12 | "args": [ 13 | "session", 14 | "create", 15 | "--template", 16 | "dir1/Template1", 17 | "--wait", 18 | "60", 19 | "--out", 20 | "junit.xml" 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /build/module-opentest/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 homepage](https://getopentest.org/). -------------------------------------------------------------------------------- /build/module-opentest/helpers.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | escapeRegEx: escapeRegEx, 3 | format: format, 4 | trimChars: trimChars 5 | } 6 | 7 | /** Escape a string so we can safely use it in a regular expression. */ 8 | function escapeRegEx(text) { 9 | return text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); 10 | } 11 | 12 | /** Utility function for string formatting. 13 | * Example: format("{0}, {1}!", "Hello", "world") // "Hello, world!" */ 14 | function format(text) { 15 | var args = arguments; 16 | var arg; 17 | var argIndex; 18 | 19 | return text.replace( 20 | /\{(\d+)\}/g, 21 | function (match, index) { 22 | argIndex = Number(index) + 1; 23 | arg = args[argIndex]; 24 | switch (typeof arg) { 25 | case 'number': 26 | case 'string': return args[argIndex]; 27 | case 'object': return JSON.stringify(args[argIndex]); 28 | case 'undefined': return match; 29 | default: return args[argIndex]; 30 | } 31 | }); 32 | } 33 | 34 | /** Trim specified characters from the beginning and end of a string. */ 35 | function trimChars(text, chars = ' \t\r\n\f') { 36 | if (!text) { 37 | return ''; 38 | } 39 | 40 | const escapedChars = escapeRegEx(chars); 41 | const regex = new RegExp( 42 | format('^[{0}]+|[{0}]+$', escapedChars), 43 | 'g'); 44 | return text.replace(regex, ''); 45 | } -------------------------------------------------------------------------------- /build/module-opentest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opentest", 3 | "version": "1.4.2", 4 | "description": "Functional test automation framework for web, mobile and REST APIs. For installation instructions and documentation please see the project website at https://getopentest.org.", 5 | "author": "Adrian Theodorescu", 6 | "homepage": "https://getopentest.org/", 7 | "license": "MIT", 8 | "bin": { 9 | "opentest": "./opentest.js", 10 | "ots": "./opentest.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/mcdcorp/opentest.git" 15 | }, 16 | "tags": [ 17 | "test", 18 | "automation", 19 | "selenium", 20 | "appium", 21 | "ios", 22 | "android", 23 | "functional" 24 | ], 25 | "bundledDependencies": [], 26 | "dependencies": { 27 | "axios": "^0.21.1", 28 | "chalk": "^2.4.2", 29 | "inquirer": "^4.0.2", 30 | "opentest-actor": "1.4.2", 31 | "opentest-server": "1.4.2", 32 | "shelljs": "^0.8.4", 33 | "url-join": "^4.0.1", 34 | "yargs": "^10.1.2" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /build/module-opentest/test-repo/macros/github/AssertRepoHasNonEmptyWiki.yaml: -------------------------------------------------------------------------------- 1 | # This macro takes one single argument, called "repo", which must contain the name of 2 | # the repo owner and the repo itself, separated by a "/" (e.g. "facebook/react"). 3 | description: Verify that a GitHub repo has a wiki section with content in it 4 | actions: 5 | - description: Navigate to the wiki page 6 | action: org.getopentest.selenium.NavigateTo 7 | args: 8 | url: $format("https://github.com/{0}/wiki", $macroArgs.repo) 9 | 10 | - description: Verify there is no button that says "Create the first page" 11 | action: org.getopentest.selenium.AssertElementNotVisible 12 | args: 13 | locator: {xpath: "//a[contains(text(), 'Create the first page')]"} 14 | 15 | - description: Read the URL of the current page 16 | action: org.getopentest.selenium.ReadCurrentUrl 17 | args: 18 | $localData: 19 | wikiPageUrl: $output.url 20 | 21 | # For some repos, GitHub will redirect the user to the repo's homepage if the repo 22 | # has no wiki page, so we must make sure to fail the test if that's the case 23 | - description: Verify that we are at the wiki URL 24 | script: | 25 | if ($localData.wikiPageUrl.indexOf("/wiki") == -1) { 26 | $fail("The wiki page doesn't exist"); 27 | } 28 | 29 | # For most repos, if no wiki page exists, the default wiki page will show a button 30 | # saying "Create the first page" 31 | - description: Verify there is no button that says "Create the first page" 32 | action: org.getopentest.selenium.AssertElementNotVisible 33 | args: 34 | locator: {xpath: "//a[contains(text(), 'Create the first page')]"} -------------------------------------------------------------------------------- /build/module-opentest/test-repo/templates/github/GitHub tests.yaml: -------------------------------------------------------------------------------- 1 | description: A test session template that runs two GitHub web UI tests 2 | sessionLabel: GitHub web UI tests 3 | maxIterations: 1 4 | tests: 5 | - name: Find the React repo on GitHub's website 6 | path: web 7 | 8 | - name: Verify GitHub repos have non-empty wiki 9 | path: web -------------------------------------------------------------------------------- /build/module-opentest/test-repo/templates/other/Quick start tests.yaml: -------------------------------------------------------------------------------- 1 | description: Runs the sample tests that don't require any configuration 2 | sessionLabel: Quick start tests 3 | maxIterations: 1 4 | tests: 5 | - name: GitHub API test 6 | path: api 7 | 8 | - name: Using an external JavaScript file 9 | path: other -------------------------------------------------------------------------------- /build/module-opentest/test-repo/tests/api/GitHub API test.yaml: -------------------------------------------------------------------------------- 1 | description: Verify that the GitHub API returns the branches for the React repo 2 | actors: 3 | - actor: ACTOR1 4 | segments: 5 | - segment: 1 6 | actions: 7 | - description: Call the GET /repos/:owner/:repo/branches API 8 | action: org.getopentest.actions.HttpRequest 9 | args: 10 | url: https://api.github.com/repos/facebook/react/branches 11 | verb: GET 12 | $localData: 13 | branches: $output.body; 14 | 15 | - description: | 16 | Verify that the branches array was returned and is not empty 17 | script: | 18 | var branches = $localData.branches; 19 | if (!branches || !(branches.length > 0)) { 20 | $fail("The response body was invalid or contained no branch elements."); 21 | } else { 22 | $log($format("The GitHub API returned {0} branches", branches.length)); 23 | } -------------------------------------------------------------------------------- /build/module-opentest/test-repo/tests/mobile/Mobile app test.yaml: -------------------------------------------------------------------------------- 1 | description: | 2 | This test is built for an imaginary app and is forever doomed to fail. You 3 | need to change it so it runs against your own app. The configuration details 4 | (Appium server URL, desired capabilities, etc.) must be specified in the 5 | actor.yaml file for the test actor you'll be using. 6 | actors: 7 | - actor: ACTOR1 8 | segments: 9 | - segment: 1 10 | actions: 11 | - description: Type the username 12 | action: org.getopentest.appium.SendKeys 13 | args: 14 | locator: { xpath: "//*[contains(@resource-id,'username')]" } 15 | text: john.doe 16 | 17 | - description: Type the password 18 | action: org.getopentest.appium.SendKeys 19 | args: 20 | locator: { xpath: "//*[contains(@resource-id,'password')]" } 21 | text: mysecurepassword 22 | 23 | - description: Tap the Log In button 24 | action: org.getopentest.appium.Click 25 | args: 26 | locator: { xpath: "//*[contains(@resource-id,'login')]" } -------------------------------------------------------------------------------- /build/module-opentest/test-repo/tests/other/Using an external JavaScript file.yaml: -------------------------------------------------------------------------------- 1 | # This test loads the moment.js library from an external JS file. External JS files 2 | # must be stored in the "scripts" directory, in the root of the test repo. 3 | description: Using the moment.js library to manipulate date and time values 4 | includes: moment.min.js 5 | actors: 6 | - actor: ACTOR1 7 | segments: 8 | - segment: 1 9 | actions: 10 | - description: Calculate the time and date for exactly one week from now 11 | script: | 12 | var oneWeekFromNow = moment().add(7, "days").format("YYYY/MM/DD HH:mm:ss"); 13 | $log("The date and time for exactly one week from now is " + oneWeekFromNow); -------------------------------------------------------------------------------- /build/module-opentest/test-repo/tests/web/Find the React repo on GitHub's website.yaml: -------------------------------------------------------------------------------- 1 | description: | 2 | Navigate to the GitHub website, find the React repo using the 3 | search functionality and go to the repo's homepage 4 | actors: 5 | - actor: ACTOR1 6 | segments: 7 | - segment: 1 8 | actions: 9 | - description: Navigate to the GitHub homepage 10 | action: org.getopentest.selenium.NavigateTo 11 | args: 12 | url: https://github.com/ 13 | 14 | - description: Enter "react" in the search box 15 | action: org.getopentest.selenium.SendKeys 16 | args: 17 | locator: {css: "input[name='q']"} 18 | text: react 19 | sendEnter: true 20 | 21 | - description: Click the React link in the search results 22 | action: org.getopentest.selenium.Click 23 | args: 24 | locator: {css: "a[href='/facebook/react']"} 25 | 26 | - description: Verify that the Clone button exists and is visible 27 | action: org.getopentest.selenium.AssertElementVisible 28 | args: 29 | locator: {xpath: "//*[contains(@class,'btn')][contains(text(),'Clone')]"} -------------------------------------------------------------------------------- /build/module-opentest/test-repo/tests/web/Verify GitHub repos have non-empty wiki.yaml: -------------------------------------------------------------------------------- 1 | description: | 2 | Verifies that GitHub repos have non-empty wiki pages. This test demonstrates 3 | two major features of OpenTest: data-driven testing and macro actions. 4 | Data-driven tests are created by populating the dataSet property of the test 5 | with an array of data records to iterate on. The data records can be simple 6 | strings or other primitive values (as we have in this test), or complex objects 7 | with multiple properties (fields). 8 | dataSet: ["facebook/react", "tesseract-ocr/tesseract"] 9 | actors: 10 | - actor: ACTOR1 11 | segments: 12 | - segment: 1 13 | actions: 14 | # The action below is a so-called "macro action", which can contain 15 | # multiple regular actions and scripts. You can find its definition 16 | # in the "macros" directory 17 | - macro: github.AssertRepoHasNonEmptyWiki 18 | args: 19 | repo: $dataRecord -------------------------------------------------------------------------------- /build/tasks/publish-modules.js: -------------------------------------------------------------------------------- 1 | const helpers = require('../lib/helpers.js'); 2 | const path = require('path'); 3 | const rootDir = require('../lib/root-dir.js'); 4 | const shelljs = require('shelljs'); 5 | const yargs = require('yargs'); 6 | 7 | helpers.logTitle('Publishing Node.js modules...'); 8 | 9 | if (yargs.argv.registry) { 10 | console.log(`Publishing packages to ${yargs.argv.registry}...`); 11 | 12 | let execResult; 13 | const npmTag = yargs.argv.tag ? yargs.argv.tag.trim() : 'beta'; 14 | let cmdLine = `npm publish --registry ${yargs.argv.registry} --tag=${npmTag}`; 15 | 16 | console.log(`Publishing module opentest-actor...`); 17 | shelljs.cd(path.join(rootDir, 'dist', 'module-opentest-actor')); 18 | execResult = shelljs.exec(cmdLine); 19 | if (execResult.code != 0) { 20 | throw new Error('Failed to publish module opentest-actor.'); 21 | } 22 | 23 | console.log(`Publishing module opentest-server...`); 24 | shelljs.cd(path.join(rootDir, 'dist', 'module-opentest-server')); 25 | execResult = shelljs.exec(cmdLine); 26 | if (execResult.code != 0) { 27 | throw new Error('Failed to publish module opentest-server.'); 28 | } 29 | 30 | console.log(`Publishing module opentest...`); 31 | shelljs.cd(path.join(rootDir, 'dist', 'module-opentest')); 32 | execResult = shelljs.exec(cmdLine); 33 | if (execResult.code != 0) { 34 | throw new Error('Failed to publish module opentest.'); 35 | } 36 | } else { 37 | throw new Error('Package registry URL was not specified. Use the "--registry" argument to provide the URL.'); 38 | } -------------------------------------------------------------------------------- /build/tasks/pull-projects.js: -------------------------------------------------------------------------------- 1 | const config = require('../lib/config-loader.js').config; 2 | const helpers = require('../lib/helpers.js'); 3 | const path = require('path'); 4 | const rootDir = require('../lib/root-dir.js'); 5 | const shelljs = require('shelljs'); 6 | 7 | helpers.logTitle('Cloning projects...'); 8 | 9 | if (config.customProjects && config.customProjects.length) { 10 | config.customProjects.forEach(project => { 11 | cloneRepo(project); 12 | }); 13 | } 14 | 15 | console.log('Done cloning projects'); 16 | 17 | function cloneRepo(project) { 18 | console.log(`Processing project ${project.dirName}...`); 19 | 20 | const customProjectsDir = path.join(rootDir, 'custom'); 21 | shelljs.mkdir('-p', customProjectsDir); 22 | shelljs.cd(customProjectsDir); 23 | 24 | console.log(`Deleting ${project.dirName}...`); 25 | shelljs.rm('-rf', path.join(customProjectsDir, project.dirName)); 26 | 27 | console.log(`Cloning ${project.dirName}...`); 28 | let returnVal; 29 | returnVal = shelljs.exec(`git clone --depth 1 ${project.repoUrl} ${project.dirName}`); 30 | if (returnVal.code != 0) { 31 | throw new Error('Failed cloning project ' + project.dirName + '.\n' + returnVal.stderr); 32 | } 33 | 34 | const gitRef = project.gitRef || 'master'; 35 | shelljs.cd(path.join(customProjectsDir, project.dirName)); 36 | returnVal = shelljs.exec(`git checkout ${gitRef}`); 37 | if (returnVal.code != 0) { 38 | throw new Error(`Failed checking out branch ${gitRef}.\n${returnVal.stderr}`); 39 | } 40 | } -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /server/.eslintignore: -------------------------------------------------------------------------------- 1 | src/public/js/lib/* -------------------------------------------------------------------------------- /server/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": 6 4 | }, 5 | "rules": { 6 | "semi": "warn" 7 | } 8 | } -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/bin/opentest-server.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | "use strict"; 3 | const syncService = require("./dist/service"); 4 | syncService.start(); -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/service'); -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /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/index.ts: -------------------------------------------------------------------------------- 1 | import * as syncService from './service'; 2 | 3 | module.exports = syncService; -------------------------------------------------------------------------------- /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(); -------------------------------------------------------------------------------- /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 | }; -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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 | }); -------------------------------------------------------------------------------- /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 | } -------------------------------------------------------------------------------- /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/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 | } -------------------------------------------------------------------------------- /server/src/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/favicon.ico -------------------------------------------------------------------------------- /server/src/public/img/loader-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/img/loader-circle.png -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-brands-400.eot -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-brands-400.woff -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-regular-400.eot -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-regular-400.woff -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-solid-900.woff -------------------------------------------------------------------------------- /server/src/public/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcdcorp/opentest/60ade6ac6a8dce228b6796f78b4d870b15b124f0/server/src/public/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /server/src/start.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as syncService from './service'; 3 | 4 | syncService.start(); -------------------------------------------------------------------------------- /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"); -------------------------------------------------------------------------------- /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 | }); -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "outDir": "dist", 6 | "sourceMap": true, 7 | "target": "es6" 8 | } 9 | } --------------------------------------------------------------------------------