From c9eae207e8ba07c6f2e38903fc6f47af330c180d Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Tue, 16 Jul 2024 13:50:28 +0200 Subject: [PATCH 01/14] [TPS2021-1393] Mobile testing enablement --- .../quickstarters/pages/e2e-spock-geb.adoc | 51 ++-- e2e-spock-geb/Jenkinsfile.template | 22 ++ e2e-spock-geb/README.md | 2 +- e2e-spock-geb/files/README.md | 280 ++++++++++++++++++ e2e-spock-geb/files/application/EmptyFile.apk | 0 e2e-spock-geb/files/build.gradle | 72 +++-- .../modules/DemoManualMenuModule.groovy | 14 + .../groovy/pages/DemoGebHomePage.groovy | 15 + .../pages/DemoGitHubAcceptanceHomePage.groovy | 8 + .../groovy/pages/DemoTheBookOfGebPage.groovy | 7 + .../groovy/specs/DemoGebHomePageSpec.groovy | 30 ++ .../DemoGitHubAcceptanceHomeSpec.groovy} | 20 +- .../groovy/specs/DemoGoogleKeepSpec.groovy | 41 +++ .../files/src/test/resources/GebConfig.groovy | 118 ++++++-- .../src/test/resources/application.properties | 2 +- .../resources/{ => helpers}/SpecHelper.groovy | 25 +- 16 files changed, 636 insertions(+), 71 deletions(-) create mode 100644 e2e-spock-geb/files/README.md create mode 100644 e2e-spock-geb/files/application/EmptyFile.apk create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy rename e2e-spock-geb/files/src/test/acceptance/groovy/{DemoAcceptanceSpec.groovy => specs/DemoGitHubAcceptanceHomeSpec.groovy} (59%) create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy rename e2e-spock-geb/files/src/test/resources/{ => helpers}/SpecHelper.groovy (73%) diff --git a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc index f7105d322..68b690d03 100644 --- a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc +++ b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc @@ -1,15 +1,17 @@ = End-to-end tests with Spock, Geb and Unirest (e2e-spock-geb) -spock, geb and unirest e2e testing quickstarter project +Spock, Geb, Unirest and Apium e2e testing quickstarter project == Purpose of this quickstarter -This is a spock, geb and unirest e2e testing project quickstarter with basic setup for https://jenkins.io/[Jenkins], https://www.sonarqube.org/[SonarQube] and https://gradle.org/[Gradle]. +This is a Spock, Geb, Unirest and Apium e2e testing project quickstarter with basic setup for https://jenkins.io/[Jenkins], https://www.sonarqube.org/[SonarQube], https://gradle.org/[Gradle], and https://appium.io/[Appium]. == What files / architecture is generated? ---- . +├── application +│ └── EmptyFile.apk ├── Jenkinsfile ├── .pre-commit-config.yaml ├── README.md @@ -18,7 +20,16 @@ This is a spock, geb and unirest e2e testing project quickstarter with basic set │ ├── test │ │ └── acceptance │ │ │ └── groovy -│ │ │ │ └── DemoAcceptanceSpec.groovy +│ │ │ │ └── modules +│ │ │ │ └── DemoManualMenuModule.groovy +│ │ │ │ └── pages +│ │ │ │ └── DemoGebHomePage.groovy +│ │ │ │ └── DemoGitHubAcceptanceHomePage.groovy +│ │ │ │ └── DemoTheBookOfGebPage.groovy +│ │ │ │ └── specs +│ │ │ │ └── DemoGebHomePageSpec.groovy +│ │ │ │ └── DemoGitHubAcceptanceHomeSpec.groovy +│ │ │ │ └── DemoGoogleKeepSpec.groovy │ │ │ └── java │ │ │ └── DemoAcceptanceTest.java │ │ └── installation @@ -30,11 +41,12 @@ This is a spock, geb and unirest e2e testing project quickstarter with basic set │ │ │ └── groovy │ │ │ │ └── DemoIntegrationSpec.groovy │ │ │ └── java -│ │ | └── DemoIntegrationTest.java +│ │ │ └── DemoIntegrationTest.java │ │ └── resources -│ │ └── application.properties -│ │ └── GebConfig.groovy -│ │ └── SpecHelper.groovy +│ │ │ └── helpers +│ │ │ └── SpecHelper.groovy +│ │ │ └── application.properties +│ │ │ └── GebConfig.groovy ├── gradle │ └── wrapper │ ├── gradle-wrapper.jar @@ -87,9 +99,11 @@ This project is generated by https://gradle.org/[Gradle] ******* http://unirest.io/[unirest] +******* https://appium.io/[apium] + ## Usage - how do you start after you provisioned this quickstarter -* Run command `gradlew test` in project directory to execute the end-to-end tests via spock/geb against the Google Home page and demo jUnit 5 tests. +* Run command `gradlew test` in project directory to execute the end-to-end tests via spock/geb against the demo pages and demo jUnit 5 tests. You will see the results inside a new folder 'build' in project directory. @@ -97,17 +111,18 @@ You will see the results inside a new folder 'build' in project directory. . └── build └── test-results - ├── acceptance-groovy - │ └── TEST-DemoAcceptance.xml - ├── acceptance-java + ├── acceptance-groovy-defaultDriver + ├── acceptance-java-defaultDriver + │ │── TEST-specs.DemoGebHomePageSpec.xml + │ │── TEST-specs.DemoGitHubAcceptanceHomeSpec.xml │ └── TEST-DemoAcceptanceTest.xml - ├── installation-groovy - │ └── TEST-DemoInstallation.xml - ├── installation-java + ├── installation-groovy-defaultDriver + ├── installation-java-defaultDriver + │ │── TEST-DemoInstallation.xml │ └── TEST-DemoInstallationTest.xml - ├── integration-groovy - │ └── TEST-DemoIntegration.xml - └── integration-java + ├── integration-groovy-defaultDriver + └── integration-java-defaultDriver + │── TEST-DemoIntegration.xml └── TEST-DemoIntegrationTest.xml ---- @@ -117,7 +132,7 @@ You will see the results inside a new folder 'build' in project directory. * You can see how a Java Junit 5 test are developed showing the Demo*Test.java files. * You can see how a Groovy Spock/Geb test are developed showing the Demo*Spec.groovy files. ** The url to test with Geb is configured in the property `config.application.url` inside `application.properties` -** Inside `GebConfig.groovy` you could change the default navigator (CHROME) +** Inside `GebConfig.groovy` you could see some environments with different drivers defined and a default browser. You could configure or change them as you need. == How this quickstarter is built through jenkins diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index 411e9c376..ebb18b502 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -1,9 +1,31 @@ // See https://www.opendevstack.org/ods-documentation/ for usage and customization. @Library('ods-jenkins-shared-library@@shared_library_ref@') _ +node { + sauceLabsUsername = env.SAUCE_LABS_USERNAME + sauceLabsAccessKey = env.SAUCE_LABS_ACCESS_KEY + dockerRegistry = env.DOCKER_REGISTRY +} odsComponentPipeline( imageStreamTag: '@ods_namespace@/jenkins-agent-jdk:@agent_image_tag@', + podContainers: [ + containerTemplate( + name: 'jnlp', + image: "${dockerRegistry}/ods/jenkins-agent-maven:4.x", + workingDir: '/tmp', + envVars: [ + envVar(key: 'SAUCE_LABS_ACCESS_KEY', value: sauceLabsAccessKey), + envVar(key: 'SAUCE_LABS_USERNAME', value: sauceLabsUsername) + ], + resourceRequestCpu: '100m', + resourceLimitCpu: '300m', + resourceRequestMemory: '1Gi', + resourceLimitMemory: '2Gi', + alwaysPullImage: true, + args: '${computer.jnlpmac} ${computer.name}' + ) + ], branchToEnvironmentMapping: [ 'master': 'dev', // 'release/': 'test' diff --git a/e2e-spock-geb/README.md b/e2e-spock-geb/README.md index d84b7b0db..c7249c0f2 100644 --- a/e2e-spock-geb/README.md +++ b/e2e-spock-geb/README.md @@ -2,6 +2,6 @@ Documentation is located in our [official documentation](https://www.opendevstack.org/ods-documentation/opendevstack/3.x/quickstarters/e2e-spock-geb.html) -Please update documentation in the [antora page directory](https://github.com/opendevstack/ods-project-quickstarters/tree/master/docs/modules/ROOT/pages) +Please update documentation in the [antora page directory](https://github.com/opendevstack/ods-quickstarters/tree/master/docs/modules/ROOT/pages) Tested thru [automated tests](../tests/e2e-spock-geb) diff --git a/e2e-spock-geb/files/README.md b/e2e-spock-geb/files/README.md new file mode 100644 index 000000000..8bb22ccbb --- /dev/null +++ b/e2e-spock-geb/files/README.md @@ -0,0 +1,280 @@ +# Spock & Geb end-to-end tests + +This end-to-end testing project was generated from the *e2e-spock-geb* ODS quickstarter. + +## Description + +This QuickStarter integrates three powerful tools: Spock, Geb, and Appium, each serving a unique purpose in the realm of testing and automation. + +Spock is a dynamic and comprehensive testing and specification framework designed specifically for Java and Groovy. +It allows for clear and concise testing, making it easier to write and understand tests. + +Geb, on the other hand, is a robust solution for browser automation. +It caters to functional, web, and acceptance testing, providing a seamless way to automate browser interactions. + +Appium is a versatile platform for automating mobile testing. +It supports a wide range of languages and testing frameworks, making it a go-to solution for mobile application testing. + +The purpose of this QuickStarter is to provide a customized, integrated environment that leverages the strengths of these three tools. +It simplifies the setup process, allowing you to focus on writing and executing tests. +It's designed to accelerate your testing efforts, improve efficiency, and ultimately, help deliver high-quality software. + +## Project Organization + +The project is structured as follows: + +The `src/test` directory contains all the tests, which are further divided into `acceptance`, `installation`, and `integration` subdirectories. +These directories accommodate tests written in both `groovy` and `java`. The classes are organized in a structured manner, +with designated spaces for `modules`, `pages`, and `specs`. + +In addition to these, within the src/test directory, there is a resources section. Here, you will find important configuration files such as `application.properties` and `GebConfig.groovy`. +These resources are crucial for the configuration and efficient operation of the project. + +Also within the `src/test` directory, you will find a `helpers` folder. This folder contains the `SpecHelper.groovy` file, which includes several functions designed to assist you in your development process, such as functions for capturing evidence. + +## Working with GebConfig.groovy + +The `GebConfig.groovy` file is a configuration file used by Geb for browser automation. It allows you to define various environments and set up different drivers for testing. + +### Application Properties +Loading Application Properties: This section loads the application properties using the SpecHelper class. +``` +// Load application.properties +def properties = new SpecHelper().getApplicationProperties() +``` + +### SauceLabs +SauceLabs Environment Variables: If you're using SauceLabs for testing, these environment variables are used to configure the iOS device. +Please note that a SauceLabs account is a prerequisite for this process. +``` +// Getting SauceLabs environment variables to configure IOs device +def sauceLabsUsername = System.getenv('SAUCE_LABS_USERNAME') +def sauceLabsAccessKey = System.getenv('SAUCE_LABS_ACCESS_KEY') +... +ios { +driver = { +... +IOSDriver driver = new IOSDriver(new URL("https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub"), caps); +return driver +} +``` + +### Environments + +This section defines different environments such as defaultDriver, chrome, edge, android, and ios. Each environment has its own driver setup. + +These three environments are dedicated to browser: +* defaultDriver - This driver is ready to use. +* chrome - To use this driver you must replace this system property: + ```System.setProperty("webdriver.chrome.driver", "replace by your chrome driver path")``` +* edge - To use this driver you must replace this system property: + ```System.setProperty("webdriver.edge.driver", "replace by your edge driver path")``` + +And these other two are dedicated to mobile: +* android - To use this driver you must replace some capabilities showed below: + ``` + DesiredCapabilities capabilities = new DesiredCapabilities() + capabilities.setCapability("platformName", "Android") + capabilities.setCapability("deviceName", "replace by your device name") + capabilities.setCapability("app", "replace by your application mobile path") + capabilities.setCapability("browserVersion", "replace by your android version"); + capabilities.setCapability("automationName", "UiAutomator2"); + capabilities.setCapability("autoGrantPermissions", "true"); + AndroidDriver driver = new AndroidDriver(new URL("http://127.0.0.1:4723"), caps); + return driver + ``` +* ios - To use this driver you must replace some capabilities showed below: + ``` + DesiredCapabilities capabilities = new DesiredCapabilities() + capabilities.setCapability("platformName", "iOS") + capabilities.setCapability("deviceName", "replace by your device name") + capabilities.setCapability("app", "replace by your application mobile path") + capabilities.setCapability("browserName", "replace by your browser name"); + capabilities.setCapability("browserVersion", "replace by your browser version"); + capabilities.setCapability("automationName", "XCUITest"); + capabilities.setCapability("autoGrantPermissions", "true"); + IOSDriver driver = new IOSDriver(new URL("https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub"), caps); + return driver + ``` + +### Base URL + +This refers to the root URL of the application under test. Please modify config.application.url in the 'application.properties' file, located within 'src\test\resources'. + + ```baseUrl = properties."config.application.url"``` + +### Reports Directory + +This is the directory where the Geb reports will be stored. Please modify config.reports.dir in the 'application.properties' file, located within 'src\test\resources'. + + ```reportsDir = new File(properties."config.reports.dir")``` + +## Test example + +This project is structured with different sections for `pages`, `modules`, and `specs`. Here is a walkthrough of how they interact: + +### Pages Section +In this section, we have the `DemoGebHomePage` class which defines the home page, https://gebish.org. +This class includes the title of the page and some of its content, specifically the `manuals` menu. +There is a second web page defined called DemoTheBookOfGebPage, which can be accessed through the 'manuals' menu. + + package pages + + import geb.Page + import modules.DemoManualsMenuModule + + class DemoGebHomePage extends Page { + + static url = "https://gebish.org" + + static at = { title == "Geb - Very Groovy Browser Automation" } + + static content = { + manualsMenu { module(DemoManualsMenuModule) } + } + } + + +### Modules Section +The `manuals` menu from the home page is defined as a module in this section. + + package modules + + class DemoManualsMenuModule extends geb.Module { + static content = { + toggle { $("div.menu a.manuals") } + linksContainer { $("#manuals-menu") } + links { linksContainer.find("a") } + } + + void open() { + toggle.click() + waitFor { !linksContainer.hasClass("animating") } + } + } + +### Specs Section + +#### Gebish.org example + +The test that utilizes these pages and modules is located in the `specs` section and is called `DemoGebHomePageSpec`. + +**Setup** - In the `DemoGebHomePageSpec` test, the `def setup()` method is used to define the test environment that will be used for the test. + +**Test Case** - The test case `can access The Book of Geb via homepage` is defined in this test. This test case simply accesses the `gebHomePage` and then accesses the `theBookOfGebPage` by opening the `manualsMenu` module. + +**Evidence Collection** - During the process of executing this test, two pieces of evidence are collected. + + package specs + + import geb.spock.GebReportingSpec + import helpers.SpecHelper + import pages.DemoGebHomePage + import pages.DemoTheBookOfGebPage + + class DemoGebHomePageSpec extends GebReportingSpec { + + def gebHomePage = page(DemoGebHomePage) + def theBookOfGebPage = page(DemoTheBookOfGebPage) + + def setup() { + System.setProperty("geb.env", "defaultDriver") + } + + def "can access The Book of Geb via homepage"() { + given: + to gebHomePage + + when: + SpecHelper.printEvidenceForPageElement(this, 1, $("manuals-menu"), "Manuals menu exists") + gebHomePage.manualsMenu.open() + SpecHelper.printEvidenceForPageElement(this, 1, $("a", xpath: '//*[@id=\"manuals-menu\"]/div/a[1]'), "Current version submenu exists") + gebHomePage.manualsMenu.links[0].click() + + then: + at theBookOfGebPage + } + } + +#### Google Keep example +The test that utilizes these pages and modules is located in the `specs` section and is called `DemoGebHomePageSpec`. + +**Setup** - In the `DemoGoogleKeepSpec` test, the `def setupSpec()` method is used to define the test environment that will be used for the test. + +**Test Case** - The test case `Open Google Keep and press Start button` is defined in this test. This test case simply open the Google Keep mobile application and click on Start button. + +**Evidence Collection** - During the process of executing this test, evidence is collected. + +**Steps to make it work property** +This example is commented by default because android environment is not configured and apk is not part of the template. +``` + import org.openqa.selenium.WebElement + import spock.lang.Stepwise + + @Stepwise + class DemoGoogleKeepSpec extends GebReportingSpec { + + + static Browser browser + + def setupSpec() { + System.setProperty("geb.env", "android") + browser = new Browser() + } + + def cleanupSpec() { + browser.driver.quit() + } + + // This is a demo test for Google Keep apk + // Please, ensure your android test environment is properly configured before uncommenting the lines below + def "Open Google Keep and press Start button"() { + when: "Google Keep is opened" + browser.driver.activateApp('com.google.android.keep') + + then: "Press the Start button" + SpecHelper.printEvidenceForMobileElement(this, 1, By.className("android.widget.Button"), "Current version submenu exists") + List startButton = browser.driver.findElements(By.className("android.widget.Button")) + if (!startButton.isEmpty()) { + startButton.get(0).click() + } + List buttons = browser.driver.findElements(By.className("android.widget.Button")) + assert !buttons.isEmpty() + } + + } +``` + +Below there are all the steps you have to follow to prepare your locale environment: +* Download the Google Keep apk, save it in application folder, and call it Keep.apk +* Install and run Appium server: + * Prerequisite - node and npm already installed. + * Open a cmd console with administrator mode + * Execute the command to install Appium server: `npm install -g appium` + * Execute the command to run Appium server: `appium` +* Configure the `android` environment. This is an example of how to configure it with Appium server installed locally: +``` + DesiredCapabilities capabilities = new DesiredCapabilities(); + capabilities.setCapability("platformName", "Android"); + capabilities.setCapability("browserVersion", "12.0.0.149"); + capabilities.setCapability("deviceName", "HuaweiP60Pro"); + capabilities.setCapability("automationName", "UiAutomator2"); + capabilities.setCapability("app", new File(System.getProperty("user.dir"), "/application/Keep.apk").getAbsolutePath()) + AndroidDriver driver = new AndroidDriver( + // The default URL in Appium is http://127.0.0.1:4723/wd/hub + new URL("http://127.0.0.1:4723"), capabilities + ); + return driver +``` + +## Running end-to-end tests + +Run `gradlew test` to execute all end-to-end tests against the test instance of the front end. + +## Links + +* [gradle](https://gradle.org/) +* [spock](http://spockframework.org/) +* [geb](https://gebish.org/) +* [unirest](http://unirest.io/) +* [apium](https://appium.io/) diff --git a/e2e-spock-geb/files/application/EmptyFile.apk b/e2e-spock-geb/files/application/EmptyFile.apk new file mode 100644 index 000000000..e69de29bb diff --git a/e2e-spock-geb/files/build.gradle b/e2e-spock-geb/files/build.gradle index 733acd9e0..a640bac33 100644 --- a/e2e-spock-geb/files/build.gradle +++ b/e2e-spock-geb/files/build.gradle @@ -24,6 +24,12 @@ plugins { id 'com.adarshr.test-logger' version "2.0.0" } +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + repositories { if (no_nexus) { println("using repository 'mavenCentral', because property no_nexus=$no_nexus") @@ -55,6 +61,10 @@ ext { seleniumVersion = "4.15.0" htmlunitVersion = "4.13.0" unirestVersion = "3.14.5" + seleniumJavaVersion = "3.141.59" + appiumVersion = "8.3.0" + chromeDriverVersion = "4.2.2" + edgeDriverVersion = "4.21.0" // When a test fail we can continue or fail the stage CONTINUE_WHEN_TEST_FAIL = true } @@ -67,6 +77,10 @@ dependencies { testImplementation "org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}" testImplementation "org.seleniumhq.selenium:htmlunit-driver:${htmlunitVersion}" testImplementation "org.seleniumhq.selenium:selenium-support:${seleniumVersion}" + testImplementation "org.seleniumhq.selenium:selenium-java:${seleniumJavaVersion}" + testImplementation group: 'io.appium', name: 'java-client', version: "${appiumVersion}" + testImplementation "org.seleniumhq.selenium:selenium-chrome-driver:${chromeDriverVersion}" + testImplementation "org.seleniumhq.selenium:selenium-edge-driver:${edgeDriverVersion}" } sourceSets { @@ -135,15 +149,22 @@ class TestLanguages { static final String GROOVY = "groovy" } -def generateTaskName(def type, def language) { - return "${type}-${language}" +// Here is defined the default environment to execute the tests +def TestEnv = ['defaultDriver'] +// You can add as many environments as needed and properly configured in GebConfig.groovy file +// This is an example +//def TestEnv = ['defaultDriver', 'chrome','edge', 'android', 'ios'] + +def generateTaskName(def type, def language, def env) { + return "${type}-${language}-${env}" } // Task to create in a parametrized way Tests task -def executeTest(def type, def language) { - return tasks.create(generateTaskName(type, language), Test) { - description = "Runs ${type} tests ${language}." - group = "verification" +def executeTest(def type, def language, def env) { + return tasks.create(generateTaskName(type, language, env), Test) { + description = "Runs ${type} tests ${language} in ${env} enviroment." + // The tasks are grouped by type + group = "verification-${type}" // Since groovy tests are junit tests and they are run as part of java tests, // we disable here the execution of junit tests if not running for java language. @@ -159,21 +180,32 @@ def executeTest(def type, def language) { } } +def verification() { + // To group the tasks by type, create the required subfolders here + def subfolderNames = [TestExecutionPhases.ACCEPTANCE, TestExecutionPhases.INTEGRATION, TestExecutionPhases.INSTALLATION] + subfolderNames.each { subfolderName -> + file("verification-${subfolderName}").mkdirs() + } +} + test { - // To create the tasks - dependsOn executeTest(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA) - dependsOn executeTest(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY) - dependsOn executeTest(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA) - dependsOn executeTest(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY) - dependsOn executeTest(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA) - dependsOn executeTest(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY) - - // To define the order - tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY)).mustRunAfter generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA) - tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY) - tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA) - tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY) - tasks.findByName(generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA) + //Per every test environment defined + for (env in TestEnv) { + // To create the tasks + dependsOn executeTest(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA, env) + dependsOn executeTest(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env) + dependsOn executeTest(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env) + dependsOn executeTest(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env) + dependsOn executeTest(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env) + dependsOn executeTest(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY, env) + + // To define the order + tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY, env)).mustRunAfter generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env) + tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env) + tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env) + tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env) + tasks.findByName(generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA, env) + } } testlogger { diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy new file mode 100644 index 000000000..4101ed871 --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy @@ -0,0 +1,14 @@ +package modules + +class DemoManualsMenuModule extends geb.Module { + static content = { + toggle { $("div.menu a.manuals") } + linksContainer { $("#manuals-menu") } + links { linksContainer.find("a") } + } + + void open() { + toggle.click() + waitFor { !linksContainer.hasClass("animating") } + } +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy new file mode 100644 index 000000000..f65ac5d03 --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy @@ -0,0 +1,15 @@ +package pages + +import geb.Page +import modules.DemoManualsMenuModule + +class DemoGebHomePage extends Page { + static url = "https://gebish.org" + + static at = { title == "Geb - Very Groovy Browser Automation" } + + static content = { + manualsMenu { module(DemoManualsMenuModule) } + } + +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy new file mode 100644 index 000000000..eff7c8b96 --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy @@ -0,0 +1,8 @@ +package pages + +import geb.Page + +class DemoGitHubAcceptanceHomePage extends Page { + static url = "/opendevstack/ods-quickstarters" + static at = { title.contains("quickstarters")} +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy new file mode 100644 index 000000000..7df1fa7c3 --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy @@ -0,0 +1,7 @@ +package pages + +import geb.Page + +class DemoTheBookOfGebPage extends Page { + static at = { title.startsWith("The Book Of Geb") } +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy new file mode 100644 index 000000000..5523986be --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy @@ -0,0 +1,30 @@ +package specs + +import geb.spock.GebReportingSpec +import helpers.SpecHelper +import pages.DemoGebHomePage +import pages.DemoTheBookOfGebPage + +class DemoGebHomePageSpec extends GebReportingSpec { + + def gebHomePage = page(DemoGebHomePage) + def theBookOfGebPage = page(DemoTheBookOfGebPage) + + def setup() { + System.setProperty("geb.env", "defaultDriver") + } + + def "can access The Book of Geb via homepage"() { + given: + to gebHomePage + + when: + SpecHelper.printEvidenceForPageElement(this, 1, $("manuals-menu"), "Manuals menu exists") + gebHomePage.manualsMenu.open() + SpecHelper.printEvidenceForPageElement(this, 1, $("a", xpath: '//*[@id=\"manuals-menu\"]/div/a[1]'), "Current version submenu exists") + gebHomePage.manualsMenu.links[0].click() + + then: + at theBookOfGebPage + } +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/DemoAcceptanceSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy similarity index 59% rename from e2e-spock-geb/files/src/test/acceptance/groovy/DemoAcceptanceSpec.groovy rename to e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy index 768648e2a..438616826 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/DemoAcceptanceSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy @@ -1,18 +1,18 @@ -import geb.Page +package specs + import geb.spock.GebReportingSpec +import helpers.SpecHelper +import pages.DemoGitHubAcceptanceHomePage import spock.lang.Stepwise -class GitHubAcceptanceHomePage extends Page { - static url = "/opendevstack/ods-quickstarters" - static at = { title.contains("quickstarters")} -} - @Stepwise -class DemoAcceptance extends GebReportingSpec { +class DemoGitHubAcceptanceHomeSpec extends GebReportingSpec { + + def gitHubAcceptanceHomePage = page(DemoGitHubAcceptanceHomePage) def "goes to GH ods-quickstarters"() { given: "User goes to ods-quickstarters and checks the content" - to GitHubAcceptanceHomePage + to gitHubAcceptanceHomePage // print evidence of two fields (the input area and iframe content) SpecHelper.printEvidenceForPageElement(this, 1, $("[data-content='Code']"), "code area") @@ -21,8 +21,8 @@ class DemoAcceptance extends GebReportingSpec { // print the two evidence fields through map SpecHelper.printEvidenceForPageElements(this, 1, [ - [ 'fragment' : $("#textareaCode"), 'description' : 'code area'], - [ 'fragment' : $("#iframecontainer"), 'description' : 'rendered code area'] + [ 'fragment' : $("#textareaCode"), 'description' : 'code area'], + [ 'fragment' : $("#iframecontainer"), 'description' : 'rendered code area'] ] ) } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy new file mode 100644 index 000000000..12c6ff5a5 --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy @@ -0,0 +1,41 @@ +package specs + +import geb.Browser +import geb.spock.GebReportingSpec +import helpers.SpecHelper +import org.openqa.selenium.By +import org.openqa.selenium.WebElement +import spock.lang.Stepwise + +@Stepwise +class DemoGoogleKeepSpec extends GebReportingSpec { + + static Browser browser + + def setupSpec() { + System.setProperty("geb.env", "android") + browser = new Browser() + } + + def cleanupSpec() { + browser.driver.quit() + } + + // This is a demo test for Google Keep apk + // Please, ensure your android test environment is properly configured before uncommenting the lines below + // In README file, Google Keep example subsection, you will find the necessary steps to configure the environment locally. + //def "Open Google Keep and press Start button"() { + // when: "Google Keep is opened" + // browser.driver.activateApp('com.google.android.keep') + // + // then: "Press the Start button" + // SpecHelper.printEvidenceForMobileElement(this, 1, By.className("android.widget.Button"), "Current version submenu exists") + // List startButton = browser.driver.findElements(By.className("android.widget.Button")) + // if (!startButton.isEmpty()) { + // startButton.get(0).click() + // } + // List buttons = browser.driver.findElements(By.className("android.widget.Button")) + // assert !buttons.isEmpty() + //} + +} diff --git a/e2e-spock-geb/files/src/test/resources/GebConfig.groovy b/e2e-spock-geb/files/src/test/resources/GebConfig.groovy index a6a86bc7f..1ba7db24e 100644 --- a/e2e-spock-geb/files/src/test/resources/GebConfig.groovy +++ b/e2e-spock-geb/files/src/test/resources/GebConfig.groovy @@ -1,33 +1,111 @@ import com.gargoylesoftware.htmlunit.BrowserVersion import com.gargoylesoftware.htmlunit.WebClient +import helpers.SpecHelper +import io.appium.java_client.android.AndroidDriver +import io.appium.java_client.ios.IOSDriver import org.openqa.selenium.htmlunit.HtmlUnitDriver import org.openqa.selenium.Proxy +import org.openqa.selenium.remote.DesiredCapabilities +import org.openqa.selenium.edge.EdgeDriver +import org.openqa.selenium.chrome.ChromeDriver // Load application.properties def properties = new SpecHelper().getApplicationProperties() -// Selenium driver (True in constructor to use JavaScript) -driver = { - HtmlUnitDriver driver = new HtmlUnitDriver(BrowserVersion.BEST_SUPPORTED, true) { - @Override - protected WebClient newWebClient(BrowserVersion version) { - WebClient webClient = super.newWebClient(version); - // don't throw on script errors - webClient.getOptions().setThrowExceptionOnScriptError(false); - return webClient; - } - }; - - def env = System.getenv() - if(env.HTTP_PROXY) { - Proxy proxy = new Proxy(); - URL url = new URL(env.HTTP_PROXY); - proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); - proxy.setNoProxy(env.NO_PROXY) - driver.setProxySettings(proxy); +// Getting SauceLabs environment variables to configure IOs device +def sauceLabsUsername = System.getenv('SAUCE_LABS_USERNAME') +def sauceLabsAccessKey = System.getenv('SAUCE_LABS_ACCESS_KEY') + +// Creating test environments +// Please, configure the test environments properly, replacing the indicated values ("REPLACE...") +// Feel free to remove/add as test environments as you need +environments { + + defaultDriver { + driver = { + HtmlUnitDriver driver = new HtmlUnitDriver(BrowserVersion.BEST_SUPPORTED, true) { + @Override + protected WebClient newWebClient(BrowserVersion version) { + WebClient webClient = super.newWebClient(version); + webClient.getOptions().setThrowExceptionOnScriptError(false); + return webClient; + } + }; + + def env = System.getenv() + if(env.HTTP_PROXY) { + Proxy proxy = new Proxy(); + URL url = new URL(env.HTTP_PROXY); + proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); + proxy.setNoProxy(env.NO_PROXY) + driver.setProxySettings(proxy); + } + return driver + } } - return driver + chrome { + driver = { + System.setProperty("webdriver.chrome.driver", "REPLACE with your chrome driver path") + ChromeDriver driver = new ChromeDriver() + + def env = System.getenv() + if(env.HTTP_PROXY) { + Proxy proxy = new Proxy(); + URL url = new URL(env.HTTP_PROXY); + proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); + proxy.setNoProxy(env.NO_PROXY) + driver.setProxySettings(proxy); + } + return driver + } + } + + edge { + driver = { + System.setProperty("webdriver.edge.driver", "REPLACE with your edge driver path") + + EdgeDriver driver = new EdgeDriver() + def env = System.getenv() + if(env.HTTP_PROXY) { + Proxy proxy = new Proxy(); + URL url = new URL(env.HTTP_PROXY); + proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); + proxy.setNoProxy(env.NO_PROXY) + driver.setProxySettings(proxy); + } + return driver + } + } + + android { + driver = { + DesiredCapabilities capabilities = new DesiredCapabilities() + capabilities.setCapability("platformName", "Android") + capabilities.setCapability("deviceName", "REPLACE with your device name") + capabilities.setCapability("app", "REPLACE with your application mobile path") + capabilities.setCapability("browserVersion", "REPLACE with your android version"); + capabilities.setCapability("automationName", "UiAutomator2"); + capabilities.setCapability("autoGrantPermissions", "true"); + AndroidDriver driver = new AndroidDriver(new URL("REPLACE with your URL"), caps); + return driver + } + } + + ios { + driver = { + DesiredCapabilities capabilities = new DesiredCapabilities() + capabilities.setCapability("platformName", "iOS") + capabilities.setCapability("deviceName", "REPLACE with your device name") + capabilities.setCapability("app", "REPLACE with your application mobile path") + capabilities.setCapability("browserName", "REPLACE with your browser name"); + capabilities.setCapability("browserVersion", "REPLACE with your browser version"); + capabilities.setCapability("automationName", "XCUITest"); + capabilities.setCapability("autoGrantPermissions", "true"); + IOSDriver driver = new IOSDriver(new URL("https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub"), caps); + return driver + } + } } waiting { diff --git a/e2e-spock-geb/files/src/test/resources/application.properties b/e2e-spock-geb/files/src/test/resources/application.properties index a7bed91de..1ef88e30a 100644 --- a/e2e-spock-geb/files/src/test/resources/application.properties +++ b/e2e-spock-geb/files/src/test/resources/application.properties @@ -1,4 +1,4 @@ -# Base url with the application to test - w3c schools +# Base url with the application to test config.application.url=https://github.com # Base url with the application to test - OpenShift app using env vars from Jenkinsfile diff --git a/e2e-spock-geb/files/src/test/resources/SpecHelper.groovy b/e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy similarity index 73% rename from e2e-spock-geb/files/src/test/resources/SpecHelper.groovy rename to e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy index 7f7287a69..f20bb1aac 100644 --- a/e2e-spock-geb/files/src/test/resources/SpecHelper.groovy +++ b/e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy @@ -1,6 +1,8 @@ -import geb.Page +package helpers + import geb.navigator.Navigator import geb.spock.GebReportingSpec +import org.openqa.selenium.By import java.util.regex.Pattern @@ -86,4 +88,25 @@ class SpecHelper { } } } + + public static void printEvidenceForMobileElement(GebReportingSpec spec, int testStepNumber, By fragment, String description = '', int desiredLevel = -1) { + printEvidenceForMobileElements(spec, testStepNumber, [ [ 'fragment' : fragment, 'description' : description] ], desiredLevel) + } + + public static void printEvidenceForMobileElements(GebReportingSpec spec, int testStepNumber, List fragmentsAndDiscriptions, int desiredLevel = -1) { + println '=====================================' + println "Test Case: ${spec.specificationContext.currentIteration.name}" + println "Test Step: ${testStepNumber}" + + if (!fragmentsAndDiscriptions || fragmentsAndDiscriptions.isEmpty()) { + throw new IllegalArgumentException("Error: evidence fragment is empty!") + } + + println "----- Test Evidence STARTS Here -----" + fragmentsAndDiscriptions.each { fragmentAndDescription -> + println "Description: ${fragmentAndDescription.description}" + println "Fragment: ${fragmentAndDescription.fragment}" + } + println "----- Test Evidence ENDS Here -----" + } } From 1a709d76fc6c35afd2c392a12ddc68e66f012ff3 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 18 Jul 2024 07:57:11 +0200 Subject: [PATCH 02/14] [TPS2021-1393] Mobile testing enablement --- .../files/src/test/resources/GebConfig.groovy | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/e2e-spock-geb/files/src/test/resources/GebConfig.groovy b/e2e-spock-geb/files/src/test/resources/GebConfig.groovy index 1ba7db24e..aa01412ca 100644 --- a/e2e-spock-geb/files/src/test/resources/GebConfig.groovy +++ b/e2e-spock-geb/files/src/test/resources/GebConfig.groovy @@ -16,6 +16,13 @@ def properties = new SpecHelper().getApplicationProperties() def sauceLabsUsername = System.getenv('SAUCE_LABS_USERNAME') def sauceLabsAccessKey = System.getenv('SAUCE_LABS_ACCESS_KEY') +// These are examples of configuring the URLs to Appium Server in different ways +// Localhost if you are working in your local environment +// SauceLabs connection if you are working with a SauceLabs device +// Both are interchangeable +def androidURL = "http://127.0.0.1:4723" +def iosURL = "https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub" + // Creating test environments // Please, configure the test environments properly, replacing the indicated values ("REPLACE...") // Feel free to remove/add as test environments as you need @@ -87,7 +94,7 @@ environments { capabilities.setCapability("browserVersion", "REPLACE with your android version"); capabilities.setCapability("automationName", "UiAutomator2"); capabilities.setCapability("autoGrantPermissions", "true"); - AndroidDriver driver = new AndroidDriver(new URL("REPLACE with your URL"), caps); + AndroidDriver driver = new AndroidDriver(new URL(androidURL), caps); return driver } } @@ -102,7 +109,7 @@ environments { capabilities.setCapability("browserVersion", "REPLACE with your browser version"); capabilities.setCapability("automationName", "XCUITest"); capabilities.setCapability("autoGrantPermissions", "true"); - IOSDriver driver = new IOSDriver(new URL("https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub"), caps); + IOSDriver driver = new IOSDriver(new URL(iosURL), caps); return driver } } From 8777b779aaf82279d89f332ee997d6322ad7fb18 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 18 Jul 2024 12:31:08 +0200 Subject: [PATCH 03/14] [TPS2021-1393] Mobile testing enablement --- e2e-spock-geb/Jenkinsfile.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index ebb18b502..513b1f261 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -12,7 +12,7 @@ odsComponentPipeline( podContainers: [ containerTemplate( name: 'jnlp', - image: "${dockerRegistry}/ods/jenkins-agent-maven:4.x", + image: "${dockerRegistry}/ods/jenkins-agent-maven:@agent_image_tag@", workingDir: '/tmp', envVars: [ envVar(key: 'SAUCE_LABS_ACCESS_KEY', value: sauceLabsAccessKey), From 3f8c7f1eba4440ee9b08a407582099b798610521 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 18 Jul 2024 14:28:23 +0200 Subject: [PATCH 04/14] Jenkinsfile --- e2e-spock-geb/Jenkinsfile.template | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index 513b1f261..a5c5b71fb 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -8,11 +8,10 @@ node { } odsComponentPipeline( - imageStreamTag: '@ods_namespace@/jenkins-agent-jdk:@agent_image_tag@', podContainers: [ containerTemplate( name: 'jnlp', - image: "${dockerRegistry}/ods/jenkins-agent-maven:@agent_image_tag@", + image: "${dockerRegistry}/ods/jenkins-agent-jdk:@agent_image_tag@", workingDir: '/tmp', envVars: [ envVar(key: 'SAUCE_LABS_ACCESS_KEY', value: sauceLabsAccessKey), From c962cc0752f66f4cf7eb9e6932dee0333b17799d Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Wed, 11 Dec 2024 08:59:27 +0100 Subject: [PATCH 05/14] [TPS2021-517] [IPA] Mobile testing enablement --- .../quickstarters/pages/e2e-spock-geb.adoc | 66 ++- e2e-spock-geb/Jenkinsfile | 18 + e2e-spock-geb/Jenkinsfile.template | 67 +-- e2e-spock-geb/files/README.md | 486 ++++++++++++------ e2e-spock-geb/files/application/EmptyFile.apk | 0 e2e-spock-geb/files/build.gradle | 153 +++--- e2e-spock-geb/files/metadata.yml | 2 +- .../modules/DemoManualMenuModule.groovy | 9 +- .../groovy/pages/DemoGebHomePage.groovy | 8 +- .../pages/DemoGitHubAcceptanceHomePage.groovy | 8 - .../groovy/pages/DemoTheBookOfGebPage.groovy | 1 + .../groovy/specs/DemoGebHomePageSpec.groovy | 29 +- .../specs/DemoGitHubAcceptanceHomeSpec.groovy | 29 -- .../groovy/specs/DemoGoogleKeepSpec.groovy | 41 -- .../groovy/specs/DemoMobileAppSpec.groovy | 68 +++ .../specs/DemoMobileGebHomePageSpec.groovy | 84 +++ .../acceptance/java/DemoAcceptanceTest.java | 9 +- .../groovy/DemoInstallationSpec.groovy | 13 +- .../java/DemoInstallationTest.java | 9 +- .../groovy/DemoIntegrationSpec.groovy | 17 +- .../integration/java/DemoIntegrationTest.java | 9 +- .../files/src/test/resources/GebConfig.groovy | 135 ++--- .../resources/helpers/Environments.groovy | 9 + .../test/resources/helpers/SpecHelper.groovy | 103 +++- 24 files changed, 890 insertions(+), 483 deletions(-) delete mode 100644 e2e-spock-geb/files/application/EmptyFile.apk delete mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy delete mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy delete mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy create mode 100644 e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy create mode 100644 e2e-spock-geb/files/src/test/resources/helpers/Environments.groovy diff --git a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc index 68b690d03..87627f89d 100644 --- a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc +++ b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc @@ -10,8 +10,6 @@ This is a Spock, Geb, Unirest and Apium e2e testing project quickstarter with ba ---- . -├── application -│ └── EmptyFile.apk ├── Jenkinsfile ├── .pre-commit-config.yaml ├── README.md @@ -24,12 +22,11 @@ This is a Spock, Geb, Unirest and Apium e2e testing project quickstarter with ba │ │ │ │ └── DemoManualMenuModule.groovy │ │ │ │ └── pages │ │ │ │ └── DemoGebHomePage.groovy -│ │ │ │ └── DemoGitHubAcceptanceHomePage.groovy │ │ │ │ └── DemoTheBookOfGebPage.groovy │ │ │ │ └── specs │ │ │ │ └── DemoGebHomePageSpec.groovy -│ │ │ │ └── DemoGitHubAcceptanceHomeSpec.groovy -│ │ │ │ └── DemoGoogleKeepSpec.groovy +│ │ │ │ └── DemoMobileAppSpec.groovy +│ │ │ │ └── DemoMobileGebHomePageSpec.groovy │ │ │ └── java │ │ │ └── DemoAcceptanceTest.java │ │ └── installation @@ -44,6 +41,7 @@ This is a Spock, Geb, Unirest and Apium e2e testing project quickstarter with ba │ │ │ └── DemoIntegrationTest.java │ │ └── resources │ │ │ └── helpers +│ │ │ └── Environments.groovy │ │ │ └── SpecHelper.groovy │ │ │ └── application.properties │ │ │ └── GebConfig.groovy @@ -86,9 +84,42 @@ If you do not want to use Nexus at all, just define the following property: ``` no_nexus=true ``` - Run `gradlew -v` to verify the installed version of gradle wrapper. + +=== Environments Configuration + +The environments used in the tests are defined in the `build.gradle` file. You can find the environments under the `ext` block as project properties. These environments are accessed via system properties in the Groovy classes. Here is an example of how the environments are defined: +``` +ext { +... + environments = [ + DESKTOP: "desktop", + MOBILE_BROWSER: "mobile_browser", + MOBILE_APP: "mobile_app" + ] +} +... +tasks.withType(Test) { + systemProperty 'environments.desktop', environments.DESKTOP + systemProperty 'environments.mobile_browser', environments.MOBILE_BROWSER + systemProperty 'environments.mobile_app', environments.MOBILE_APP +} +``` + +Additionally, there is a class called `Environments.groovy` that facilitates access to these environments from the Groovy code. The class is located in the `src/test/resources/helpers` directory. +``` +package helpers + +class Environments { + // Define environment constants using system properties + // Check the build.gradle file for the defined properties + static final String DESKTOP = System.getProperty('environments.desktop') + static final String MOBILE_BROWSER = System.getProperty('environments.mobile_browser') + static final String MOBILE_APP = System.getProperty('environments.mobile_app') +} +``` + == Frameworks used This project is generated by https://gradle.org/[Gradle] @@ -111,18 +142,19 @@ You will see the results inside a new folder 'build' in project directory. . └── build └── test-results - ├── acceptance-groovy-defaultDriver - ├── acceptance-java-defaultDriver + ├── acceptance-groovy-desktop + ├── acceptance-java-desktop + │ │── TEST-DemoAcceptanceTest.xml │ │── TEST-specs.DemoGebHomePageSpec.xml - │ │── TEST-specs.DemoGitHubAcceptanceHomeSpec.xml - │ └── TEST-DemoAcceptanceTest.xml - ├── installation-groovy-defaultDriver - ├── installation-java-defaultDriver - │ │── TEST-DemoInstallation.xml + │ │── TEST-specs.DemoMobileAppSpec.xml + │ └── TEST-specs.DemoMobileGebHomePageSpec.xml + ├── installation-groovy-desktop + ├── installation-java-desktop + │ │── TEST-DemoInstallationSpec.xml │ └── TEST-DemoInstallationTest.xml - ├── integration-groovy-defaultDriver - └── integration-java-defaultDriver - │── TEST-DemoIntegration.xml + ├── integration-groovy-desktop + └── integration-java-desktop + │── TEST-DemoIntegrationSpec.xml └── TEST-DemoIntegrationTest.xml ---- @@ -149,8 +181,6 @@ In Jenkinsfile.template, there is the following stage: All the results are stashed and published through Jenkins jUnit publisher. -include::partial$secret-scanning-with-gitleaks.adoc - == Builder agent used This quickstarter uses the diff --git a/e2e-spock-geb/Jenkinsfile b/e2e-spock-geb/Jenkinsfile index 5ab91e95d..8516b4f52 100644 --- a/e2e-spock-geb/Jenkinsfile +++ b/e2e-spock-geb/Jenkinsfile @@ -21,6 +21,24 @@ odsQuickstarterPipeline( odsQuickstarterStageCopyFiles(context) odsQuickstarterStageRenderJenkinsfile(context) + + createSauceLabsOpenshiftSecret(context) odsQuickstarterStageRenderSonarProperties(context) } + +def createSauceLabsOpenshiftSecret(def context) { + stage('Create Credentials') { + def project = context.projectId + "-cd" + def secretExists = sh(script: "oc get secret sauce-labs-user-access-key -n $project", returnStatus: true) == 0 + if (!secretExists) { + sh """ + oc create secret generic sauce-labs-user-access-key -n $project \ + --from-literal=username=changeme \ + --from-literal=password=changeme \ + --type="kubernetes.io/basic-auth" && \ + oc label secret sauce-labs-user-access-key -n $project credential.sync.jenkins.openshift.io=true + """ + } + } +} \ No newline at end of file diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index a5c5b71fb..60dc31d76 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -2,29 +2,11 @@ @Library('ods-jenkins-shared-library@@shared_library_ref@') _ node { - sauceLabsUsername = env.SAUCE_LABS_USERNAME - sauceLabsAccessKey = env.SAUCE_LABS_ACCESS_KEY dockerRegistry = env.DOCKER_REGISTRY } odsComponentPipeline( - podContainers: [ - containerTemplate( - name: 'jnlp', - image: "${dockerRegistry}/ods/jenkins-agent-jdk:@agent_image_tag@", - workingDir: '/tmp', - envVars: [ - envVar(key: 'SAUCE_LABS_ACCESS_KEY', value: sauceLabsAccessKey), - envVar(key: 'SAUCE_LABS_USERNAME', value: sauceLabsUsername) - ], - resourceRequestCpu: '100m', - resourceLimitCpu: '300m', - resourceRequestMemory: '1Gi', - resourceLimitMemory: '2Gi', - alwaysPullImage: true, - args: '${computer.jnlpmac} ${computer.name}' - ) - ], + imageStreamTag: '@ods_namespace@/jenkins-agent-jdk:@agent_image_tag@', branchToEnvironmentMapping: [ 'master': 'dev', // 'release/': 'test' @@ -42,16 +24,43 @@ def stageTest(def context) { springBootEnv = 'dev' } - stage('Integration Test') { - sh (script: "chmod a+x gradle*", label : "allow gradle to execute") - withEnv(["TAGVERSION=${context.tagversion}", "NEXUS_HOST=${context.nexusHost}", "NEXUS_USERNAME=${context.nexusUsername}", "NEXUS_PASSWORD=${context.nexusPassword}", "JAVA_OPTS=${javaOpts}","GRADLE_TEST_OPTS=${gradleTestOpts}","ENVIRONMENT=${springBootEnv}","OPENSHIFT_PROJECT=${context.targetProject}","OPENSHIFT_APP_DOMAIN=${context.getOpenshiftApplicationDomain()}"]) { - def status = sh(script: "source use-j17.sh && ./gradlew clean test --stacktrace --no-daemon && source use-j11.sh", returnStatus: true) - junit(testResults:"build/test-results/installation*/*.xml, build/test-results/integration*/*.xml, build/test-results/acceptance*/*.xml", allowEmptyResults:true) - stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/installation*/*.xml', allowEmpty: true) - stash(name: "integration-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/integration*/*.xml', allowEmpty: true) - stash(name: "acceptance-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/acceptance*/*.xml', allowEmpty: true) - if (status != 0) { - error "Executing tests failed!" + stage('Functional Test') { + sh (script: "chmod a+x gradle*", label : "allow gradle to execute") + withEnv([ + "TAGVERSION=${context.tagversion}", + "NEXUS_HOST=${context.nexusHost}", + "NEXUS_USERNAME=${context.nexusUsername}", + "NEXUS_PASSWORD=${context.nexusPassword}", + "JAVA_OPTS=${javaOpts}", + "GRADLE_TEST_OPTS=${gradleTestOpts}", + "ENVIRONMENT=${springBootEnv}", + "OPENSHIFT_PROJECT=${context.targetProject}", + "OPENSHIFT_APP_DOMAIN=${context.getOpenshiftApplicationDomain()}" + ]) { + withCredentials([ + usernamePassword(credentialsId: "${context.projectId}-cd-sauce-labs-user-access-key", passwordVariable: 'SAUCE_LABS_ACCESS_KEY', usernameVariable: 'SAUCE_LABS_USERNAME'), + ]) { + // Note: Testing in the production environment is not enabled by default as it can lead to unintended consequences, + // including potential downtime, data corruption, or exposure of sensitive information. + // This block is designed to skip acceptance and integration tests in the production environment to avoid these risks. + // If you choose to enable these tests in production take all necessary precautions. This means verifying your + // preconditions, database access, fake data, API calls, etc. + // Remember that any test case in the installation folder will be executed in production. + def status + if (context.environment == 'prod') { + status = sh(script: './gradlew clean testProd --stacktrace --no-daemon', returnStatus: true) + junit(testResults:"build/test-results/installation*/*.xml", allowEmptyResults:true) + stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/*installation*/*.xml', allowEmpty: true) + } else { + status = sh(script: './gradlew clean test --stacktrace --no-daemon', returnStatus: true) + junit(testResults:"build/test-results/installation*/*.xml, build/test-results/integration*/*.xml, build/test-results/acceptance*/*.xml", allowEmptyResults:true) + stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/installation*/*.xml', allowEmpty: true) + stash(name: "integration-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/integration*/*.xml', allowEmpty: true) + stash(name: "acceptance-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/acceptance*/*.xml', allowEmpty: true) + } + if (status != 0) { + error "Executing tests failed!" + } } } } diff --git a/e2e-spock-geb/files/README.md b/e2e-spock-geb/files/README.md index 8bb22ccbb..23ac14be5 100644 --- a/e2e-spock-geb/files/README.md +++ b/e2e-spock-geb/files/README.md @@ -30,7 +30,7 @@ with designated spaces for `modules`, `pages`, and `specs`. In addition to these, within the src/test directory, there is a resources section. Here, you will find important configuration files such as `application.properties` and `GebConfig.groovy`. These resources are crucial for the configuration and efficient operation of the project. -Also within the `src/test` directory, you will find a `helpers` folder. This folder contains the `SpecHelper.groovy` file, which includes several functions designed to assist you in your development process, such as functions for capturing evidence. +Also within the `src/test` directory, you will find a `helpers` folder. This folder contains the `SpecHelper.groovy` file, which includes several functions designed to assist you in your development process, such as functions for capturing evidence, and the `Environments.groovy` to define the different environments in which the tests can be executed. ## Working with GebConfig.groovy @@ -61,41 +61,79 @@ return driver ### Environments -This section defines different environments such as defaultDriver, chrome, edge, android, and ios. Each environment has its own driver setup. - -These three environments are dedicated to browser: -* defaultDriver - This driver is ready to use. -* chrome - To use this driver you must replace this system property: - ```System.setProperty("webdriver.chrome.driver", "replace by your chrome driver path")``` -* edge - To use this driver you must replace this system property: - ```System.setProperty("webdriver.edge.driver", "replace by your edge driver path")``` - -And these other two are dedicated to mobile: -* android - To use this driver you must replace some capabilities showed below: - ``` - DesiredCapabilities capabilities = new DesiredCapabilities() - capabilities.setCapability("platformName", "Android") - capabilities.setCapability("deviceName", "replace by your device name") - capabilities.setCapability("app", "replace by your application mobile path") - capabilities.setCapability("browserVersion", "replace by your android version"); - capabilities.setCapability("automationName", "UiAutomator2"); - capabilities.setCapability("autoGrantPermissions", "true"); - AndroidDriver driver = new AndroidDriver(new URL("http://127.0.0.1:4723"), caps); - return driver - ``` -* ios - To use this driver you must replace some capabilities showed below: - ``` - DesiredCapabilities capabilities = new DesiredCapabilities() - capabilities.setCapability("platformName", "iOS") - capabilities.setCapability("deviceName", "replace by your device name") - capabilities.setCapability("app", "replace by your application mobile path") - capabilities.setCapability("browserName", "replace by your browser name"); - capabilities.setCapability("browserVersion", "replace by your browser version"); - capabilities.setCapability("automationName", "XCUITest"); - capabilities.setCapability("autoGrantPermissions", "true"); - IOSDriver driver = new IOSDriver(new URL("https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub"), caps); - return driver - ``` +This section defines different environments such as DESKTOP, MOBILE_BROWSER, and MOBILE_APP. Each environment has its own driver setup. + +These environments are dedicated to browser testing: + DESKTOP - This environment uses the HtmlUnitDriver for headless browser testing. + MOBILE_BROWSER - This environment uses the AndroidDriver for testing on mobile browsers. +And this environment is dedicated to mobile app testing: + MOBILE_APP - This environment uses the IOSDriver for testing on iOS mobile applications. + +* Desktop Environment - The DESKTOP environment is configured to use the HtmlUnitDriver: + ``` + "${Environments.DESKTOP}" { + driver = { + HtmlUnitDriver driver = new HtmlUnitDriver(BrowserVersion.BEST_SUPPORTED, true) { + @Override + protected WebClient newWebClient(BrowserVersion version) { + WebClient webClient = super.newWebClient(version) + webClient.getOptions().setThrowExceptionOnScriptError(false) + webClient.getOptions().setCssEnabled(false) + return webClient + } + } + return driver + } + } + ``` +* Mobile Browser Environment - The MOBILE_BROWSER environment is configured to use the AndroidDriver: + ``` + "${Environments.MOBILE_BROWSER}" { + driver = { + MutableCapabilities caps = new MutableCapabilities() + caps.setCapability("platformName", "Android") + caps.setCapability("browserName", "Chrome") + caps.setCapability("appium:deviceName", "Google Pixel 7a GoogleAPI Emulator") + caps.setCapability("appium:platformVersion", "13.0") + caps.setCapability("appium:automationName", "UiAutomator2") + MutableCapabilities sauceOptions = new MutableCapabilities() + sauceOptions.setCapability("appiumVersion", "2.11.0") + sauceOptions.setCapability("username", sauceLabsUsername) + sauceOptions.setCapability("accessKey", sauceLabsAccessKey) + sauceOptions.setCapability("build", "") + sauceOptions.setCapability("name", "") + sauceOptions.setCapability("deviceOrientation", "PORTRAIT") + caps.setCapability("sauce:options", sauceOptions) + URL url = new URL("https://ondemand.eu-central-1.saucelabs.com:443/wd/hub") + AndroidDriver driver = new AndroidDriver(url, caps) + return driver + } + } + ``` +* Mobile App Environment - The MOBILE_APP environment is configured to use the IOSDriver: + ``` + "${Environments.MOBILE_APP}" { + driver = { + MutableCapabilities caps = new MutableCapabilities() + caps.setCapability("platformName", "iOS") + caps.setCapability("appium:app", "storage:filename=SauceLabs-Demo-App.Simulator.XCUITest.zip") + caps.setCapability("appium:deviceName", "iPhone Simulator") + caps.setCapability("appium:platformVersion", "17.0") + caps.setCapability("appium:automationName", "XCUITest") + MutableCapabilities sauceOptions = new MutableCapabilities() + sauceOptions.setCapability("appiumVersion", "2.1.3") + sauceOptions.setCapability("username", sauceLabsUsername) + sauceOptions.setCapability("accessKey", sauceLabsAccessKey) + sauceOptions.setCapability("build", "") + sauceOptions.setCapability("name", "") + sauceOptions.setCapability("deviceOrientation", "PORTRAIT") + caps.setCapability("sauce:options", sauceOptions) + URL url = new URL("https://ondemand.eu-central-1.saucelabs.com:443/wd/hub") + IOSDriver driver = new IOSDriver(url, caps) + return driver + } + } + ``` ### Base URL @@ -117,155 +155,279 @@ This project is structured with different sections for `pages`, `modules`, and ` In this section, we have the `DemoGebHomePage` class which defines the home page, https://gebish.org. This class includes the title of the page and some of its content, specifically the `manuals` menu. There is a second web page defined called DemoTheBookOfGebPage, which can be accessed through the 'manuals' menu. + ``` + package pages + + import geb.Page + import modules.DemoManualMenuModule + + class DemoGebHomePage extends Page { + // URL of the Geb home page + static url = "https://gebish.org" + + // Condition to verify that the browser is at the correct page + static at = { title == "Geb - Very Groovy Browser Automation" } + + static content = { + // Define the manuals menu module + manualsMenu { module(DemoManualMenuModule) } + } + } + ``` - package pages +### Modules Section +The `manuals` menu from the home page is defined as a module in this section. + ``` + package modules + + class DemoManualMenuModule extends geb.Module { + static content = { + // Define the toggle element for the manuals menu + toggle { $("div.menu a.manuals") } + + // Define the container for the links in the manuals menu + linksContainer { $("#manuals-menu") } + + // Define the links within the links container + links { linksContainer.find("a") } + } + + // Method to open the manuals menu + void open() { + toggle.click() + // Wait until the links container is no longer animating + waitFor { !linksContainer.hasClass("animating") } + } + } + ``` + +### Specs Section - import geb.Page - import modules.DemoManualsMenuModule +#### Gebish.org example - for DESKTOP - class DemoGebHomePage extends Page { +The test that utilizes these pages and modules is located in the `specs` section and is called `DemoGebHomePageSpec`. - static url = "https://gebish.org" +**Setup** - In the `DemoGebHomePageSpec` test, the `def setupSpec()` method is used to check the environment and skips tests if it is not DESKTOP. - static at = { title == "Geb - Very Groovy Browser Automation" } +**Test Case** - The test case `can access The Book of Geb via homepage` is defined in this test. This test case simply accesses the `gebHomePage` and then accesses the `theBookOfGebPage` by opening the `manualsMenu` module. - static content = { - manualsMenu { module(DemoManualsMenuModule) } - } +**Evidence Collection** - During the process of executing this test, multiple pieces of evidence are collected. + ``` + package specs + + import geb.spock.GebReportingSpec + import helpers.SpecHelper + import pages.DemoGebHomePage + import pages.DemoTheBookOfGebPage + import spock.lang.IgnoreIf + import helpers.* + + class DemoGebHomePageSpec extends GebReportingSpec { + + def gebHomePage = page(DemoGebHomePage) + def theBookOfGebPage = page(DemoTheBookOfGebPage) + + def setupSpec() { + if (System.getProperty("geb.env") != Environments.DESKTOP) { + println "Skipping tests - environments not supported" + return + } } + + @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) + def "can access The Book of Geb via homepage"() { + given: + to gebHomePage + + when: + gebHomePage.manualsMenu.open() + gebHomePage.manualsMenu.links[0].click() + + SpecHelper.printEvidenceForPageElement(this, 1, $("#introduction"), "Introduction header") + SpecHelper.printEvidenceForPageElements(this, 1, + [ + [ 'fragment' : $("#content > div:nth-child(2) > div > div:nth-child(1)"), 'description' : '1st paragraph'], + [ 'fragment' : $("#content > div:nth-child(2) > div > div:nth-child(2)"), 'description' : '2nd paragraph'] + ] + ) + + then: + at theBookOfGebPage + } + } + ``` + +#### Gebish.org example - for MOBILE_BROWSER +The test that utilizes these elements is located in the `specs` section and is called `DemoMobileGebHomePageSpec`. +**Setup** - In the `DemoMobileGebHomePageSpec` test, the `def setupSpec()` method is used to check the environment and skips tests if it is not MOBILE_BROWSER, and initialize the Appium driver. -### Modules Section -The `manuals` menu from the home page is defined as a module in this section. - - package modules - - class DemoManualsMenuModule extends geb.Module { - static content = { - toggle { $("div.menu a.manuals") } - linksContainer { $("#manuals-menu") } - links { linksContainer.find("a") } - } +**Test Case** - The test case ` verify geb home page and documentation navigation` is defined in this test. This test case navigates to the Geb home page and then accesses the Documentation page. - void open() { - toggle.click() - waitFor { !linksContainer.hasClass("animating") } - } +**Evidence Collection** - During the process of executing this test, evidence is collected. + ``` + package specs + + import geb.spock.GebReportingSpec + import io.appium.java_client.AppiumDriver + import org.openqa.selenium.WebElement + import spock.lang.Shared + import spock.lang.Stepwise + import spock.lang.IgnoreIf + import helpers.* + + @Stepwise + class DemoMobileGebHomePageSpec extends GebReportingSpec { + + // Shared driver instance for the AppiumDriver + @Shared + def static driver + // Shared result variable to track test success + @Shared + def static result = true + + def setupSpec() { + // Check the environment and skip tests if it is not MOBILE_BROWSER + if (System.getProperty("geb.env") != Environments.MOBILE_BROWSER) { + println "Skipping tests - environments not supported" + return + } + + // Initialize the Appium driver + driver = browser.driver as AppiumDriver } -### Specs Section + def cleanupSpec() { + // Set the job result and quit the driver if it is initialized + if (driver) { + driver.executeScript("sauce:job-result=$result") + driver.quit() + } + } -#### Gebish.org example + @IgnoreIf({ System.getProperty("geb.env") != Environments.MOBILE_BROWSER }) + def "verify geb home page and documentation navigation"() { + when: "Navigating to Geb home page" + try { + // Open the Geb home page + driver.get("https://www.gebish.org") + } catch (AssertionError e) { + result = false + throw e + } + + then: "The page title should be 'Geb - Very Groovy Browser Automation'" + try { + // Verify the page title + assert title == "Geb - Very Groovy Browser Automation" + } catch (AssertionError e) { + result = false + throw e + } + + when: "Accessing to the Documentation page" + try { + // Wait for the Documentation button to be displayed and click it + waitFor { $("button.ui.blue.button", text: "Documentation").displayed } + WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() + documentationButton.click() + + // Print evidence for the Documentation button + SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") + } catch (AssertionError e) { + result = false + throw e + } + + then: "The page title should be 'The Book Of Geb'" + try { + // Verify the page title + assert title == "The Book Of Geb" + } catch (AssertionError e) { + result = false + throw e + } + } -The test that utilizes these pages and modules is located in the `specs` section and is called `DemoGebHomePageSpec`. + } + ``` +#### My Demo App Sauce Labs example - for MOBILE_APP +The test that utilizes these elements is located in the `specs` section and is called `DemoMobileGebHomePageSpec`. -**Setup** - In the `DemoGebHomePageSpec` test, the `def setup()` method is used to define the test environment that will be used for the test. +**Setup** - In the `DemoMobileAppSpec` test, the `def setupSpec()` method is used to check the environment and skips tests if it is not MOBILE_APP, and initialize the Appium driver -**Test Case** - The test case `can access The Book of Geb via homepage` is defined in this test. This test case simply accesses the `gebHomePage` and then accesses the `theBookOfGebPage` by opening the `manualsMenu` module. +**Test Case** - The test case `check elements in the first page of the app` is defined in this test. This test case verifies the presence of a specific element and interacts with it. -**Evidence Collection** - During the process of executing this test, two pieces of evidence are collected. +**Evidence Collection** - During the process of executing this test, evidence is collected for the specific element. +``` package specs - - import geb.spock.GebReportingSpec - import helpers.SpecHelper - import pages.DemoGebHomePage - import pages.DemoTheBookOfGebPage - - class DemoGebHomePageSpec extends GebReportingSpec { - - def gebHomePage = page(DemoGebHomePage) - def theBookOfGebPage = page(DemoTheBookOfGebPage) - - def setup() { - System.setProperty("geb.env", "defaultDriver") - } - - def "can access The Book of Geb via homepage"() { - given: - to gebHomePage - - when: - SpecHelper.printEvidenceForPageElement(this, 1, $("manuals-menu"), "Manuals menu exists") - gebHomePage.manualsMenu.open() - SpecHelper.printEvidenceForPageElement(this, 1, $("a", xpath: '//*[@id=\"manuals-menu\"]/div/a[1]'), "Current version submenu exists") - gebHomePage.manualsMenu.links[0].click() - - then: - at theBookOfGebPage - } - } - -#### Google Keep example -The test that utilizes these pages and modules is located in the `specs` section and is called `DemoGebHomePageSpec`. - -**Setup** - In the `DemoGoogleKeepSpec` test, the `def setupSpec()` method is used to define the test environment that will be used for the test. -**Test Case** - The test case `Open Google Keep and press Start button` is defined in this test. This test case simply open the Google Keep mobile application and click on Start button. + import geb.spock.GebReportingSpec + import io.appium.java_client.AppiumDriver + import io.appium.java_client.AppiumBy + import org.openqa.selenium.WebElement + import spock.lang.IgnoreIf + import spock.lang.Shared + import spock.lang.Stepwise + import helpers.* + + @Stepwise + class DemoMobileAppSpec extends GebReportingSpec { + + // Shared driver instance for the AppiumDriver + @Shared + def static driver + // Shared result variable to track test success + @Shared + def static result = true + + def setupSpec() { + // Check the environment and skip tests if it is not MOBILE_APP + if (System.getProperty("geb.env") != Environments.MOBILE_APP) { + println "Skipping tests - environments not supported" + return + } + // Initialize the Appium driver + driver = browser.driver as AppiumDriver + } -**Evidence Collection** - During the process of executing this test, evidence is collected. + def cleanupSpec() { + // Set the job result and quit the driver if it is initialized + if (driver) { + driver.executeScript("sauce:job-result=$result") + driver.quit() + } + } -**Steps to make it work property** -This example is commented by default because android environment is not configured and apk is not part of the template. -``` - import org.openqa.selenium.WebElement - import spock.lang.Stepwise - - @Stepwise - class DemoGoogleKeepSpec extends GebReportingSpec { - - - static Browser browser - - def setupSpec() { - System.setProperty("geb.env", "android") - browser = new Browser() - } - - def cleanupSpec() { - browser.driver.quit() - } - - // This is a demo test for Google Keep apk - // Please, ensure your android test environment is properly configured before uncommenting the lines below - def "Open Google Keep and press Start button"() { - when: "Google Keep is opened" - browser.driver.activateApp('com.google.android.keep') - - then: "Press the Start button" - SpecHelper.printEvidenceForMobileElement(this, 1, By.className("android.widget.Button"), "Current version submenu exists") - List startButton = browser.driver.findElements(By.className("android.widget.Button")) - if (!startButton.isEmpty()) { - startButton.get(0).click() - } - List buttons = browser.driver.findElements(By.className("android.widget.Button")) - assert !buttons.isEmpty() - } - - } -``` + @IgnoreIf({ System.getProperty("geb.env") != Environments.MOBILE_APP}) + def "check elements in the first page of the app"() { + given: "Launching the app" + when: "Printing all the elements" + try { + // Verify if the specific element is present + List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) + + if (!specificElements.isEmpty() && specificElements[0].isDisplayed()) { + // Click on the element + specificElements[0].click() + println "Clicked on element with name 'Cart-tab-item'" + + // Print evidence for the specific element + SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") + } else { + println "Element with name 'Cart-tab-item' not found or not displayed" + } + } catch (Exception e) { + result = false + throw e + } + then: "The specific element should be present" + assert true + } -Below there are all the steps you have to follow to prepare your locale environment: -* Download the Google Keep apk, save it in application folder, and call it Keep.apk -* Install and run Appium server: - * Prerequisite - node and npm already installed. - * Open a cmd console with administrator mode - * Execute the command to install Appium server: `npm install -g appium` - * Execute the command to run Appium server: `appium` -* Configure the `android` environment. This is an example of how to configure it with Appium server installed locally: -``` - DesiredCapabilities capabilities = new DesiredCapabilities(); - capabilities.setCapability("platformName", "Android"); - capabilities.setCapability("browserVersion", "12.0.0.149"); - capabilities.setCapability("deviceName", "HuaweiP60Pro"); - capabilities.setCapability("automationName", "UiAutomator2"); - capabilities.setCapability("app", new File(System.getProperty("user.dir"), "/application/Keep.apk").getAbsolutePath()) - AndroidDriver driver = new AndroidDriver( - // The default URL in Appium is http://127.0.0.1:4723/wd/hub - new URL("http://127.0.0.1:4723"), capabilities - ); - return driver -``` + } + ``` ## Running end-to-end tests diff --git a/e2e-spock-geb/files/application/EmptyFile.apk b/e2e-spock-geb/files/application/EmptyFile.apk deleted file mode 100644 index e69de29bb..000000000 diff --git a/e2e-spock-geb/files/build.gradle b/e2e-spock-geb/files/build.gradle index a640bac33..b7fcdf9f1 100644 --- a/e2e-spock-geb/files/build.gradle +++ b/e2e-spock-geb/files/build.gradle @@ -58,15 +58,20 @@ ext { junitVersion = "5.10.1" spockVersion = "2.3-groovy-4.0" gebVersion = "7.0" - seleniumVersion = "4.15.0" + seleniumVersion = "4.25.0" htmlunitVersion = "4.13.0" unirestVersion = "3.14.5" - seleniumJavaVersion = "3.141.59" - appiumVersion = "8.3.0" + appiumVersion = "9.3.0" chromeDriverVersion = "4.2.2" edgeDriverVersion = "4.21.0" - // When a test fail we can continue or fail the stage + apiGuardianAPI = "1.1.2" CONTINUE_WHEN_TEST_FAIL = true + // Define environments as project properties to be accessed via system properties in Groovy classes + environments = [ + DESKTOP: "desktop", + MOBILE_BROWSER: "mobile_browser", + MOBILE_APP: "mobile_app" + ] } dependencies { @@ -75,55 +80,30 @@ dependencies { testImplementation "com.konghq:unirest-java:${unirestVersion}" testImplementation "org.gebish:geb-spock:${gebVersion}" testImplementation "org.seleniumhq.selenium:selenium-firefox-driver:${seleniumVersion}" - testImplementation "org.seleniumhq.selenium:htmlunit-driver:${htmlunitVersion}" testImplementation "org.seleniumhq.selenium:selenium-support:${seleniumVersion}" - testImplementation "org.seleniumhq.selenium:selenium-java:${seleniumJavaVersion}" - testImplementation group: 'io.appium', name: 'java-client', version: "${appiumVersion}" + testImplementation "org.seleniumhq.selenium:selenium-java:${seleniumVersion}" + testImplementation "org.seleniumhq.selenium:htmlunit-driver:${htmlunitVersion}" testImplementation "org.seleniumhq.selenium:selenium-chrome-driver:${chromeDriverVersion}" testImplementation "org.seleniumhq.selenium:selenium-edge-driver:${edgeDriverVersion}" + testImplementation "io.appium:java-client:${appiumVersion}" + testImplementation "org.apiguardian:apiguardian-api:${apiGuardianAPI}" } sourceSets { - installation { - groovy { - srcDir 'src/test/installation/groovy' - } - java { - srcDir 'src/test/installation/java' - } - resources { - srcDir 'src/test/resources' - } - compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath - runtimeClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath - } - - integration { - groovy { - srcDir 'src/test/integration/groovy' - } - java { - srcDir 'src/test/integration/java' - } - resources { - srcDir 'src/test/resources' - } - compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath - runtimeClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath - } - - acceptance { - groovy { - srcDir 'src/test/acceptance/groovy' - } - java { - srcDir 'src/test/acceptance/java' - } - resources { - srcDir 'src/test/resources' + [TestExecutionPhases.INSTALLATION, TestExecutionPhases.INTEGRATION, TestExecutionPhases.ACCEPTANCE].each { phase -> + "$phase" { + groovy { + srcDir "src/test/${phase}/groovy" + } + java { + srcDir "src/test/${phase}/java" + } + resources { + srcDir 'src/test/resources' + } + compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath + runtimeClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath } - compileClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath - runtimeClasspath += sourceSets.main.output + sourceSets.test.output + configurations.testRuntimeClasspath } } @@ -149,12 +129,6 @@ class TestLanguages { static final String GROOVY = "groovy" } -// Here is defined the default environment to execute the tests -def TestEnv = ['defaultDriver'] -// You can add as many environments as needed and properly configured in GebConfig.groovy file -// This is an example -//def TestEnv = ['defaultDriver', 'chrome','edge', 'android', 'ios'] - def generateTaskName(def type, def language, def env) { return "${type}-${language}-${env}" } @@ -162,8 +136,7 @@ def generateTaskName(def type, def language, def env) { // Task to create in a parametrized way Tests task def executeTest(def type, def language, def env) { return tasks.create(generateTaskName(type, language, env), Test) { - description = "Runs ${type} tests ${language} in ${env} enviroment." - // The tasks are grouped by type + description = "Runs ${type} tests ${language} in ${env} environment." group = "verification-${type}" // Since groovy tests are junit tests and they are run as part of java tests, @@ -177,37 +150,71 @@ def executeTest(def type, def language, def env) { ignoreFailures = "${CONTINUE_WHEN_TEST_FAIL}" testClassesDirs = sourceSets["${type}"].output.classesDirs classpath = sourceSets["${type}"].runtimeClasspath + + systemProperty "geb.env", env + } } -def verification() { - // To group the tasks by type, create the required subfolders here - def subfolderNames = [TestExecutionPhases.ACCEPTANCE, TestExecutionPhases.INTEGRATION, TestExecutionPhases.INSTALLATION] - subfolderNames.each { subfolderName -> - file("verification-${subfolderName}").mkdirs() +def executeTestProd(def type, def language, def env) { + return tasks.create(generateTaskName(type, language, env), Test) { + description = "Runs ${type} tests ${language} in ${env} environment." + group = "verification-${type}" + + // Since groovy tests are junit tests and they are run as part of java tests, + // we disable here the execution of junit tests if not running for java language. + // jenkins to jira integration does not allows to run a test more than once. + if ("${language}".equalsIgnoreCase(TestLanguages.JAVA)) { + // Mandatory to run JUnit 5 test but incompatible with groovy tests + useJUnitPlatform() + } + + ignoreFailures = "${CONTINUE_WHEN_TEST_FAIL}" + testClassesDirs = sourceSets["${type}"].output.classesDirs + classpath = sourceSets["${type}"].runtimeClasspath + + systemProperty "geb.env", env + } } test { - //Per every test environment defined - for (env in TestEnv) { - // To create the tasks - dependsOn executeTest(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA, env) - dependsOn executeTest(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env) - dependsOn executeTest(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env) - dependsOn executeTest(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env) - dependsOn executeTest(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env) - dependsOn executeTest(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY, env) + // To create the tasks + environments.each {env -> + [TestExecutionPhases.INSTALLATION, TestExecutionPhases.INTEGRATION, TestExecutionPhases.ACCEPTANCE].each { phase -> + [TestLanguages.JAVA, TestLanguages.GROOVY].each { language -> + dependsOn executeTest(phase, language, env.value) + } + } + // To define the order + tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY, env.value)).mustRunAfter generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env.value) + tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env.value)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env.value) + tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env.value)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env.value) + tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env.value)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env.value) + tasks.findByName(generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env.value)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA, env.value) + } +} + +task testProd { + description = "Runs only the installation phase tests." + group = "verification" + // Define dependencies on installation phase tasks + environments.each { env -> + [TestLanguages.JAVA, TestLanguages.GROOVY].each { language -> + dependsOn generateTaskName(TestExecutionPhases.INSTALLATION, language, env.value) + } // To define the order - tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.GROOVY, env)).mustRunAfter generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env) - tasks.findByName(generateTaskName(TestExecutionPhases.ACCEPTANCE, TestLanguages.JAVA, env)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env) - tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.GROOVY, env)).mustRunAfter generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env) - tasks.findByName(generateTaskName(TestExecutionPhases.INTEGRATION, TestLanguages.JAVA, env)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env) - tasks.findByName(generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA, env) + tasks.findByName(generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.GROOVY, env.value)).mustRunAfter generateTaskName(TestExecutionPhases.INSTALLATION, TestLanguages.JAVA, env.value) } } +tasks.withType(Test) { + systemProperty 'environments.desktop', environments.DESKTOP + systemProperty 'environments.mobile_browser', environments.MOBILE_BROWSER + systemProperty 'environments.mobile_app', environments.MOBILE_APP +} + testlogger { showStandardStreams true } diff --git a/e2e-spock-geb/files/metadata.yml b/e2e-spock-geb/files/metadata.yml index c29b7a401..4e5d0ff4c 100644 --- a/e2e-spock-geb/files/metadata.yml +++ b/e2e-spock-geb/files/metadata.yml @@ -1,6 +1,6 @@ --- name: e2e-spock-geb -description: "Spock is a highly expressive testing and specification framework for Java and Groovy. Geb is a browser automation solution for functional/web/acceptance testing. Technologies: Spock 2.3-groovy-4.0, Geb 7.0, Selenium 4.15.0" +description: "Spock is a highly expressive testing and specification framework for Java and Groovy. Geb is a browser automation solution for functional/web/acceptance testing. Appium is an open-source tool for automating mobile apps. Technologies: Spock 2.3-groovy-4.0, Geb 7.0, Selenium 4.25.0, Appium 9.3.0" supplier: http://spockframework.org version: 4.x type: ods-test diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy index 4101ed871..f4eec56cb 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/modules/DemoManualMenuModule.groovy @@ -1,14 +1,21 @@ package modules -class DemoManualsMenuModule extends geb.Module { +class DemoManualMenuModule extends geb.Module { static content = { + // Define the toggle element for the manuals menu toggle { $("div.menu a.manuals") } + + // Define the container for the links in the manuals menu linksContainer { $("#manuals-menu") } + + // Define the links within the links container links { linksContainer.find("a") } } + // Method to open the manuals menu void open() { toggle.click() + // Wait until the links container is no longer animating waitFor { !linksContainer.hasClass("animating") } } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy index f65ac5d03..08c6d6083 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGebHomePage.groovy @@ -1,15 +1,17 @@ package pages import geb.Page -import modules.DemoManualsMenuModule +import modules.DemoManualMenuModule class DemoGebHomePage extends Page { + // URL of the Geb home page static url = "https://gebish.org" + // Condition to verify that the browser is at the correct page static at = { title == "Geb - Very Groovy Browser Automation" } static content = { - manualsMenu { module(DemoManualsMenuModule) } + // Define the manuals menu module + manualsMenu { module(DemoManualMenuModule) } } - } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy deleted file mode 100644 index eff7c8b96..000000000 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoGitHubAcceptanceHomePage.groovy +++ /dev/null @@ -1,8 +0,0 @@ -package pages - -import geb.Page - -class DemoGitHubAcceptanceHomePage extends Page { - static url = "/opendevstack/ods-quickstarters" - static at = { title.contains("quickstarters")} -} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy index 7df1fa7c3..027e2d1aa 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/pages/DemoTheBookOfGebPage.groovy @@ -3,5 +3,6 @@ package pages import geb.Page class DemoTheBookOfGebPage extends Page { + // Verify that the page title starts with "The Book Of Geb" static at = { title.startsWith("The Book Of Geb") } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy index 5523986be..ef5d76566 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy @@ -1,30 +1,49 @@ package specs import geb.spock.GebReportingSpec -import helpers.SpecHelper import pages.DemoGebHomePage import pages.DemoTheBookOfGebPage +import spock.lang.IgnoreIf +import helpers.* class DemoGebHomePageSpec extends GebReportingSpec { + // Define page objects for the home page and the book page def gebHomePage = page(DemoGebHomePage) def theBookOfGebPage = page(DemoTheBookOfGebPage) - def setup() { - System.setProperty("geb.env", "defaultDriver") + def setupSpec() { + // Check the environment and skip tests if it is not DESKTOP + if (System.getProperty("geb.env") != Environments.DESKTOP) { + println "Skipping tests - environments not supported" + return + } } + @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) def "can access The Book of Geb via homepage"() { given: + // Navigate to the Geb home page to gebHomePage when: - SpecHelper.printEvidenceForPageElement(this, 1, $("manuals-menu"), "Manuals menu exists") + // Open the manuals menu and click the first link gebHomePage.manualsMenu.open() - SpecHelper.printEvidenceForPageElement(this, 1, $("a", xpath: '//*[@id=\"manuals-menu\"]/div/a[1]'), "Current version submenu exists") gebHomePage.manualsMenu.links[0].click() + // Print evidence of the introduction header element + SpecHelper.printEvidenceForPageElement(this, 1, $("#introduction"), "Introduction header") + + // Print evidence of the first and second paragraphs + SpecHelper.printEvidenceForPageElements(this, 1, + [ + [ 'fragment' : $("#content > div:nth-child(2) > div > div:nth-child(1)"), 'description' : '1st paragraph'], + [ 'fragment' : $("#content > div:nth-child(2) > div > div:nth-child(2)"), 'description' : '2nd paragraph'] + ] + ) + then: + // Verify that the browser is at the book page at theBookOfGebPage } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy deleted file mode 100644 index 438616826..000000000 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGitHubAcceptanceHomeSpec.groovy +++ /dev/null @@ -1,29 +0,0 @@ -package specs - -import geb.spock.GebReportingSpec -import helpers.SpecHelper -import pages.DemoGitHubAcceptanceHomePage -import spock.lang.Stepwise - -@Stepwise -class DemoGitHubAcceptanceHomeSpec extends GebReportingSpec { - - def gitHubAcceptanceHomePage = page(DemoGitHubAcceptanceHomePage) - - def "goes to GH ods-quickstarters"() { - given: "User goes to ods-quickstarters and checks the content" - to gitHubAcceptanceHomePage - - // print evidence of two fields (the input area and iframe content) - SpecHelper.printEvidenceForPageElement(this, 1, $("[data-content='Code']"), "code area") - SpecHelper.printEvidenceForPageElement(this, 1, $("#iframecontainer"), "rendered code area") - - // print the two evidence fields through map - SpecHelper.printEvidenceForPageElements(this, 1, - [ - [ 'fragment' : $("#textareaCode"), 'description' : 'code area'], - [ 'fragment' : $("#iframecontainer"), 'description' : 'rendered code area'] - ] - ) - } -} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy deleted file mode 100644 index 12c6ff5a5..000000000 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGoogleKeepSpec.groovy +++ /dev/null @@ -1,41 +0,0 @@ -package specs - -import geb.Browser -import geb.spock.GebReportingSpec -import helpers.SpecHelper -import org.openqa.selenium.By -import org.openqa.selenium.WebElement -import spock.lang.Stepwise - -@Stepwise -class DemoGoogleKeepSpec extends GebReportingSpec { - - static Browser browser - - def setupSpec() { - System.setProperty("geb.env", "android") - browser = new Browser() - } - - def cleanupSpec() { - browser.driver.quit() - } - - // This is a demo test for Google Keep apk - // Please, ensure your android test environment is properly configured before uncommenting the lines below - // In README file, Google Keep example subsection, you will find the necessary steps to configure the environment locally. - //def "Open Google Keep and press Start button"() { - // when: "Google Keep is opened" - // browser.driver.activateApp('com.google.android.keep') - // - // then: "Press the Start button" - // SpecHelper.printEvidenceForMobileElement(this, 1, By.className("android.widget.Button"), "Current version submenu exists") - // List startButton = browser.driver.findElements(By.className("android.widget.Button")) - // if (!startButton.isEmpty()) { - // startButton.get(0).click() - // } - // List buttons = browser.driver.findElements(By.className("android.widget.Button")) - // assert !buttons.isEmpty() - //} - -} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy new file mode 100644 index 000000000..26592d519 --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy @@ -0,0 +1,68 @@ +package specs + +import geb.spock.GebReportingSpec +import io.appium.java_client.AppiumDriver +import io.appium.java_client.AppiumBy +import org.openqa.selenium.WebElement +import org.openqa.selenium.support.ui.WebDriverWait +import org.openqa.selenium.support.ui.ExpectedConditions +import spock.lang.IgnoreIf +import spock.lang.Shared +import spock.lang.Stepwise +import helpers.* + +@Stepwise +class DemoMobileAppSpec extends GebReportingSpec { + + // Shared driver instance for the AppiumDriver + @Shared + def static driver + // Shared result variable to track test success + @Shared + def static result = true + + def setupSpec() { + // Check the environment and skip tests if it is not MOBILE_APP + if (System.getProperty("geb.env") != Environments.MOBILE_APP) { + println "Skipping tests - environments not supported" + return + } + // Initialize the Appium driver + driver = browser.driver as AppiumDriver + } + + def cleanupSpec() { + // Set the job result and quit the driver if it is initialized + if (driver) { + driver.executeScript("sauce:job-result=$result") + driver.quit() + } + } + + @IgnoreIf({ System.getProperty("geb.env") != Environments.MOBILE_APP}) + def "check elements in the first page of the app"() { + given: "Launching the app" + when: "Printing all the elements" + try { + // Verify if the specific element is present + List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) + + if (!specificElements.isEmpty() && specificElements[0].isDisplayed()) { + // Click on the element + specificElements[0].click() + println "Clicked on element with name 'Cart-tab-item'" + + // Print evidence for the specific element + SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") + } else { + println "Element with name 'Cart-tab-item' not found or not displayed" + } + } catch (Exception e) { + result = false + throw e + } + then: "The specific element should be present" + assert true + } + +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy new file mode 100644 index 000000000..fb0aa049c --- /dev/null +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy @@ -0,0 +1,84 @@ +package specs + +import geb.spock.GebReportingSpec +import io.appium.java_client.AppiumDriver +import org.openqa.selenium.WebElement +import spock.lang.Shared +import spock.lang.Stepwise +import spock.lang.IgnoreIf +import helpers.* + +@Stepwise +class DemoMobileGebHomePageSpec extends GebReportingSpec { + + // Shared driver instance for the AppiumDriver + @Shared + def static driver + // Shared result variable to track test success + @Shared + def static result = true + + def setupSpec() { + // Check the environment and skip tests if it is not MOBILE_BROWSER + if (System.getProperty("geb.env") != Environments.MOBILE_BROWSER) { + println "Skipping tests - environments not supported" + return + } + + // Initialize the Appium driver + driver = browser.driver as AppiumDriver + } + + def cleanupSpec() { + // Set the job result and quit the driver if it is initialized + if (driver) { + driver.executeScript("sauce:job-result=$result") + driver.quit() + } + } + + @IgnoreIf({ System.getProperty("geb.env") != Environments.MOBILE_BROWSER }) + def "verify geb home page and documentation navigation"() { + when: "Navigating to Geb home page" + try { + // Open the Geb home page + driver.get("https://www.gebish.org") + } catch (AssertionError e) { + result = false + throw e + } + + then: "The page title should be 'Geb - Very Groovy Browser Automation'" + try { + // Verify the page title + assert title == "Geb - Very Groovy Browser Automation" + } catch (AssertionError e) { + result = false + throw e + } + + when: "Accessing to the Documentation page" + try { + // Wait for the Documentation button to be displayed and click it + waitFor { $("button.ui.blue.button", text: "Documentation").displayed } + WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() + documentationButton.click() + + // Print evidence for the Documentation button + SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") + } catch (AssertionError e) { + result = false + throw e + } + + then: "The page title should be 'The Book Of Geb'" + try { + // Verify the page title + assert title == "The Book Of Geb" + } catch (AssertionError e) { + result = false + throw e + } + } + +} diff --git a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java index f2cfd8341..24f0d6f3c 100644 --- a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java +++ b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java @@ -1,12 +1,19 @@ - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; public class DemoAcceptanceTest { @Test + @EnabledIf("customCondition") void basicTest() { + // Assert that the condition is true Assertions.assertTrue(true); } + boolean customCondition() { + // Custom condition logic to determine if the test should be enabled + return false; + } + } diff --git a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy index 8280be79d..16c550236 100644 --- a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy +++ b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy @@ -1,9 +1,20 @@ import geb.spock.GebReportingSpec +import helpers.Environments +import spock.lang.IgnoreIf import spock.lang.Stepwise @Stepwise -class DemoInstallation extends GebReportingSpec { +class DemoInstallationSpec extends GebReportingSpec { + def setupSpec() { + // Check the environment and skip tests if necessary + if (System.getProperty("geb.env") != Environments.DESKTOP) { + println "Skipping tests - environments not supported" + return + } + } + + @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) def "basic test"() { given: "Example test" true == true diff --git a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java index d5cd905b7..6a5a5fb20 100644 --- a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java +++ b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java @@ -1,12 +1,19 @@ - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; public class DemoInstallationTest { @Test + @EnabledIf("customCondition") void basicTest() { + // Assert that the condition is true Assertions.assertTrue(true); } + boolean customCondition() { + // Implement your custom condition logic here + return false; + } + } diff --git a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy index 432926a67..0311071ca 100644 --- a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy +++ b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy @@ -1,12 +1,23 @@ import geb.spock.GebReportingSpec +import helpers.Environments +import spock.lang.IgnoreIf import spock.lang.Stepwise @Stepwise -class DemoIntegration extends GebReportingSpec { +class DemoIntegrationSpec extends GebReportingSpec { + def setupSpec() { + // Check the environment and skip tests if it is not DESKTOP + if (System.getProperty("geb.env") != Environments.DESKTOP) { + println "Skipping tests - environments not supported" + return + } + } + + @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) def "basic test"() { - given: "Example test" + given: "An example test scenario" + // This is a placeholder assertion for demonstration purposes true == true } } - diff --git a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java index 9c86d92a1..ff6ffe58e 100644 --- a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java +++ b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java @@ -1,12 +1,19 @@ - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; public class DemoIntegrationTest { @Test + @EnabledIf("customCondition") void basicTest() { + // Assert that the condition is true Assertions.assertTrue(true); } + boolean customCondition() { + // Implement your custom condition logic here + return false; + } + } diff --git a/e2e-spock-geb/files/src/test/resources/GebConfig.groovy b/e2e-spock-geb/files/src/test/resources/GebConfig.groovy index aa01412ca..518640f33 100644 --- a/e2e-spock-geb/files/src/test/resources/GebConfig.groovy +++ b/e2e-spock-geb/files/src/test/resources/GebConfig.groovy @@ -1,120 +1,84 @@ import com.gargoylesoftware.htmlunit.BrowserVersion import com.gargoylesoftware.htmlunit.WebClient -import helpers.SpecHelper import io.appium.java_client.android.AndroidDriver import io.appium.java_client.ios.IOSDriver +import org.openqa.selenium.MutableCapabilities import org.openqa.selenium.htmlunit.HtmlUnitDriver -import org.openqa.selenium.Proxy -import org.openqa.selenium.remote.DesiredCapabilities -import org.openqa.selenium.edge.EdgeDriver -import org.openqa.selenium.chrome.ChromeDriver +import helpers.* -// Load application.properties +// Load application properties from application.properties file def properties = new SpecHelper().getApplicationProperties() -// Getting SauceLabs environment variables to configure IOs device +// Get SauceLabs environment variables for configuring iOS device def sauceLabsUsername = System.getenv('SAUCE_LABS_USERNAME') def sauceLabsAccessKey = System.getenv('SAUCE_LABS_ACCESS_KEY') -// These are examples of configuring the URLs to Appium Server in different ways -// Localhost if you are working in your local environment -// SauceLabs connection if you are working with a SauceLabs device -// Both are interchangeable -def androidURL = "http://127.0.0.1:4723" -def iosURL = "https://$sauceLabsUsername:$sauceLabsAccessKey@ondemand.eu-central-1.saucelabs.com:443/wd/hub" - -// Creating test environments -// Please, configure the test environments properly, replacing the indicated values ("REPLACE...") -// Feel free to remove/add as test environments as you need environments { - defaultDriver { + // Configuration for desktop environment using HtmlUnitDriver + "${Environments.DESKTOP}" { driver = { HtmlUnitDriver driver = new HtmlUnitDriver(BrowserVersion.BEST_SUPPORTED, true) { @Override protected WebClient newWebClient(BrowserVersion version) { - WebClient webClient = super.newWebClient(version); - webClient.getOptions().setThrowExceptionOnScriptError(false); - return webClient; + WebClient webClient = super.newWebClient(version) + webClient.getOptions().setThrowExceptionOnScriptError(false) + webClient.getOptions().setCssEnabled(false) + return webClient } - }; - - def env = System.getenv() - if(env.HTTP_PROXY) { - Proxy proxy = new Proxy(); - URL url = new URL(env.HTTP_PROXY); - proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); - proxy.setNoProxy(env.NO_PROXY) - driver.setProxySettings(proxy); } return driver } } - chrome { + // Configuration for mobile browser environment using AndroidDriver + "${Environments.MOBILE_BROWSER}" { driver = { - System.setProperty("webdriver.chrome.driver", "REPLACE with your chrome driver path") - ChromeDriver driver = new ChromeDriver() - - def env = System.getenv() - if(env.HTTP_PROXY) { - Proxy proxy = new Proxy(); - URL url = new URL(env.HTTP_PROXY); - proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); - proxy.setNoProxy(env.NO_PROXY) - driver.setProxySettings(proxy); - } + MutableCapabilities caps = new MutableCapabilities() + caps.setCapability("platformName", "Android") + caps.setCapability("browserName", "Chrome") + caps.setCapability("appium:deviceName", "Google Pixel 7a GoogleAPI Emulator") + caps.setCapability("appium:platformVersion", "13.0") + caps.setCapability("appium:automationName", "UiAutomator2") + MutableCapabilities sauceOptions = new MutableCapabilities() + sauceOptions.setCapability("appiumVersion", "2.11.0") + sauceOptions.setCapability("username", sauceLabsUsername) + sauceOptions.setCapability("accessKey", sauceLabsAccessKey) + sauceOptions.setCapability("build", "") + sauceOptions.setCapability("name", "") + sauceOptions.setCapability("deviceOrientation", "PORTRAIT") + caps.setCapability("sauce:options", sauceOptions) + URL url = new URL("https://ondemand.eu-central-1.saucelabs.com:443/wd/hub") + AndroidDriver driver = new AndroidDriver(url, caps) return driver } } - edge { + // Configuration for mobile app environment using IOSDriver + "${Environments.MOBILE_APP}" { driver = { - System.setProperty("webdriver.edge.driver", "REPLACE with your edge driver path") - - EdgeDriver driver = new EdgeDriver() - def env = System.getenv() - if(env.HTTP_PROXY) { - Proxy proxy = new Proxy(); - URL url = new URL(env.HTTP_PROXY); - proxy.setHttpProxy("${url.getHost()}:${url.getPort()}"); - proxy.setNoProxy(env.NO_PROXY) - driver.setProxySettings(proxy); - } - return driver - } - } - - android { - driver = { - DesiredCapabilities capabilities = new DesiredCapabilities() - capabilities.setCapability("platformName", "Android") - capabilities.setCapability("deviceName", "REPLACE with your device name") - capabilities.setCapability("app", "REPLACE with your application mobile path") - capabilities.setCapability("browserVersion", "REPLACE with your android version"); - capabilities.setCapability("automationName", "UiAutomator2"); - capabilities.setCapability("autoGrantPermissions", "true"); - AndroidDriver driver = new AndroidDriver(new URL(androidURL), caps); - return driver - } - } - - ios { - driver = { - DesiredCapabilities capabilities = new DesiredCapabilities() - capabilities.setCapability("platformName", "iOS") - capabilities.setCapability("deviceName", "REPLACE with your device name") - capabilities.setCapability("app", "REPLACE with your application mobile path") - capabilities.setCapability("browserName", "REPLACE with your browser name"); - capabilities.setCapability("browserVersion", "REPLACE with your browser version"); - capabilities.setCapability("automationName", "XCUITest"); - capabilities.setCapability("autoGrantPermissions", "true"); - IOSDriver driver = new IOSDriver(new URL(iosURL), caps); + MutableCapabilities caps = new MutableCapabilities() + caps.setCapability("platformName", "iOS") + caps.setCapability("appium:app", "storage:filename=SauceLabs-Demo-App.Simulator.XCUITest.zip") // The filename of the mobile app + caps.setCapability("appium:deviceName", "iPhone Simulator") + caps.setCapability("appium:platformVersion", "17.0") + caps.setCapability("appium:automationName", "XCUITest") + MutableCapabilities sauceOptions = new MutableCapabilities() + sauceOptions.setCapability("appiumVersion", "2.1.3") + sauceOptions.setCapability("username", sauceLabsUsername) + sauceOptions.setCapability("accessKey", sauceLabsAccessKey) + sauceOptions.setCapability("build", "") + sauceOptions.setCapability("name", "") + sauceOptions.setCapability("deviceOrientation", "PORTRAIT") + caps.setCapability("sauce:options", sauceOptions) + URL url = new URL("https://ondemand.eu-central-1.saucelabs.com:443/wd/hub") + IOSDriver driver = new IOSDriver(url, caps) return driver } } } +// Configure waiting settings waiting { timeout = 25 retryInterval = 0.5 @@ -130,9 +94,8 @@ waiting { } } -// Base URL of the application to test +// Set the base URL of the application to test baseUrl = properties."config.application.url" -// Reports dir +// Set the directory for storing reports reportsDir = new File(properties."config.reports.dir") - diff --git a/e2e-spock-geb/files/src/test/resources/helpers/Environments.groovy b/e2e-spock-geb/files/src/test/resources/helpers/Environments.groovy new file mode 100644 index 000000000..eb547f961 --- /dev/null +++ b/e2e-spock-geb/files/src/test/resources/helpers/Environments.groovy @@ -0,0 +1,9 @@ +package helpers + +class Environments { + // Define environment constants using system properties + // Check the build.gradle file for the defined properties + static final String DESKTOP = System.getProperty('environments.desktop') + static final String MOBILE_BROWSER = System.getProperty('environments.mobile_browser') + static final String MOBILE_APP = System.getProperty('environments.mobile_app') +} diff --git a/e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy b/e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy index f20bb1aac..24fcb004f 100644 --- a/e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy +++ b/e2e-spock-geb/files/src/test/resources/helpers/SpecHelper.groovy @@ -2,18 +2,23 @@ package helpers import geb.navigator.Navigator import geb.spock.GebReportingSpec +import io.appium.java_client.AppiumDriver import org.openqa.selenium.By +import org.openqa.selenium.StaleElementReferenceException +import org.openqa.selenium.WebDriver +import org.openqa.selenium.WebElement import java.util.regex.Pattern class SpecHelper { + // Load application properties and replace placeholders with environment variables public Properties getApplicationProperties() { def env = System.getenv() def properties = new Properties() this.getClass().getResource('/application.properties').withInputStream { - properties.load(it) + properties.load(it) } properties.each { key, value -> @@ -32,29 +37,32 @@ class SpecHelper { return properties } + // Print evidence for a single page element public static void printEvidenceForPageElement(GebReportingSpec spec, int testStepNumber, Navigator fragment, String description = '', int desiredLevel = -1) { printEvidenceForPageElements(spec, testStepNumber, [ [ 'fragment' : fragment, 'description' : description] ], desiredLevel) } - public static void printEvidenceForPageElements(GebReportingSpec spec, int testStepNumber, List fragmentsAndDiscriptions, int desiredLevel = -1) { + // Print evidence for multiple page elements + public static void printEvidenceForPageElements(GebReportingSpec spec, int testStepNumber, List fragmentsAndDescriptions, int desiredLevel = -1) { println '=====================================' println "Test Case: ${spec.specificationContext.currentIteration.name}" println "Test Step: ${testStepNumber}" println "Page URL: ${spec.getBrowser().getPage().getDriver().getCurrentUrl()}" - if (!fragmentsAndDiscriptions || fragmentsAndDiscriptions.isEmpty()) { + if (!fragmentsAndDescriptions || fragmentsAndDescriptions.isEmpty()) { throw new IllegalArgumentException("Error: evidence fragment is empty!") } println "----- Test Evidence STARTS Here -----" - fragmentsAndDiscriptions.each { fragmentAndDescription -> + fragmentsAndDescriptions.each { fragmentAndDescription -> println "Description: ${fragmentAndDescription.description}" printEvidenceRecursive(fragmentAndDescription.fragment, 0, desiredLevel) } println "----- Test Evidence ENDS Here -----" } - private static printEvidenceRecursive(Navigator fragment, int level = 0, int desiredLevel = -1) { + // Recursively print evidence for a page element and its children + private static void printEvidenceRecursive(Navigator fragment, int level = 0, int desiredLevel = -1) { if (!fragment) { return } @@ -63,50 +71,105 @@ class SpecHelper { return } - // create fragmentIndentation based on level + // Create indentation based on the level String fragmentIndentation = '' for (int i = 0; i < level; i++) { fragmentIndentation += ' ' } - // create the prepend for the fragment, current level, plus strings + // Prepend the fragment with the current level and indentation String fragmentPrepend = "(${level})${fragmentIndentation}" - Navigator children = fragment.children(); - // no children of current fragment - print fragment and content - // (value for input types, text or for images or links, nothing) + Navigator children = fragment.children() + // If no children, print the fragment and its content if (children.size() == 0) { def value = fragment.value() ?: fragment.text() println "${fragmentPrepend}${fragment} ${value}" } else { - // print the current fragment without any content + // Print the current fragment without content println "${fragmentPrepend}${fragment}" - // for each child print the evidence recursively + // Recursively print each child children.each { child -> printEvidenceRecursive(child, (level + 1), desiredLevel) } } } - public static void printEvidenceForMobileElement(GebReportingSpec spec, int testStepNumber, By fragment, String description = '', int desiredLevel = -1) { - printEvidenceForMobileElements(spec, testStepNumber, [ [ 'fragment' : fragment, 'description' : description] ], desiredLevel) + // Print evidence for a single web element + public static void printEvidenceForWebElement(GebReportingSpec spec, int testStepNumber, WebElement element, String description = '', int desiredLevel = -1) { + printEvidenceForWebElements(spec, testStepNumber, [ ['element': element, 'description': description] ], desiredLevel) } - public static void printEvidenceForMobileElements(GebReportingSpec spec, int testStepNumber, List fragmentsAndDiscriptions, int desiredLevel = -1) { + // Print evidence for multiple web elements + public static void printEvidenceForWebElements(GebReportingSpec spec, int testStepNumber, List elementsAndDescriptions, int desiredLevel = -1) { println '=====================================' println "Test Case: ${spec.specificationContext.currentIteration.name}" println "Test Step: ${testStepNumber}" - if (!fragmentsAndDiscriptions || fragmentsAndDiscriptions.isEmpty()) { - throw new IllegalArgumentException("Error: evidence fragment is empty!") + if (!elementsAndDescriptions || elementsAndDescriptions.isEmpty()) { + throw new IllegalArgumentException("Error: evidence element is empty!") + } + + WebDriver driver = spec.getBrowser().getPage().getDriver() + if (driver instanceof AppiumDriver) { + println "Page Source: ${driver.getPageSource()}" + } else { + println "Page URL: ${driver.getCurrentUrl()}" } println "----- Test Evidence STARTS Here -----" - fragmentsAndDiscriptions.each { fragmentAndDescription -> - println "Description: ${fragmentAndDescription.description}" - println "Fragment: ${fragmentAndDescription.fragment}" + elementsAndDescriptions.each { elementAndDescriptions -> + println "Description: ${elementAndDescriptions.description}" + printEvidenceRecursive(elementAndDescriptions.element, 0, desiredLevel) } println "----- Test Evidence ENDS Here -----" } + + // Recursively print evidence for a web element and its children + private static void printEvidenceRecursive(WebElement element, int level = 0, int desiredLevel = -1) { + if (element == null) { + return + } + + if (level == desiredLevel) { + return + } + + // Create indentation based on the level + String fragmentIndentation = '' + for (int i = 0; i < level; i++) { + fragmentIndentation += ' ' + } + + // Prepend the element with the current level and indentation + String fragmentPrepend = "(${level})${fragmentIndentation}" + + List children + try { + children = element.findElements(By.xpath("./*")) + } catch (StaleElementReferenceException e) { + println "${fragmentPrepend}${element} [Stale Element]" + return + } + + // If no children, print the element and its content + if (children.isEmpty()) { + try { + def value = element.getAttribute("value") ?: element.getText() + println "${fragmentPrepend}${element} ${value}" + } catch (StaleElementReferenceException e) { + println "${fragmentPrepend}${element} [Stale Element]" + } + } else { + // Print the current element without content + println "${fragmentPrepend}${element}" + + // Recursively print each child + children.each { child -> + printEvidenceRecursive(child, (level + 1), desiredLevel) + } + } + } + } From c26d514a66feae9b1fbb7ad96d9c3d9ebd0a15f8 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Wed, 11 Dec 2024 14:11:14 +0100 Subject: [PATCH 06/14] [Review] adoc --- .../quickstarters/pages/e2e-spock-geb.adoc | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc index 87627f89d..dabe46f6d 100644 --- a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc +++ b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc @@ -1,10 +1,10 @@ -= End-to-end tests with Spock, Geb and Unirest (e2e-spock-geb) += End-to-end tests with Spock, Geb, Unirest, and Appium (e2e-spock-geb) -Spock, Geb, Unirest and Apium e2e testing quickstarter project +Spock, Geb, Unirest, and Appium e2e testing quickstarter project == Purpose of this quickstarter -This is a Spock, Geb, Unirest and Apium e2e testing project quickstarter with basic setup for https://jenkins.io/[Jenkins], https://www.sonarqube.org/[SonarQube], https://gradle.org/[Gradle], and https://appium.io/[Appium]. +This is a Spock, Geb, Unirest, and Appium e2e testing project quickstarter with basic setup for https://jenkins.io/[Jenkins], https://www.sonarqube.org/[SonarQube], https://gradle.org/[Gradle], and https://appium.io/[Appium]. == What files / architecture is generated? @@ -84,8 +84,8 @@ If you do not want to use Nexus at all, just define the following property: ``` no_nexus=true ``` -Run `gradlew -v` to verify the installed version of gradle wrapper. +Run `gradlew -v` to verify the installed version of gradle wrapper. === Environments Configuration @@ -120,19 +120,21 @@ class Environments { } ``` -== Frameworks used +== Sauce Labs Integration -This project is generated by https://gradle.org/[Gradle] +Sauce Labs is a cloud-based platform that provides comprehensive testing solutions for web and mobile applications. It allows you to run tests on a wide range of real devices and emulators/simulators, ensuring your applications work seamlessly across different environments. -******* http://spockframework.org/[spock] +This template is prepared to work with Sauce Labs virtual devices, allowing you to perform all mobile tests on these virtual devices. -******* https://gebish.org/[geb] +=== Key Features of Sauce Labs -******* http://unirest.io/[unirest] - -******* https://appium.io/[apium] +* **Real Device Cloud**: Access to thousands of real Android and iOS devices for manual and automated testing. +* **Emulators and Simulators**: Cost-effective and scalable testing on virtual devices. +* **Cross-Browser Testing**: Ensure compatibility across various browser and OS combinations. +* **Error Monitoring and Reporting**: Capture and resolve application errors quickly with detailed insights. +* **CI/CD Integration**: Seamlessly integrate with your continuous integration and delivery pipelines. -## Usage - how do you start after you provisioned this quickstarter +== Usage - how do you start after you provisioned this quickstarter * Run command `gradlew test` in project directory to execute the end-to-end tests via spock/geb against the demo pages and demo jUnit 5 tests. @@ -158,6 +160,19 @@ You will see the results inside a new folder 'build' in project directory. └── TEST-DemoIntegrationTest.xml ---- +== Frameworks used + +This project is generated by https://gradle.org/[Gradle] + +******* http://spockframework.org/[spock] + +******* https://gebish.org/[geb] + +******* http://unirest.io/[unirest] + +******* https://appium.io/[apium] + +******* https://saucelabs.com/[Sauce Labs] ## Customization - how do you start to configure your test @@ -188,4 +203,4 @@ https://github.com/opendevstack/ods-quickstarters/tree/master/common/jenkins-age == Known limitations -NA +NA \ No newline at end of file From ade4de70dc61b13af5be74d84c84235974878a95 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Wed, 11 Dec 2024 14:17:30 +0100 Subject: [PATCH 07/14] [Review] adoc - saucelabs secret --- docs/modules/quickstarters/pages/e2e-spock-geb.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc index dabe46f6d..3d2bf19ca 100644 --- a/docs/modules/quickstarters/pages/e2e-spock-geb.adoc +++ b/docs/modules/quickstarters/pages/e2e-spock-geb.adoc @@ -134,6 +134,10 @@ This template is prepared to work with Sauce Labs virtual devices, allowing you * **Error Monitoring and Reporting**: Capture and resolve application errors quickly with detailed insights. * **CI/CD Integration**: Seamlessly integrate with your continuous integration and delivery pipelines. +=== How to use it + +To use Sauce Labs, a secret will be created by default where the `username` and `accessKey` necessary to execute the test cases in Sauce Labs will be stored. By default, these values will be set to "changeme". Once you have obtained your Sauce Labs username and access key, you should modify the secret data to start interacting with Sauce Labs. + == Usage - how do you start after you provisioned this quickstarter * Run command `gradlew test` in project directory to execute the end-to-end tests via spock/geb against the demo pages and demo jUnit 5 tests. From a62fa41af9eb949edc5bc993cf33ce4f63569c02 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Wed, 11 Dec 2024 14:20:56 +0100 Subject: [PATCH 08/14] [Review] Jenkinsfile.template --- e2e-spock-geb/Jenkinsfile.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index 60dc31d76..eddda9402 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -50,7 +50,7 @@ def stageTest(def context) { if (context.environment == 'prod') { status = sh(script: './gradlew clean testProd --stacktrace --no-daemon', returnStatus: true) junit(testResults:"build/test-results/installation*/*.xml", allowEmptyResults:true) - stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/*installation*/*.xml', allowEmpty: true) + stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/installation*/*.xml', allowEmpty: true) } else { status = sh(script: './gradlew clean test --stacktrace --no-daemon', returnStatus: true) junit(testResults:"build/test-results/installation*/*.xml, build/test-results/integration*/*.xml, build/test-results/acceptance*/*.xml", allowEmptyResults:true) From 7f5f8c8bbb1cc06d64e7d5b57d214974972d5e99 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Wed, 11 Dec 2024 15:25:46 +0100 Subject: [PATCH 09/14] [Review] some changes --- e2e-spock-geb/files/build.gradle | 29 +--- .../groovy/specs/DemoGebHomePageSpec.groovy | 8 +- .../groovy/specs/DemoMobileAppSpec.groovy | 120 ++++++------- .../specs/DemoMobileGebHomePageSpec.groovy | 160 +++++++++--------- .../acceptance/java/DemoAcceptanceTest.java | 31 ++-- .../groovy/DemoInstallationSpec.groovy | 35 ++-- .../java/DemoInstallationTest.java | 31 ++-- .../groovy/DemoIntegrationSpec.groovy | 35 ++-- .../integration/java/DemoIntegrationTest.java | 31 ++-- 9 files changed, 193 insertions(+), 287 deletions(-) diff --git a/e2e-spock-geb/files/build.gradle b/e2e-spock-geb/files/build.gradle index b7fcdf9f1..451e08767 100644 --- a/e2e-spock-geb/files/build.gradle +++ b/e2e-spock-geb/files/build.gradle @@ -69,8 +69,8 @@ ext { // Define environments as project properties to be accessed via system properties in Groovy classes environments = [ DESKTOP: "desktop", - MOBILE_BROWSER: "mobile_browser", - MOBILE_APP: "mobile_app" +// MOBILE_BROWSER: "mobile_browser", +// MOBILE_APP: "mobile_app" ] } @@ -156,31 +156,10 @@ def executeTest(def type, def language, def env) { } } -def executeTestProd(def type, def language, def env) { - return tasks.create(generateTaskName(type, language, env), Test) { - description = "Runs ${type} tests ${language} in ${env} environment." - group = "verification-${type}" - - // Since groovy tests are junit tests and they are run as part of java tests, - // we disable here the execution of junit tests if not running for java language. - // jenkins to jira integration does not allows to run a test more than once. - if ("${language}".equalsIgnoreCase(TestLanguages.JAVA)) { - // Mandatory to run JUnit 5 test but incompatible with groovy tests - useJUnitPlatform() - } - - ignoreFailures = "${CONTINUE_WHEN_TEST_FAIL}" - testClassesDirs = sourceSets["${type}"].output.classesDirs - classpath = sourceSets["${type}"].runtimeClasspath - - systemProperty "geb.env", env - - } -} - test { + // To create the tasks - environments.each {env -> + environments.each { env -> [TestExecutionPhases.INSTALLATION, TestExecutionPhases.INTEGRATION, TestExecutionPhases.ACCEPTANCE].each { phase -> [TestLanguages.JAVA, TestLanguages.GROOVY].each { language -> dependsOn executeTest(phase, language, env.value) diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy index ef5d76566..7131a75a5 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy @@ -3,7 +3,6 @@ package specs import geb.spock.GebReportingSpec import pages.DemoGebHomePage import pages.DemoTheBookOfGebPage -import spock.lang.IgnoreIf import helpers.* class DemoGebHomePageSpec extends GebReportingSpec { @@ -13,14 +12,9 @@ class DemoGebHomePageSpec extends GebReportingSpec { def theBookOfGebPage = page(DemoTheBookOfGebPage) def setupSpec() { - // Check the environment and skip tests if it is not DESKTOP - if (System.getProperty("geb.env") != Environments.DESKTOP) { - println "Skipping tests - environments not supported" - return - } + } - @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) def "can access The Book of Geb via homepage"() { given: // Navigate to the Geb home page diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy index 26592d519..f6a553d88 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy @@ -1,68 +1,52 @@ -package specs - -import geb.spock.GebReportingSpec -import io.appium.java_client.AppiumDriver -import io.appium.java_client.AppiumBy -import org.openqa.selenium.WebElement -import org.openqa.selenium.support.ui.WebDriverWait -import org.openqa.selenium.support.ui.ExpectedConditions -import spock.lang.IgnoreIf -import spock.lang.Shared -import spock.lang.Stepwise -import helpers.* - -@Stepwise -class DemoMobileAppSpec extends GebReportingSpec { - - // Shared driver instance for the AppiumDriver - @Shared - def static driver - // Shared result variable to track test success - @Shared - def static result = true - - def setupSpec() { - // Check the environment and skip tests if it is not MOBILE_APP - if (System.getProperty("geb.env") != Environments.MOBILE_APP) { - println "Skipping tests - environments not supported" - return - } - // Initialize the Appium driver - driver = browser.driver as AppiumDriver - } - - def cleanupSpec() { - // Set the job result and quit the driver if it is initialized - if (driver) { - driver.executeScript("sauce:job-result=$result") - driver.quit() - } - } - - @IgnoreIf({ System.getProperty("geb.env") != Environments.MOBILE_APP}) - def "check elements in the first page of the app"() { - given: "Launching the app" - when: "Printing all the elements" - try { - // Verify if the specific element is present - List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) - - if (!specificElements.isEmpty() && specificElements[0].isDisplayed()) { - // Click on the element - specificElements[0].click() - println "Clicked on element with name 'Cart-tab-item'" - - // Print evidence for the specific element - SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") - } else { - println "Element with name 'Cart-tab-item' not found or not displayed" - } - } catch (Exception e) { - result = false - throw e - } - then: "The specific element should be present" - assert true - } - -} +//package specs +// +//import geb.spock.GebReportingSpec +//import io.appium.java_client.AppiumDriver +//import io.appium.java_client.AppiumBy +//import org.openqa.selenium.WebElement +//import spock.lang.Shared +//import spock.lang.Stepwise +//import helpers.* +// +//@Stepwise +//class DemoMobileAppSpec extends GebReportingSpec { +// +// // Shared driver instance for the AppiumDriver +// @Shared +// def static driver +// // Shared result variable to track test success +// @Shared +// def static result = true +// +// def setupSpec() { +// // Initialize the Appium driver +// driver = browser.driver as AppiumDriver +// } +// +// def cleanupSpec() { +// // Set the job result and quit the driver if it is initialized +// if (driver) { +// driver.executeScript("sauce:job-result=$result") +// driver.quit() +// } +// } +// +// def "check elements in the first page of the app"() { +// given: "Launching the app" +// when: "Printing all the elements" +// try { +// // Verify if the specific element is present +// List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) +// // Click on the element +// specificElements[0].click() +// // Print evidence for the specific element +// SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") +// } catch (Exception e) { +// result = false +// throw e +// } +// then: "The specific element should be present" +// assert true +// } +// +//} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy index fb0aa049c..4c7cb9d7e 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy @@ -1,84 +1,76 @@ -package specs - -import geb.spock.GebReportingSpec -import io.appium.java_client.AppiumDriver -import org.openqa.selenium.WebElement -import spock.lang.Shared -import spock.lang.Stepwise -import spock.lang.IgnoreIf -import helpers.* - -@Stepwise -class DemoMobileGebHomePageSpec extends GebReportingSpec { - - // Shared driver instance for the AppiumDriver - @Shared - def static driver - // Shared result variable to track test success - @Shared - def static result = true - - def setupSpec() { - // Check the environment and skip tests if it is not MOBILE_BROWSER - if (System.getProperty("geb.env") != Environments.MOBILE_BROWSER) { - println "Skipping tests - environments not supported" - return - } - - // Initialize the Appium driver - driver = browser.driver as AppiumDriver - } - - def cleanupSpec() { - // Set the job result and quit the driver if it is initialized - if (driver) { - driver.executeScript("sauce:job-result=$result") - driver.quit() - } - } - - @IgnoreIf({ System.getProperty("geb.env") != Environments.MOBILE_BROWSER }) - def "verify geb home page and documentation navigation"() { - when: "Navigating to Geb home page" - try { - // Open the Geb home page - driver.get("https://www.gebish.org") - } catch (AssertionError e) { - result = false - throw e - } - - then: "The page title should be 'Geb - Very Groovy Browser Automation'" - try { - // Verify the page title - assert title == "Geb - Very Groovy Browser Automation" - } catch (AssertionError e) { - result = false - throw e - } - - when: "Accessing to the Documentation page" - try { - // Wait for the Documentation button to be displayed and click it - waitFor { $("button.ui.blue.button", text: "Documentation").displayed } - WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() - documentationButton.click() - - // Print evidence for the Documentation button - SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") - } catch (AssertionError e) { - result = false - throw e - } - - then: "The page title should be 'The Book Of Geb'" - try { - // Verify the page title - assert title == "The Book Of Geb" - } catch (AssertionError e) { - result = false - throw e - } - } - -} +//package specs +// +//import geb.spock.GebReportingSpec +//import io.appium.java_client.AppiumDriver +//import org.openqa.selenium.WebElement +//import spock.lang.Shared +//import spock.lang.Stepwise +//import helpers.* +// +//@Stepwise +//class DemoMobileGebHomePageSpec extends GebReportingSpec { +// +// // Shared driver instance for the AppiumDriver +// @Shared +// def static driver +// // Shared result variable to track test success +// @Shared +// def static result = true +// +// def setupSpec() { +// // Initialize the Appium driver +// driver = browser.driver as AppiumDriver +// } +// +// def cleanupSpec() { +// // Set the job result and quit the driver if it is initialized +// if (driver) { +// driver.executeScript("sauce:job-result=$result") +// driver.quit() +// } +// } +// +// def "verify geb home page and documentation navigation"() { +// when: "Navigating to Geb home page" +// try { +// // Open the Geb home page +// driver.get("https://www.gebish.org") +// } catch (AssertionError e) { +// result = false +// throw e +// } +// +// then: "The page title should be 'Geb - Very Groovy Browser Automation'" +// try { +// // Verify the page title +// assert title == "Geb - Very Groovy Browser Automation" +// } catch (AssertionError e) { +// result = false +// throw e +// } +// +// when: "Accessing to the Documentation page" +// try { +// // Wait for the Documentation button to be displayed and click it +// waitFor { $("button.ui.blue.button", text: "Documentation").displayed } +// WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() +// documentationButton.click() +// +// // Print evidence for the Documentation button +// SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") +// } catch (AssertionError e) { +// result = false +// throw e +// } +// +// then: "The page title should be 'The Book Of Geb'" +// try { +// // Verify the page title +// assert title.contains("The Book Of Geb") == "The Book Of Geb" +// } catch (AssertionError e) { +// result = false +// throw e +// } +// } +// +//} diff --git a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java index 24f0d6f3c..4827e1c9a 100644 --- a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java +++ b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java @@ -1,19 +1,12 @@ -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIf; - -public class DemoAcceptanceTest { - - @Test - @EnabledIf("customCondition") - void basicTest() { - // Assert that the condition is true - Assertions.assertTrue(true); - } - - boolean customCondition() { - // Custom condition logic to determine if the test should be enabled - return false; - } - -} +//import org.junit.jupiter.api.Assertions; +//import org.junit.jupiter.api.Test; +// +//public class DemoAcceptanceTest { +// +// @Test +// void basicTest() { +// // Assert that the condition is true +// Assertions.assertTrue(true); +// } +// +//} diff --git a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy index 16c550236..8fc3cd831 100644 --- a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy +++ b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy @@ -1,23 +1,12 @@ -import geb.spock.GebReportingSpec -import helpers.Environments -import spock.lang.IgnoreIf -import spock.lang.Stepwise - -@Stepwise -class DemoInstallationSpec extends GebReportingSpec { - - def setupSpec() { - // Check the environment and skip tests if necessary - if (System.getProperty("geb.env") != Environments.DESKTOP) { - println "Skipping tests - environments not supported" - return - } - } - - @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) - def "basic test"() { - given: "Example test" - true == true - } -} - +//import geb.spock.GebReportingSpec +//import spock.lang.Stepwise +// +//@Stepwise +//class DemoInstallationSpec extends GebReportingSpec { +// +// def "basic test"() { +// given: "Example test" +// true == true +// } +//} +// diff --git a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java index 6a5a5fb20..f2bdc25fd 100644 --- a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java +++ b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java @@ -1,19 +1,12 @@ -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIf; - -public class DemoInstallationTest { - - @Test - @EnabledIf("customCondition") - void basicTest() { - // Assert that the condition is true - Assertions.assertTrue(true); - } - - boolean customCondition() { - // Implement your custom condition logic here - return false; - } - -} +//import org.junit.jupiter.api.Assertions; +//import org.junit.jupiter.api.Test; +// +//public class DemoInstallationTest { +// +// @Test +// void basicTest() { +// // Assert that the condition is true +// Assertions.assertTrue(true); +// } +// +//} diff --git a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy index 0311071ca..55c517c54 100644 --- a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy +++ b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy @@ -1,23 +1,12 @@ -import geb.spock.GebReportingSpec -import helpers.Environments -import spock.lang.IgnoreIf -import spock.lang.Stepwise - -@Stepwise -class DemoIntegrationSpec extends GebReportingSpec { - - def setupSpec() { - // Check the environment and skip tests if it is not DESKTOP - if (System.getProperty("geb.env") != Environments.DESKTOP) { - println "Skipping tests - environments not supported" - return - } - } - - @IgnoreIf({ System.getProperty("geb.env") != Environments.DESKTOP }) - def "basic test"() { - given: "An example test scenario" - // This is a placeholder assertion for demonstration purposes - true == true - } -} +//import geb.spock.GebReportingSpec +//import spock.lang.Stepwise +// +//@Stepwise +//class DemoIntegrationSpec extends GebReportingSpec { +// +// def "basic test"() { +// given: "An example test scenario" +// // This is a placeholder assertion for demonstration purposes +// true == true +// } +//} diff --git a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java index ff6ffe58e..9364494dd 100644 --- a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java +++ b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java @@ -1,19 +1,12 @@ -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIf; - -public class DemoIntegrationTest { - - @Test - @EnabledIf("customCondition") - void basicTest() { - // Assert that the condition is true - Assertions.assertTrue(true); - } - - boolean customCondition() { - // Implement your custom condition logic here - return false; - } - -} +//import org.junit.jupiter.api.Assertions; +//import org.junit.jupiter.api.Test; +// +//public class DemoIntegrationTest { +// +// @Test +// void basicTest() { +// // Assert that the condition is true +// Assertions.assertTrue(true); +// } +// +//} From 3d587f6780df0e001551d1643b0635db43cf2ce5 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 12 Dec 2024 07:20:06 +0100 Subject: [PATCH 10/14] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57d5153bc..5d9ab01d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ - Added new function to cypress to log into applications using MFA ([#1070](https://github.com/opendevstack/ods-quickstarters/pull/1070)) - Removal of deprecated versions ([#1068](https://github.com/opendevstack/ods-quickstarters/issues/1068)) - Generate PDF report for cypress and improved environment management ([#1079](https://github.com/opendevstack/ods-quickstarters/pull/1079)) +- Mobile testing enablement adding Appium in e2e-spock-geb quickstarter ### Added From 978db59defc2a575f185345ef09809cd5cc6e56e Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 12 Dec 2024 07:38:15 +0100 Subject: [PATCH 11/14] [Review] status management --- e2e-spock-geb/Jenkinsfile.template | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index eddda9402..73b4678ea 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -58,8 +58,17 @@ def stageTest(def context) { stash(name: "integration-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/integration*/*.xml', allowEmpty: true) stash(name: "acceptance-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/acceptance*/*.xml', allowEmpty: true) } - if (status != 0) { - error "Executing tests failed!" + + // Handle the test status + switch (status) { + case 0: + echo "All tests passed successfully" + break + case 1: + unstable "Some tests have failed" + break + default: + error "Something went wrong, when executing tests, exitCode ${status}" } } } From ca8c90d2048bbf34949d542d5bc0f7bd2342f935 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 12 Dec 2024 09:49:53 +0100 Subject: [PATCH 12/14] [Review] Using tags to include/exclude tests --- e2e-spock-geb/files/.pre-commit-config.yaml | 2 +- e2e-spock-geb/files/build.gradle | 23 ++- .../gradle/wrapper/gradle-wrapper.properties | 2 +- .../groovy/specs/DemoGebHomePageSpec.groovy | 4 +- .../groovy/specs/DemoMobileAppSpec.groovy | 106 ++++++------ .../specs/DemoMobileGebHomePageSpec.groovy | 154 +++++++++--------- .../acceptance/java/DemoAcceptanceTest.java | 26 +-- .../groovy/DemoInstallationSpec.groovy | 26 +-- .../java/DemoInstallationTest.java | 26 +-- .../groovy/DemoIntegrationSpec.groovy | 26 +-- .../integration/java/DemoIntegrationTest.java | 26 +-- 11 files changed, 227 insertions(+), 194 deletions(-) diff --git a/e2e-spock-geb/files/.pre-commit-config.yaml b/e2e-spock-geb/files/.pre-commit-config.yaml index f1f8f73f5..c9528f476 100644 --- a/e2e-spock-geb/files/.pre-commit-config.yaml +++ b/e2e-spock-geb/files/.pre-commit-config.yaml @@ -1,5 +1,5 @@ repos: - repo: https://github.com/gitleaks/gitleaks - rev: v8.18.4 + rev: v8.16.1 hooks: - id: gitleaks diff --git a/e2e-spock-geb/files/build.gradle b/e2e-spock-geb/files/build.gradle index 451e08767..47ac21964 100644 --- a/e2e-spock-geb/files/build.gradle +++ b/e2e-spock-geb/files/build.gradle @@ -19,9 +19,9 @@ buildscript { } plugins { - id 'java' - id 'groovy' - id 'com.adarshr.test-logger' version "2.0.0" + id 'java' + id 'groovy' + id 'com.adarshr.test-logger' version "2.0.0" } java { @@ -67,6 +67,7 @@ ext { apiGuardianAPI = "1.1.2" CONTINUE_WHEN_TEST_FAIL = true // Define environments as project properties to be accessed via system properties in Groovy classes + // Please, adjust the environments according to your project needs environments = [ DESKTOP: "desktop", // MOBILE_BROWSER: "mobile_browser", @@ -139,6 +140,22 @@ def executeTest(def type, def language, def env) { description = "Runs ${type} tests ${language} in ${env} environment." group = "verification-${type}" + // Specify the tags to include/exclude for each environment + // Please, adjust the tags according to your project needs + useJUnitPlatform { + switch (env) { + case environments.DESKTOP: + includeTags 'demo_desktop' + break +// case environments.MOBILE_BROWSER: +// includeTags 'demo_mobile_browser' +// break +// case environments.MOBILE_APP: +// includeTags 'demo_mobile_app' +// break + } + } + // Since groovy tests are junit tests and they are run as part of java tests, // we disable here the execution of junit tests if not running for java language. // jenkins to jira integration does not allows to run a test more than once. diff --git a/e2e-spock-geb/files/gradle/wrapper/gradle-wrapper.properties b/e2e-spock-geb/files/gradle/wrapper/gradle-wrapper.properties index e1adfb493..a59520664 100644 --- a/e2e-spock-geb/files/gradle/wrapper/gradle-wrapper.properties +++ b/e2e-spock-geb/files/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy index 7131a75a5..371b0a7c3 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy @@ -3,7 +3,8 @@ package specs import geb.spock.GebReportingSpec import pages.DemoGebHomePage import pages.DemoTheBookOfGebPage -import helpers.* +import helpers.SpecHelper +import spock.lang.Tag class DemoGebHomePageSpec extends GebReportingSpec { @@ -15,6 +16,7 @@ class DemoGebHomePageSpec extends GebReportingSpec { } + @Tag("demo_desktop") def "can access The Book of Geb via homepage"() { given: // Navigate to the Geb home page diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy index f6a553d88..e6041c44c 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy @@ -1,52 +1,54 @@ -//package specs -// -//import geb.spock.GebReportingSpec -//import io.appium.java_client.AppiumDriver -//import io.appium.java_client.AppiumBy -//import org.openqa.selenium.WebElement -//import spock.lang.Shared -//import spock.lang.Stepwise -//import helpers.* -// -//@Stepwise -//class DemoMobileAppSpec extends GebReportingSpec { -// -// // Shared driver instance for the AppiumDriver -// @Shared -// def static driver -// // Shared result variable to track test success -// @Shared -// def static result = true -// -// def setupSpec() { -// // Initialize the Appium driver -// driver = browser.driver as AppiumDriver -// } -// -// def cleanupSpec() { -// // Set the job result and quit the driver if it is initialized -// if (driver) { -// driver.executeScript("sauce:job-result=$result") -// driver.quit() -// } -// } -// -// def "check elements in the first page of the app"() { -// given: "Launching the app" -// when: "Printing all the elements" -// try { -// // Verify if the specific element is present -// List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) -// // Click on the element -// specificElements[0].click() -// // Print evidence for the specific element -// SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") -// } catch (Exception e) { -// result = false -// throw e -// } -// then: "The specific element should be present" -// assert true -// } -// -//} +package specs + +import geb.spock.GebReportingSpec +import io.appium.java_client.AppiumDriver +import io.appium.java_client.AppiumBy +import org.openqa.selenium.WebElement +import spock.lang.Shared +import spock.lang.Stepwise +import spock.lang.Tag +import helpers.SpecHelper + +@Stepwise +class DemoMobileAppSpec extends GebReportingSpec { + + // Shared driver instance for the AppiumDriver + @Shared + def static driver + // Shared result variable to track test success + @Shared + def static result = true + + def setupSpec() { + // Initialize the Appium driver + driver = browser.driver as AppiumDriver + } + + def cleanupSpec() { + // Set the job result and quit the driver if it is initialized + if (driver) { + driver.executeScript("sauce:job-result=$result") + driver.quit() + } + } + + @Tag("demo_mobile_app") + def "check elements in the first page of the app"() { + given: "Launching the app" + when: "Printing all the elements" + try { + // Verify if the specific element is present + List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) + // Click on the element + specificElements[0].click() + // Print evidence for the specific element + SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") + } catch (Exception e) { + result = false + throw e + } + then: "The specific element should be present" + assert true + } + +} diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy index 4c7cb9d7e..39ebfa25d 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy @@ -1,76 +1,78 @@ -//package specs -// -//import geb.spock.GebReportingSpec -//import io.appium.java_client.AppiumDriver -//import org.openqa.selenium.WebElement -//import spock.lang.Shared -//import spock.lang.Stepwise -//import helpers.* -// -//@Stepwise -//class DemoMobileGebHomePageSpec extends GebReportingSpec { -// -// // Shared driver instance for the AppiumDriver -// @Shared -// def static driver -// // Shared result variable to track test success -// @Shared -// def static result = true -// -// def setupSpec() { -// // Initialize the Appium driver -// driver = browser.driver as AppiumDriver -// } -// -// def cleanupSpec() { -// // Set the job result and quit the driver if it is initialized -// if (driver) { -// driver.executeScript("sauce:job-result=$result") -// driver.quit() -// } -// } -// -// def "verify geb home page and documentation navigation"() { -// when: "Navigating to Geb home page" -// try { -// // Open the Geb home page -// driver.get("https://www.gebish.org") -// } catch (AssertionError e) { -// result = false -// throw e -// } -// -// then: "The page title should be 'Geb - Very Groovy Browser Automation'" -// try { -// // Verify the page title -// assert title == "Geb - Very Groovy Browser Automation" -// } catch (AssertionError e) { -// result = false -// throw e -// } -// -// when: "Accessing to the Documentation page" -// try { -// // Wait for the Documentation button to be displayed and click it -// waitFor { $("button.ui.blue.button", text: "Documentation").displayed } -// WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() -// documentationButton.click() -// -// // Print evidence for the Documentation button -// SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") -// } catch (AssertionError e) { -// result = false -// throw e -// } -// -// then: "The page title should be 'The Book Of Geb'" -// try { -// // Verify the page title -// assert title.contains("The Book Of Geb") == "The Book Of Geb" -// } catch (AssertionError e) { -// result = false -// throw e -// } -// } -// -//} +package specs + +import geb.spock.GebReportingSpec +import io.appium.java_client.AppiumDriver +import org.openqa.selenium.WebElement +import spock.lang.Shared +import spock.lang.Stepwise +import spock.lang.Tag +import helpers.SpecHelper + +@Stepwise +class DemoMobileGebHomePageSpec extends GebReportingSpec { + + // Shared driver instance for the AppiumDriver + @Shared + def static driver + // Shared result variable to track test success + @Shared + def static result = true + + def setupSpec() { + // Initialize the Appium driver + driver = browser.driver as AppiumDriver + } + + def cleanupSpec() { + // Set the job result and quit the driver if it is initialized + if (driver) { + driver.executeScript("sauce:job-result=$result") + driver.quit() + } + } + + @Tag("demo_mobile_browser") + def "verify geb home page and documentation navigation"() { + when: "Navigating to Geb home page" + try { + // Open the Geb home page + driver.get("https://www.gebish.org") + } catch (AssertionError e) { + result = false + throw e + } + + then: "The page title should be 'Geb - Very Groovy Browser Automation'" + try { + // Verify the page title + assert title == "Geb - Very Groovy Browser Automation" + } catch (AssertionError e) { + result = false + throw e + } + + when: "Accessing to the Documentation page" + try { + // Wait for the Documentation button to be displayed and click it + waitFor { $("button.ui.blue.button", text: "Documentation").displayed } + WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() + documentationButton.click() + + // Print evidence for the Documentation button + SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") + } catch (AssertionError e) { + result = false + throw e + } + + then: "The page title should be 'The Book Of Geb'" + try { + // Verify the page title + assert title == "The Book Of Geb" + } catch (AssertionError e) { + result = false + throw e + } + } + +} diff --git a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java index 4827e1c9a..a64af6bb1 100644 --- a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java +++ b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java @@ -1,12 +1,14 @@ -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.Test; -// -//public class DemoAcceptanceTest { -// -// @Test -// void basicTest() { -// // Assert that the condition is true -// Assertions.assertTrue(true); -// } -// -//} +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import spock.lang.Tag; + +public class DemoAcceptanceTest { + + @Test + @Tag("empty") + void basicTest() { + // Assert that the condition is true + Assertions.assertTrue(true); + } + +} diff --git a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy index 8fc3cd831..99e85f900 100644 --- a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy +++ b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy @@ -1,12 +1,14 @@ -//import geb.spock.GebReportingSpec -//import spock.lang.Stepwise -// -//@Stepwise -//class DemoInstallationSpec extends GebReportingSpec { -// -// def "basic test"() { -// given: "Example test" -// true == true -// } -//} -// +import geb.spock.GebReportingSpec +import spock.lang.Stepwise +import spock.lang.Tag + +@Stepwise +class DemoInstallationSpec extends GebReportingSpec { + + @Tag("empty") + def "basic test"() { + given: "Example test" + true == true + } +} + diff --git a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java index f2bdc25fd..897068a53 100644 --- a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java +++ b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java @@ -1,12 +1,14 @@ -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.Test; -// -//public class DemoInstallationTest { -// -// @Test -// void basicTest() { -// // Assert that the condition is true -// Assertions.assertTrue(true); -// } -// -//} +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import spock.lang.Tag; + +public class DemoInstallationTest { + + @Test + @Tag("empty") + void basicTest() { + // Assert that the condition is true + Assertions.assertTrue(true); + } + +} diff --git a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy index 55c517c54..115b57814 100644 --- a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy +++ b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy @@ -1,12 +1,14 @@ -//import geb.spock.GebReportingSpec -//import spock.lang.Stepwise -// -//@Stepwise -//class DemoIntegrationSpec extends GebReportingSpec { -// -// def "basic test"() { -// given: "An example test scenario" -// // This is a placeholder assertion for demonstration purposes -// true == true -// } -//} +import geb.spock.GebReportingSpec +import spock.lang.Stepwise +import spock.lang.Tag + +@Stepwise +class DemoIntegrationSpec extends GebReportingSpec { + + @Tag("empty") + def "basic test"() { + given: "An example test scenario" + // This is a placeholder assertion for demonstration purposes + true == true + } +} diff --git a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java index 9364494dd..2c2928d36 100644 --- a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java +++ b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java @@ -1,12 +1,14 @@ -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.Test; -// -//public class DemoIntegrationTest { -// -// @Test -// void basicTest() { -// // Assert that the condition is true -// Assertions.assertTrue(true); -// } -// -//} +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import spock.lang.Tag; + +public class DemoIntegrationTest { + + @Test + @Tag("empty") + void basicTest() { + // Assert that the condition is true + Assertions.assertTrue(true); + } + +} From adac7b71fe807445a98bc7221ee09cf6a0205f79 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 12 Dec 2024 13:23:24 +0100 Subject: [PATCH 13/14] [Review] Removing try-catch blocks --- e2e-spock-geb/files/build.gradle | 6 +- .../groovy/specs/DemoGebHomePageSpec.groovy | 8 +-- .../groovy/specs/DemoMobileAppSpec.groovy | 47 ++++++------ .../specs/DemoMobileGebHomePageSpec.groovy | 71 ++++++++----------- .../acceptance/java/DemoAcceptanceTest.java | 1 - .../groovy/DemoInstallationSpec.groovy | 1 - .../java/DemoInstallationTest.java | 1 - .../groovy/DemoIntegrationSpec.groovy | 1 - .../integration/java/DemoIntegrationTest.java | 1 - 9 files changed, 61 insertions(+), 76 deletions(-) diff --git a/e2e-spock-geb/files/build.gradle b/e2e-spock-geb/files/build.gradle index 47ac21964..51339f518 100644 --- a/e2e-spock-geb/files/build.gradle +++ b/e2e-spock-geb/files/build.gradle @@ -145,13 +145,13 @@ def executeTest(def type, def language, def env) { useJUnitPlatform { switch (env) { case environments.DESKTOP: - includeTags 'demo_desktop' + includeTags 'test_desktop' break // case environments.MOBILE_BROWSER: -// includeTags 'demo_mobile_browser' +// includeTags 'test_mobile_browser' // break // case environments.MOBILE_APP: -// includeTags 'demo_mobile_app' +// includeTags 'test_mobile_app' // break } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy index 371b0a7c3..4c809306c 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy @@ -12,11 +12,9 @@ class DemoGebHomePageSpec extends GebReportingSpec { def gebHomePage = page(DemoGebHomePage) def theBookOfGebPage = page(DemoTheBookOfGebPage) - def setupSpec() { - - } - - @Tag("demo_desktop") + // Add this @Tag to include this test in the 'test_desktop' group. + // This tag ensures the test runs in the Environment.DESKTOP configuration. + @Tag("test_desktop") def "can access The Book of Geb via homepage"() { given: // Navigate to the Geb home page diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy index e6041c44c..a4f09e449 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy @@ -17,38 +17,45 @@ class DemoMobileAppSpec extends GebReportingSpec { def static driver // Shared result variable to track test success @Shared - def static result = true + def static result = false def setupSpec() { // Initialize the Appium driver driver = browser.driver as AppiumDriver } - def cleanupSpec() { - // Set the job result and quit the driver if it is initialized - if (driver) { - driver.executeScript("sauce:job-result=$result") - driver.quit() - } + // Quit the driver if it is initialized + driver.quit() + } + def setup() { + // Set the job result to false + result = false + } + def cleanup() { + // Set the job result in Sauce Labs + driver.executeScript("sauce:job-result=$result") } - @Tag("demo_mobile_app") + // Add this @Tag to include this test in the 'test_mobile_app' group. + // This tag ensures the test runs in the Environment.MOBILE_APP configuration. + @Tag("test_mobile_app") def "check elements in the first page of the app"() { given: "Launching the app" when: "Printing all the elements" - try { - // Verify if the specific element is present - List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) - // Click on the element - specificElements[0].click() - // Print evidence for the specific element - SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") - } catch (Exception e) { - result = false - throw e - } + // Verify if the specific element is present + List specificElements = driver.findElements(AppiumBy.name("Cart-tab-item")) + then: "The specific element should be present" - assert true + assert specificElements != null && !specificElements.isEmpty() + assert specificElements[0] != null + + // Click on the element + specificElements[0].click() + // Print evidence for the specific element + SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") + + // Set the job result to true if the assertion passes + (result = true) != null } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy index 39ebfa25d..3cf29b55d 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy @@ -16,63 +16,48 @@ class DemoMobileGebHomePageSpec extends GebReportingSpec { def static driver // Shared result variable to track test success @Shared - def static result = true + def static result = false def setupSpec() { // Initialize the Appium driver driver = browser.driver as AppiumDriver } - def cleanupSpec() { - // Set the job result and quit the driver if it is initialized - if (driver) { - driver.executeScript("sauce:job-result=$result") - driver.quit() - } + // Quit the driver if it is initialized + driver.quit() + } + def setup() { + // Set the job result to false + result = false + } + def cleanup() { + // Set the job result in Sauce Labs + driver.executeScript("sauce:job-result=$result") } - @Tag("demo_mobile_browser") + // Add this @Tag to include this test in the 'test_mobile_browser' group. + // This tag ensures the test runs in the Environment.MOBILE_BROWSER configuration. + @Tag("test_mobile_browser") def "verify geb home page and documentation navigation"() { when: "Navigating to Geb home page" - try { - // Open the Geb home page - driver.get("https://www.gebish.org") - } catch (AssertionError e) { - result = false - throw e - } - + // Open the Geb home page + driver.get("https://www.gebish.org") then: "The page title should be 'Geb - Very Groovy Browser Automation'" - try { - // Verify the page title - assert title == "Geb - Very Groovy Browser Automation" - } catch (AssertionError e) { - result = false - throw e - } - + // Verify the page title + assert title == "Geb - Very Groovy Browser Automation" when: "Accessing to the Documentation page" - try { - // Wait for the Documentation button to be displayed and click it - waitFor { $("button.ui.blue.button", text: "Documentation").displayed } - WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() - documentationButton.click() - - // Print evidence for the Documentation button - SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") - } catch (AssertionError e) { - result = false - throw e - } + // Wait for the Documentation button to be displayed and click it + waitFor { $("button.ui.blue.button", text: "Documentation").displayed } + WebElement documentationButton = $("button.ui.blue.button", text: "Documentation").firstElement() + documentationButton.click() + // Print evidence for the Documentation button + SpecHelper.printEvidenceForWebElement(this, 1, documentationButton, "Documentation Button Evidence") then: "The page title should be 'The Book Of Geb'" - try { - // Verify the page title - assert title == "The Book Of Geb" - } catch (AssertionError e) { - result = false - throw e - } + // Verify the page title + assert title == "The Book Of Geb" + // Set the job result to true if the assertion passes + (result = true) != null } } diff --git a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java index a64af6bb1..fe0c20363 100644 --- a/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java +++ b/e2e-spock-geb/files/src/test/acceptance/java/DemoAcceptanceTest.java @@ -5,7 +5,6 @@ public class DemoAcceptanceTest { @Test - @Tag("empty") void basicTest() { // Assert that the condition is true Assertions.assertTrue(true); diff --git a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy index 99e85f900..ab48d5e6a 100644 --- a/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy +++ b/e2e-spock-geb/files/src/test/installation/groovy/DemoInstallationSpec.groovy @@ -5,7 +5,6 @@ import spock.lang.Tag @Stepwise class DemoInstallationSpec extends GebReportingSpec { - @Tag("empty") def "basic test"() { given: "Example test" true == true diff --git a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java index 897068a53..3056dceff 100644 --- a/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java +++ b/e2e-spock-geb/files/src/test/installation/java/DemoInstallationTest.java @@ -5,7 +5,6 @@ public class DemoInstallationTest { @Test - @Tag("empty") void basicTest() { // Assert that the condition is true Assertions.assertTrue(true); diff --git a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy index 115b57814..ebfb28c85 100644 --- a/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy +++ b/e2e-spock-geb/files/src/test/integration/groovy/DemoIntegrationSpec.groovy @@ -5,7 +5,6 @@ import spock.lang.Tag @Stepwise class DemoIntegrationSpec extends GebReportingSpec { - @Tag("empty") def "basic test"() { given: "An example test scenario" // This is a placeholder assertion for demonstration purposes diff --git a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java index 2c2928d36..27d0604e3 100644 --- a/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java +++ b/e2e-spock-geb/files/src/test/integration/java/DemoIntegrationTest.java @@ -5,7 +5,6 @@ public class DemoIntegrationTest { @Test - @Tag("empty") void basicTest() { // Assert that the condition is true Assertions.assertTrue(true); From c796f0f6383b3e538dcb7fae6d8fc1e113aa6121 Mon Sep 17 00:00:00 2001 From: "Garcia,Ana_Maria (IT EDS) BI-ES-S" Date: Thu, 12 Dec 2024 15:12:21 +0100 Subject: [PATCH 14/14] [Review] Sauce labs results --- e2e-spock-geb/Jenkinsfile.template | 5 +--- .../groovy/specs/DemoGebHomePageSpec.groovy | 1 + .../groovy/specs/DemoMobileAppSpec.groovy | 23 ++++++++++++------- .../specs/DemoMobileGebHomePageSpec.groovy | 23 ++++++++++++------- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/e2e-spock-geb/Jenkinsfile.template b/e2e-spock-geb/Jenkinsfile.template index 73b4678ea..de1ce4aba 100644 --- a/e2e-spock-geb/Jenkinsfile.template +++ b/e2e-spock-geb/Jenkinsfile.template @@ -64,11 +64,8 @@ def stageTest(def context) { case 0: echo "All tests passed successfully" break - case 1: - unstable "Some tests have failed" - break default: - error "Something went wrong, when executing tests, exitCode ${status}" + unstable "Some tests have failed or encountered errors. Please check the logs for more details." } } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy index 4c809306c..9dc5ad57a 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoGebHomePageSpec.groovy @@ -40,4 +40,5 @@ class DemoGebHomePageSpec extends GebReportingSpec { // Verify that the browser is at the book page at theBookOfGebPage } + } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy index a4f09e449..2997eccd7 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileAppSpec.groovy @@ -15,9 +15,9 @@ class DemoMobileAppSpec extends GebReportingSpec { // Shared driver instance for the AppiumDriver @Shared def static driver - // Shared result variable to track test success + // Shared variable to indicate the success of the test for Sauce Labs @Shared - def static result = false + def static sauceLabsResult = false def setupSpec() { // Initialize the Appium driver @@ -28,12 +28,19 @@ class DemoMobileAppSpec extends GebReportingSpec { driver.quit() } def setup() { - // Set the job result to false - result = false + // Initialize the Sauce Labs result to false + sauceLabsResult = false } def cleanup() { - // Set the job result in Sauce Labs - driver.executeScript("sauce:job-result=$result") + // Set the job result in + driver.executeScript("sauce:job-result=$sauceLabsResult") + } + + // This function sets the Sauce Labs result to true, indicating that the test passed successfully. + // We use this variable to inform Sauce Labs about the test results, storing whether there were any failures. + // By setting it to true at the end of each test, we ensure that Sauce Labs is updated with the correct test status. + def setTrueResultForSauceLabs() { + (sauceLabsResult = true) != null } // Add this @Tag to include this test in the 'test_mobile_app' group. @@ -54,8 +61,8 @@ class DemoMobileAppSpec extends GebReportingSpec { // Print evidence for the specific element SpecHelper.printEvidenceForWebElement(this, 1, specificElements[0], "Cart-tab-item Element Evidence") - // Set the job result to true if the assertion passes - (result = true) != null + // Set the Sauce Labs result to true, indicating that the test passed successfully + setTrueResultForSauceLabs() } } diff --git a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy index 3cf29b55d..3e8590f3a 100644 --- a/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy +++ b/e2e-spock-geb/files/src/test/acceptance/groovy/specs/DemoMobileGebHomePageSpec.groovy @@ -14,9 +14,9 @@ class DemoMobileGebHomePageSpec extends GebReportingSpec { // Shared driver instance for the AppiumDriver @Shared def static driver - // Shared result variable to track test success + // Shared variable to indicate the success of the test for Sauce Labs @Shared - def static result = false + def static sauceLabsResult = false def setupSpec() { // Initialize the Appium driver @@ -27,12 +27,19 @@ class DemoMobileGebHomePageSpec extends GebReportingSpec { driver.quit() } def setup() { - // Set the job result to false - result = false + // Initialize the Sauce Labs result to false + sauceLabsResult = false } def cleanup() { - // Set the job result in Sauce Labs - driver.executeScript("sauce:job-result=$result") + // Set the job result in + driver.executeScript("sauce:job-result=$sauceLabsResult") + } + + // This function sets the Sauce Labs result to true, indicating that the test passed successfully. + // We use this variable to inform Sauce Labs about the test results, storing whether there were any failures. + // By setting it to true at the end of each test, we ensure that Sauce Labs is updated with the correct test status. + def setTrueResultForSauceLabs() { + (sauceLabsResult = true) != null } // Add this @Tag to include this test in the 'test_mobile_browser' group. @@ -56,8 +63,8 @@ class DemoMobileGebHomePageSpec extends GebReportingSpec { then: "The page title should be 'The Book Of Geb'" // Verify the page title assert title == "The Book Of Geb" - // Set the job result to true if the assertion passes - (result = true) != null + // Set the Sauce Labs result to true, indicating that the test passed successfully + setTrueResultForSauceLabs() } }