├── .gitignore ├── Jenkinsfile ├── LICENSE ├── README.md ├── build.gradle ├── chromedriver.exe ├── geckodriver.exe ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── operadriver.exe ├── serenity.properties ├── settings.gradle └── src ├── main └── java │ └── co │ └── com │ └── yourcompany │ └── certification │ └── nameproject │ ├── exceptions │ ├── RepositoryAlreadyExistsError.java │ ├── RepositoryModelCreationException.java │ ├── StartError.java │ └── UserModelCreationException.java │ ├── interactions │ ├── EnterAndHide.java │ ├── EnterAndHideIntoTarget.java │ └── SelectDropDownButton.java │ ├── model │ ├── Repository.java │ ├── User.java │ ├── builders │ │ ├── RepositoryBuilder.java │ │ └── UserBuilder.java │ └── enumerables │ │ ├── GitIgnore.java │ │ └── License.java │ ├── questions │ ├── TheCurrent.java │ └── TheRepository.java │ ├── tasks │ ├── CreateRepository.java │ └── Start.java │ ├── userinterface │ ├── CreateNewRepositoryPage.java │ ├── GitHubLoginPage.java │ ├── RepositoryPage.java │ └── UserGitHubHomePage.java │ └── util │ ├── builder │ └── Builder.java │ └── validations │ └── Validations.java └── test ├── java └── co │ └── com │ └── yourcompany │ └── certification │ └── nameproject │ ├── runners │ └── GitHubTestRunner.java │ └── stepdefinitions │ └── CreateRepositoryInGitHubStepDefinition.java └── resources └── features └── create_repository.feature /.gitignore: -------------------------------------------------------------------------------- 1 | #JAVA 2 | # Compiled class file 3 | *.class 4 | 5 | # Log file 6 | *.log 7 | 8 | # Package Files # 9 | *.jar 10 | *.war 11 | *.ear 12 | *.zip 13 | *.tar.gz 14 | *.rar 15 | 16 | #INTELLIJ IDEA 17 | # User-specific stuff: 18 | .idea/ 19 | *.iml 20 | out/ 21 | 22 | #Serenity 23 | target/ 24 | build/ 25 | 26 | #gradle 27 | .gradle/ 28 | 29 | # Ignore Gradle GUI config 30 | gradle-app.setting 31 | 32 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 33 | !gradle-wrapper.jar 34 | 35 | # Cache of project 36 | .gradletasknamecache 37 | 38 | #Sonar 39 | sonar-project.properties -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | triggers { cron('H */4 * * 1-5') } 4 | parameters { 5 | string(name: 'USER', defaultValue: 'tu usuario', description: 'Usuario de GitHub') 6 | } 7 | stages { 8 | stage('build') { 9 | steps { 10 | bat 'gradlew.bat clean build -x test' 11 | } 12 | } 13 | stage('test-firefox') { 14 | steps { 15 | withCredentials([string(credentialsId: 'password-github', variable: 'password')]) { 16 | bat "gradlew.bat test -Dgithub-user=${params.USER} -Dpassword=${password} -Dcontext=firefox -Dwebdriver.driver=firefox" 17 | } 18 | } 19 | } 20 | stage('aggregate') { 21 | steps { 22 | bat 'gradlew.bat aggregate' 23 | } 24 | } 25 | stage('publish report'){ 26 | steps { 27 | publishHTML([ 28 | allowMissing: false, 29 | alwaysLinkToLastBuild: true, 30 | keepAll: true, 31 | reportDir: 'target/site/serenity', 32 | reportFiles: 'index.html', 33 | reportName: 'Serenity-BDD', 34 | reportTitles: '' 35 | ]) 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 César Daniel Meneses Guevara 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # base_project_for_web_automation_projects 2 | 3 | # [Español] 4 | Proyecto base con ejemplo para proyectos de automatización web con serenidad BDD, screenplay y cucumber. 5 | 6 | ## Detalles generales de la implementación 7 | 8 | Los tests usan tareas (tasks), interacciones (interactions), preguntas (questions), elementos de páginas (userinterface). 9 | La estructura completa del proyecto es la siguiente: 10 | 11 | ```` 12 | + exceptions 13 | Clases que controlan las posibles excepciones técnicas y de negocios que se presentan durante la ejecución de pruebas 14 | + model 15 | Clases relacionadas con el modelo de dominio y sus respectivos builder cuando es necesario 16 | + tasks 17 | Clases que representan tareas que realiza el actor a nivel de proceso de negocio 18 | + interactions 19 | Clases que representan las interacciones directas con la interfaz de usuario 20 | + userinterface 21 | Page Objects y Page Elements. Mapean los objetos de la interfaz de usuario 22 | + questions 23 | Objetos usados para consultar acerca del estado de la aplicación 24 | + util 25 | Clases de utilidad 26 | + runners 27 | Clases que permiten correr los tests 28 | + step definitions 29 | Clases que mapean las líneas Gherkin a código java 30 | + features 31 | La representación de las historias en archivos cucumber 32 | ```` 33 | 34 | ## Requerimientos 35 | 36 | Para correr el proyecto se necesita Java JDK 1.8 y Gradle preferiblemente con la versión 7.1. 37 | 38 | ## Para correr el proyecto 39 | 40 | En caso de querer ejecutar el proyecto en un solo navegador se debe en el archivo serenity.properties descomentar la línea 41 | 42 | #webdriver.driver= chrome 43 | 44 | eliminando el caracter #, en el ejemplo se tiene por defecto chrome. seguidamente se puede ejecutar el comando: 45 | 46 | gradle clean test -Dgithub-user=tuUsuarioGitHub -Dpassword=TuContraseña aggregate 47 | 48 | Para ejecutar este proyecto en diferentes navegadores se debe seguir el siguiente orden de ejecución: 49 | 50 | gradle clean 51 | gradle test -Dgithub-user=tuUsuarioGitHub -Dpassword=TuContraseña -Dcontext=navegador -Dwebdriver.driver=driverAUtilizar // Se repite dependiendo a la cantidad de driver quieras utilziar 52 | gradle aggregate 53 | 54 | Independiente de si es en un solo navegador o varios, se generará el reporte en la carpeta /target/site/serenity/ 55 | 56 | Ejemplo: 57 | 58 | gradle clean 59 | gradle test -Dgithub-user=cedaniel200 -Dpassword=123456 -Dcontext=chrome -Dwebdriver.driver=chrome 60 | gradle test -Dgithub-user=cedaniel200 -Dpassword=123456 -Dcontext=firefox -Dwebdriver.driver=firefox 61 | gradle test -Dgithub-user=cedaniel200 -Dpassword=123456 -Dbinary="C:\Users\miusuario\AppData\Local\Programs\Opera\60.0.3255.83\opera.exe" -Dcontext=opera -Dwebdriver.driver=opera 62 | gradle aggregate 63 | 64 | En el caso del navegador Opera, se debe añadir un nuevo parámetro que especifica la ruta dónde está el ejecutable del navegador. 65 | 66 | ## Jenkins file 67 | 68 | Para utilizar el jenkinsfile necesitas crear una credencial con id password-github, ejecutar con parametro, donde se solicita el 69 | usuario de github. Ésta configuracion solo ejecuta la prueba en el navegador firefox. 70 | 71 | ## Pipeline Azure DevOps 72 | 73 | ir a http://bit.ly/2Pxeuqy luego ingresar en Pipelines -> Releases -> DevFest -> Release-4 74 | 75 | # Advertencia 76 | El ejemplo utiliza usuarios de GitHub, si el usuario que usa es nuevo, puede fallar, ya que GitHub lo envía a una página diferente a la que se usó en el ejercicio. 77 | 78 | ### Si tiene alguna pregunta, puede escribirme a cdanielmg200@gmail.com 79 | 80 | 81 | # [English] 82 | 83 | base project with example for web automation projects with serenity BDD, screenplay and cucumber 84 | 85 | ## General details of the implementation 86 | 87 | The tests use tasks, interactions, questions, elements of pages (userinterface). 88 | The complete structure of the project is the following: 89 | 90 | ```` 91 | + exceptions 92 |      Classes that control the possible technical and business exceptions that arise during the execution of tests 93 | + model 94 |      Classes related to the domain model and their respective builders when necessary 95 | + tasks 96 |      Classes that represent tasks performed by the actor at the business process level 97 | + interactions 98 |      Classes that represent direct interactions with the user interface 99 | + userinterface 100 |      Page Objects and Page Elements. Map the objects of the user interface 101 | + questions 102 |      Objects used to check the status of the application 103 | + util 104 |      Utility classes 105 | + runners 106 |      Classes that allow to run the tests 107 | + step definitions 108 |      Classes that map the Gherkin lines to java code 109 | + features 110 |      The representation of the stories in cucumber archives 111 | ```` 112 | ## Requirements 113 | 114 | To run the project you need Java JDK 1.8 and Gradle preferably with version 7.1. 115 | 116 | ## To run the project 117 | 118 | In case you want to run the project in a single browser, you must in the file serenity.properties uncomment the line 119 | 120 | #webdriver.driver= chrome 121 | 122 | eliminating the character #, in the example you have default chrome. Then the command can be executed: 123 | 124 | gradle clean test -Dgithub-user=tuUsuarioGitHub -Dpassword=TuContraseña aggregate 125 | 126 | To execute this project in different browsers the following order of execution must be followed: 127 | 128 | gradle clean 129 | gradle test -Dgithub-user=tuUsuarioGitHub -Dpassword=TuContraseña -Dcontext=navegador -Dwebdriver.driver=driverAUtilizar // Repeats depending on the amount of driver you want to use 130 | gradle aggregate 131 | 132 | Regardless of whether it is in a single browser or several, the report will be generated in the folder /target/site/serenity/ 133 | 134 | Example: 135 | 136 | gradle clean 137 | gradle test -Dgithub-user=cedaniel200 -Dpassword=123456 -Dcontext=chrome -Dwebdriver.driver=chrome 138 | gradle test -Dgithub-user=cedaniel200 -Dpassword=123456 -Dcontext=firefox -Dwebdriver.driver=firefox 139 | gradle test -Dgithub-user=cedaniel200 -Dpassword=123456 -Dbinary="C:\Users\miusuario\AppData\Local\Programs\Opera\60.0.3255.83\opera.exe" -Dcontext=opera -Dwebdriver.driver=opera 140 | gradle aggregate 141 | 142 | In the case of the Opera browser, a new parameter must be added specifying the path where the browser executable is. 143 | 144 | ## Jenkins file 145 |   146 | To use the jenkinsfile you need to create a credential with id password-github, Run with parameter, where the github user is requested. This configuration only runs the test in the firefox browser. 147 | 148 | ## Pipeline Azure DevOps 149 | 150 | go to http://bit.ly/2Pxeuqy after that, click in Pipelines -> Releases -> DevFest -> Release-4 151 | 152 | # Warning 153 | The example uses GitHub users, if the user used is new it may fail, since GitHub sends it to a different page than the one used in the exercise. 154 | 155 | ## If you have any questions you can write me at cdanielmg200@gmail.com 156 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | mavenCentral() 4 | mavenLocal() 5 | } 6 | ext{ 7 | serenityVersion = '3.2.5' 8 | serenityGradlePluginVersion = '2.4.34' 9 | serenityCucumberVersion = '3.2.5' 10 | 11 | junitVersion = '4.13.2' 12 | slf4jVersion = '1.7.36' 13 | assertjVersion = '3.23.1' 14 | } 15 | dependencies { 16 | classpath("net.serenity-bdd:serenity-gradle-plugin:$rootProject.ext.serenityGradlePluginVersion") 17 | } 18 | } 19 | 20 | group 'co.com.yourcompany.certification' 21 | version '1.0-SNAPSHOT' 22 | 23 | apply plugin: 'java' 24 | apply plugin: 'idea' 25 | apply plugin: 'net.serenity-bdd.aggregator' 26 | 27 | sourceCompatibility = 1.8 28 | 29 | repositories { 30 | mavenCentral() 31 | mavenLocal() 32 | } 33 | 34 | dependencies { 35 | testImplementation "net.serenity-bdd:serenity-core:$rootProject.ext.serenityVersion" 36 | testImplementation "net.serenity-bdd:serenity-junit:$rootProject.ext.serenityVersion" 37 | implementation "net.serenity-bdd:serenity-screenplay:$rootProject.ext.serenityVersion" 38 | implementation "net.serenity-bdd:serenity-screenplay-webdriver:$rootProject.ext.serenityVersion" 39 | implementation "net.serenity-bdd:serenity-cucumber:$rootProject.ext.serenityCucumberVersion" 40 | 41 | testImplementation "junit:junit:$rootProject.ext.junitVersion" 42 | testImplementation "org.assertj:assertj-core:$rootProject.ext.assertjVersion" 43 | 44 | testImplementation "org.slf4j:slf4j-simple:$rootProject.ext.slf4jVersion" 45 | } 46 | 47 | tasks.withType(Test){ 48 | systemProperties = System.properties as Map 49 | maxParallelForks = Runtime.runtime.availableProcessors() 50 | } 51 | 52 | gradle.startParameter.continueOnFailure = true -------------------------------------------------------------------------------- /chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedaniel200/base_project_for_web_automation_projects/c19ee751a15ad7f7f8c1e717830fd09452869521/chromedriver.exe -------------------------------------------------------------------------------- /geckodriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedaniel200/base_project_for_web_automation_projects/c19ee751a15ad7f7f8c1e717830fd09452869521/geckodriver.exe -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedaniel200/base_project_for_web_automation_projects/c19ee751a15ad7f7f8c1e717830fd09452869521/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /operadriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cedaniel200/base_project_for_web_automation_projects/c19ee751a15ad7f7f8c1e717830fd09452869521/operadriver.exe -------------------------------------------------------------------------------- /serenity.properties: -------------------------------------------------------------------------------- 1 | #webdriver.driver= chrome 2 | chrome.switches=--start-maximized -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'github' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/exceptions/RepositoryAlreadyExistsError.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.exceptions; 2 | 3 | public class RepositoryAlreadyExistsError extends AssertionError { 4 | 5 | private static final String MESSAGE_FORMAT_REPOSITORY_ALREADY_EXISTS = "The repository named %s already exists"; 6 | 7 | public RepositoryAlreadyExistsError(String message, Throwable cause) { 8 | super(message, cause); 9 | } 10 | 11 | public static String withMessageBy(String repositoryName) { 12 | return String.format(MESSAGE_FORMAT_REPOSITORY_ALREADY_EXISTS, repositoryName); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/exceptions/RepositoryModelCreationException.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.exceptions; 2 | 3 | public class RepositoryModelCreationException extends IllegalStateException { 4 | 5 | public RepositoryModelCreationException(String message){ 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/exceptions/StartError.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.exceptions; 2 | 3 | public class StartError extends AssertionError { 4 | 5 | public static final String MESSAGE_LOGIN_PAGE_NOT_LOADED = "The login page could not be loaded"; 6 | public static final String MESSAGE_FAILED_AUTHENTICATION = "Authentication failed"; 7 | 8 | public StartError(String message, Throwable cause) { 9 | super(message, cause); 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/exceptions/UserModelCreationException.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.exceptions; 2 | 3 | public class UserModelCreationException extends IllegalStateException { 4 | 5 | public UserModelCreationException(String message) { 6 | super(message); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/interactions/EnterAndHide.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.interactions; 2 | 3 | import net.serenitybdd.screenplay.actions.EnterValue; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | 6 | import static net.serenitybdd.screenplay.Tasks.instrumented; 7 | 8 | public class EnterAndHide { 9 | 10 | private final String theText; 11 | private String mask; 12 | 13 | private EnterAndHide(String text) { 14 | this.theText = text; 15 | this.mask = "any text"; 16 | } 17 | 18 | public static EnterAndHide theValue(String text) { 19 | return new EnterAndHide(text); 20 | } 21 | 22 | public EnterAndHide as(String mask) { 23 | this.mask = mask; 24 | return this; 25 | } 26 | 27 | public EnterValue into(String cssOrXpathForElement) { 28 | return instrumented(EnterAndHideIntoTarget.class, theText, mask, Target.the(cssOrXpathForElement).locatedBy(cssOrXpathForElement)); 29 | } 30 | 31 | public EnterValue into(Target target) { 32 | return instrumented(EnterAndHideIntoTarget.class, theText, mask, target); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/interactions/EnterAndHideIntoTarget.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.interactions; 2 | 3 | import net.serenitybdd.screenplay.Actor; 4 | import net.serenitybdd.screenplay.actions.EnterValue; 5 | import net.serenitybdd.screenplay.targets.Target; 6 | import net.thucydides.core.annotations.Step; 7 | 8 | public class EnterAndHideIntoTarget extends EnterValue { 9 | 10 | private Target target; 11 | private String mask; 12 | 13 | public EnterAndHideIntoTarget(String theText, String mask, Target target) { 14 | super(theText); 15 | this.target = target; 16 | this.mask = mask; 17 | } 18 | 19 | @Step("{0} enters #mask into #target") 20 | public void performAs(T theUser) { 21 | target.resolveFor(theUser).type(theText); 22 | if (getFollowedByKeys().length > 0) { 23 | target.resolveFor(theUser).sendKeys(getFollowedByKeys()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/interactions/SelectDropDownButton.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.interactions; 2 | 3 | import co.com.yourcompany.certification.nameproject.model.enumerables.GitIgnore; 4 | import co.com.yourcompany.certification.nameproject.model.enumerables.License; 5 | import net.serenitybdd.screenplay.Actor; 6 | import net.serenitybdd.screenplay.Interaction; 7 | import net.serenitybdd.screenplay.targets.Target; 8 | import net.thucydides.core.annotations.Step; 9 | import org.openqa.selenium.WebElement; 10 | 11 | import java.util.concurrent.Callable; 12 | 13 | import static co.com.yourcompany.certification.nameproject.userinterface.CreateNewRepositoryPage.*; 14 | import static java.util.concurrent.TimeUnit.SECONDS; 15 | import static net.serenitybdd.screenplay.Tasks.instrumented; 16 | import static org.awaitility.Awaitility.await; 17 | 18 | public class SelectDropDownButton implements Interaction { 19 | 20 | private final Target button; 21 | private final Target filter; 22 | private final String valueFilter; 23 | private final String cssSelectorForElementSelected; 24 | 25 | public SelectDropDownButton(Target button, Target filter, String valueFilter, String selectorForElementSelected) { 26 | this.valueFilter = valueFilter; 27 | this.button = button; 28 | this.filter = filter; 29 | this.cssSelectorForElementSelected = selectorForElementSelected; 30 | } 31 | 32 | public static SelectDropDownButton addGitIgnoreFilteringBy(GitIgnore valueFilter) { 33 | return instrumented(SelectDropDownButton.class, ADD_GITIGNORE, 34 | FILTER_GITIGNORE, valueFilter.toString(), 35 | String.format(SELECTOR_FORMAT_GITIGNORE, valueFilter)); 36 | } 37 | 38 | public static SelectDropDownButton addLicenseFilteringBy(License valueFilter) { 39 | return instrumented(SelectDropDownButton.class, ADD_LICENSE, 40 | FILTER_LICENSE, valueFilter.toString(), 41 | String.format(SELECTOR_FORMAT_LICENSE, valueFilter)); 42 | } 43 | 44 | @Override 45 | @Step("{0} clicks on #button is filtered by #valueFilter and click on the resulting item") 46 | public void performAs(T actor) { 47 | button.resolveFor(actor).click(); 48 | filter.resolveFor(actor).sendKeys(valueFilter); 49 | Target selectedItem = Target.the("selected item").locatedBy(cssSelectorForElementSelected); 50 | await().forever().pollInterval(1, SECONDS).until(isNotNull(selectedItem.resolveFor(actor))); 51 | selectedItem.resolveFor(actor).click(); 52 | } 53 | 54 | private Callable isNotNull(WebElement element) { 55 | return () -> element != null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/model/Repository.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.model; 2 | 3 | import co.com.yourcompany.certification.nameproject.exceptions.RepositoryModelCreationException; 4 | import co.com.yourcompany.certification.nameproject.model.builders.RepositoryBuilder; 5 | import co.com.yourcompany.certification.nameproject.model.enumerables.GitIgnore; 6 | import co.com.yourcompany.certification.nameproject.model.enumerables.License; 7 | 8 | import static co.com.yourcompany.certification.nameproject.util.validations.Validations.isEmptyOrNull; 9 | 10 | public class Repository { 11 | 12 | private final String name; 13 | private final String description; 14 | private final boolean initializeWithREADME; 15 | private final GitIgnore gitIgnore; 16 | private final License license; 17 | 18 | public Repository(RepositoryBuilder builder) throws RepositoryModelCreationException { 19 | name = builder.getName(); 20 | description = builder.getDescription(); 21 | initializeWithREADME = builder.isInitializeWithREADME(); 22 | gitIgnore = builder.getGitIgnore(); 23 | license = builder.getLicense(); 24 | isValid(); 25 | } 26 | 27 | private void isValid() throws RepositoryModelCreationException { 28 | if (isEmptyOrNull(this.name)) { 29 | throw new RepositoryModelCreationException("The repository does not contain a name"); 30 | } 31 | } 32 | 33 | public String name() { 34 | return name; 35 | } 36 | 37 | public String description() { 38 | return description; 39 | } 40 | 41 | public boolean isInitializeWithREADME() { 42 | return initializeWithREADME; 43 | } 44 | 45 | public GitIgnore gitIgnore() { 46 | return gitIgnore; 47 | } 48 | 49 | public License license() { 50 | return license; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/model/User.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.model; 2 | 3 | import co.com.yourcompany.certification.nameproject.exceptions.UserModelCreationException; 4 | import co.com.yourcompany.certification.nameproject.model.builders.UserBuilder; 5 | 6 | import static co.com.yourcompany.certification.nameproject.util.validations.Validations.isEmptyOrNull; 7 | 8 | public class User { 9 | 10 | private final String username; 11 | private final String password; 12 | 13 | public User(UserBuilder builder) { 14 | this.username = builder.getUsername(); 15 | this.password = builder.getPassword(); 16 | isValid(); 17 | } 18 | 19 | private void isValid(){ 20 | if(isEmptyOrNull(username) || isEmptyOrNull(password)){ 21 | throw new UserModelCreationException( 22 | String.format("Invalid username (%s) or password (%s)", username, password)); 23 | } 24 | } 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public String getPassword() { 31 | return password; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/model/builders/RepositoryBuilder.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.model.builders; 2 | 3 | import co.com.yourcompany.certification.nameproject.exceptions.RepositoryModelCreationException; 4 | import co.com.yourcompany.certification.nameproject.model.Repository; 5 | import co.com.yourcompany.certification.nameproject.model.enumerables.GitIgnore; 6 | import co.com.yourcompany.certification.nameproject.model.enumerables.License; 7 | import co.com.yourcompany.certification.nameproject.util.builder.Builder; 8 | 9 | public class RepositoryBuilder implements Builder { 10 | 11 | private String name; 12 | private String description; 13 | private boolean initializeWithREADME; 14 | private GitIgnore gitIgnore; 15 | private License license; 16 | 17 | private RepositoryBuilder(String name) { 18 | this.name = name; 19 | this.initializeWithREADME = false; 20 | this.description = ""; 21 | this.gitIgnore = GitIgnore.NONE; 22 | this.license = License.NONE; 23 | } 24 | 25 | public static RepositoryBuilder name(String name){ 26 | return new RepositoryBuilder(name); 27 | } 28 | 29 | public RepositoryBuilder description(String description){ 30 | this.description = description; 31 | return this; 32 | } 33 | 34 | public RepositoryBuilder initializeWithREADME(){ 35 | this.initializeWithREADME = true; 36 | return this; 37 | } 38 | 39 | public RepositoryBuilder gitIgnore(GitIgnore gitIgnore){ 40 | this.gitIgnore = gitIgnore; 41 | return this; 42 | } 43 | 44 | public RepositoryBuilder license(License license){ 45 | this.license = license; 46 | return this; 47 | } 48 | 49 | public String getName() { 50 | return name; 51 | } 52 | 53 | public String getDescription() { 54 | return description; 55 | } 56 | 57 | public boolean isInitializeWithREADME() { 58 | return initializeWithREADME; 59 | } 60 | 61 | public GitIgnore getGitIgnore() { 62 | return gitIgnore; 63 | } 64 | 65 | public License getLicense() { 66 | return license; 67 | } 68 | 69 | @Override 70 | public Repository build() throws RepositoryModelCreationException { 71 | return new Repository(this); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/model/builders/UserBuilder.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.model.builders; 2 | 3 | import co.com.yourcompany.certification.nameproject.exceptions.UserModelCreationException; 4 | import co.com.yourcompany.certification.nameproject.model.User; 5 | import co.com.yourcompany.certification.nameproject.util.builder.Builder; 6 | 7 | public class UserBuilder implements Builder { 8 | 9 | private String username; 10 | private String password; 11 | 12 | private UserBuilder(String username) { 13 | this.username = username; 14 | } 15 | 16 | public User withPassword(String password) throws UserModelCreationException { 17 | this.password = password; 18 | return this.build(); 19 | } 20 | 21 | public String getUsername() { 22 | return username; 23 | } 24 | 25 | public String getPassword() { 26 | return password; 27 | } 28 | 29 | @Override 30 | public User build() throws UserModelCreationException { 31 | return new User(this); 32 | } 33 | 34 | public static UserBuilder theUser(String username){ 35 | return new UserBuilder(username); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/model/enumerables/GitIgnore.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.model.enumerables; 2 | 3 | public enum GitIgnore { 4 | 5 | NONE("None"), 6 | JAVA("Java"), 7 | ANDROID("Android"), 8 | C("C"), 9 | C_PLUS_PLUS("C++"); 10 | 11 | private final String nameGitIgnore; 12 | 13 | GitIgnore(final String nameGitIgnore) { 14 | this.nameGitIgnore = nameGitIgnore; 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return nameGitIgnore; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/model/enumerables/License.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.model.enumerables; 2 | 3 | public enum License { 4 | 5 | NONE("None"), 6 | APACHE_2("Apache license 2.0"), 7 | MIT("MIT License"), 8 | MOZILLA("Mozilla Public License 2.0"); 9 | 10 | private final String licenseName; 11 | 12 | License(final String licenseName) { 13 | this.licenseName = licenseName; 14 | } 15 | 16 | @Override 17 | public String toString() { 18 | return licenseName; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/questions/TheCurrent.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.questions; 2 | 3 | import net.serenitybdd.screenplay.Actor; 4 | import net.serenitybdd.screenplay.Question; 5 | import net.serenitybdd.screenplay.annotations.Subject; 6 | import net.thucydides.core.webdriver.SerenityWebdriverManager; 7 | 8 | @Subject("the current URL") 9 | public class TheCurrent implements Question { 10 | 11 | @Override 12 | public String answeredBy(Actor actor) { 13 | return SerenityWebdriverManager.inThisTestThread().getCurrentDriver().getCurrentUrl(); 14 | } 15 | 16 | public static Question url() { 17 | return new TheCurrent(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/questions/TheRepository.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.questions; 2 | 3 | import co.com.yourcompany.certification.nameproject.userinterface.RepositoryPage; 4 | import net.serenitybdd.screenplay.Actor; 5 | import net.serenitybdd.screenplay.Question; 6 | import net.serenitybdd.screenplay.annotations.Subject; 7 | 8 | @Subject("the name of the repository") 9 | public class TheRepository implements Question { 10 | 11 | @Override 12 | public String answeredBy(Actor actor) { 13 | return RepositoryPage.REPOSITORY_NAME.resolveFor(actor).getText(); 14 | } 15 | 16 | public static TheRepository name() { 17 | return new TheRepository(); 18 | } 19 | } -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/tasks/CreateRepository.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.tasks; 2 | 3 | import co.com.yourcompany.certification.nameproject.exceptions.RepositoryAlreadyExistsError; 4 | import co.com.yourcompany.certification.nameproject.exceptions.RepositoryModelCreationException; 5 | import co.com.yourcompany.certification.nameproject.interactions.SelectDropDownButton; 6 | import co.com.yourcompany.certification.nameproject.model.Repository; 7 | import co.com.yourcompany.certification.nameproject.model.enumerables.License; 8 | import co.com.yourcompany.certification.nameproject.util.builder.Builder; 9 | import net.serenitybdd.screenplay.Actor; 10 | import net.serenitybdd.screenplay.Task; 11 | import net.serenitybdd.screenplay.actions.Click; 12 | import net.serenitybdd.screenplay.actions.Enter; 13 | import net.serenitybdd.screenplay.actions.Scroll; 14 | import net.serenitybdd.screenplay.conditions.Check; 15 | 16 | import static co.com.yourcompany.certification.nameproject.exceptions.RepositoryAlreadyExistsError.withMessageBy; 17 | import static co.com.yourcompany.certification.nameproject.model.enumerables.GitIgnore.NONE; 18 | import static co.com.yourcompany.certification.nameproject.userinterface.CreateNewRepositoryPage.*; 19 | import static co.com.yourcompany.certification.nameproject.userinterface.UserGitHubHomePage.NEW_REPOSITORY; 20 | import static co.com.yourcompany.certification.nameproject.util.validations.Validations.isNotEmptyOrNull; 21 | import static net.serenitybdd.screenplay.GivenWhenThen.seeThat; 22 | import static net.serenitybdd.screenplay.Tasks.instrumented; 23 | import static net.serenitybdd.screenplay.matchers.WebElementStateMatchers.isNotVisible; 24 | import static net.serenitybdd.screenplay.questions.WebElementQuestion.the; 25 | 26 | public class CreateRepository implements Task { 27 | 28 | private final Repository repository; 29 | 30 | public CreateRepository(Repository repository) { 31 | this.repository = repository; 32 | } 33 | 34 | @Override 35 | public void performAs(T actor) { 36 | actor.attemptsTo( 37 | Click.on(NEW_REPOSITORY), 38 | Enter.theValue(repository.name()).into(REPOSITORY_NAME) 39 | ); 40 | 41 | actor.should(seeThat(the(MESSAGE_REPOSITORY_ALREADY_EXISTS), isNotVisible()) 42 | .orComplainWith(RepositoryAlreadyExistsError.class, 43 | withMessageBy(repository.name()))); 44 | 45 | actor.attemptsTo( 46 | Check.whether(isNotEmptyOrNull(repository.description())) 47 | .andIfSo(Enter.theValue(repository.description()).into(REPOSITORY_DESCRIPTION)), 48 | Check.whether(repository.isInitializeWithREADME()) 49 | .andIfSo(Click.on(INITIALIZE_THIS_REPOSITORY_WITH_README)), 50 | Scroll.to(CREATE_REPOSITORY), 51 | Check.whether(repository.gitIgnore() != NONE) 52 | .andIfSo(SelectDropDownButton.addGitIgnoreFilteringBy(repository.gitIgnore())), 53 | Check.whether(repository.license() != License.NONE) 54 | .andIfSo(SelectDropDownButton.addLicenseFilteringBy(repository.license())), 55 | Click.on(CREATE_REPOSITORY) 56 | ); 57 | } 58 | 59 | public static CreateRepository withTheFollowingData(Builder builder) throws RepositoryModelCreationException { 60 | return instrumented(CreateRepository.class, builder.build()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/tasks/Start.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.tasks; 2 | 3 | import co.com.yourcompany.certification.nameproject.exceptions.StartError; 4 | import co.com.yourcompany.certification.nameproject.exceptions.UserModelCreationException; 5 | import co.com.yourcompany.certification.nameproject.interactions.EnterAndHide; 6 | import co.com.yourcompany.certification.nameproject.model.User; 7 | import co.com.yourcompany.certification.nameproject.userinterface.GitHubLoginPage; 8 | import net.serenitybdd.screenplay.Actor; 9 | import net.serenitybdd.screenplay.Task; 10 | import net.serenitybdd.screenplay.actions.Click; 11 | import net.serenitybdd.screenplay.actions.Enter; 12 | import net.serenitybdd.screenplay.actions.Open; 13 | import net.thucydides.core.annotations.Step; 14 | 15 | import static co.com.yourcompany.certification.nameproject.exceptions.StartError.MESSAGE_FAILED_AUTHENTICATION; 16 | import static co.com.yourcompany.certification.nameproject.exceptions.StartError.MESSAGE_LOGIN_PAGE_NOT_LOADED; 17 | import static co.com.yourcompany.certification.nameproject.model.builders.UserBuilder.theUser; 18 | import static co.com.yourcompany.certification.nameproject.userinterface.UserGitHubHomePage.DASHBOARD; 19 | import static co.com.yourcompany.certification.nameproject.userinterface.GitHubLoginPage.*; 20 | import static net.serenitybdd.screenplay.GivenWhenThen.seeThat; 21 | import static net.serenitybdd.screenplay.Tasks.instrumented; 22 | import static net.serenitybdd.screenplay.matchers.WebElementStateMatchers.isVisible; 23 | import static net.serenitybdd.screenplay.questions.WebElementQuestion.the; 24 | 25 | public class Start implements Task { 26 | 27 | private static final String USERNAME = "DEFAULT_USERNAME"; 28 | private static final String USER_PASSWORD = "DEFAULT_PASSWORD"; 29 | private final User user; 30 | private GitHubLoginPage gitHubLoginPage; 31 | 32 | public Start(User user) { 33 | this.user = user; 34 | } 35 | 36 | @Override 37 | @Step("{0} performs an authentication") 38 | public void performAs(T theActor) { 39 | theActor.attemptsTo(Open.browserOn(gitHubLoginPage)); 40 | 41 | theActor.should(seeThat(the(USERNAME_OR_EMAIL_ADDRESS), isVisible()) 42 | .orComplainWith(StartError.class, 43 | MESSAGE_LOGIN_PAGE_NOT_LOADED)); 44 | 45 | theActor.attemptsTo( 46 | Enter.theValue(user.getUsername()).into(USERNAME_OR_EMAIL_ADDRESS), 47 | EnterAndHide.theValue(user.getPassword()).as("a password").into(PASSWORD), 48 | Click.on(SIGN_IN)); 49 | 50 | theActor.should(seeThat(the(DASHBOARD), isVisible()) 51 | .orComplainWith(StartError.class, 52 | MESSAGE_FAILED_AUTHENTICATION)); 53 | } 54 | 55 | public static Start authenticating(User user) { 56 | return instrumented(Start.class, user); 57 | } 58 | 59 | public static Start withAnAuthenticatedDefaultUser() throws UserModelCreationException { 60 | return instrumented(Start.class, theUser(USERNAME).withPassword(USER_PASSWORD)); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/userinterface/CreateNewRepositoryPage.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.userinterface; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | import org.openqa.selenium.By; 5 | 6 | public class CreateNewRepositoryPage { 7 | 8 | public static final Target REPOSITORY_NAME = Target.the("repository name field") 9 | .located(By.id("repository_name")); 10 | 11 | public static final Target REPOSITORY_DESCRIPTION = Target.the("repository description field") 12 | .located(By.id("repository_description")); 13 | 14 | public static final Target INITIALIZE_THIS_REPOSITORY_WITH_README = Target 15 | .the("Initialize this repository with a README") 16 | .located(By.id("repository_auto_init")); 17 | 18 | 19 | public static final Target ADD_GITIGNORE = Target 20 | .the("Add .gitignore") 21 | .locatedBy("//*[contains(text(),'.gitignore template:')]"); 22 | 23 | public static final Target FILTER_GITIGNORE = Target 24 | .the("filter of the gitignore") 25 | .locatedBy("//input[@aria-label = '.gitignore template']"); 26 | 27 | public static final String SELECTOR_FORMAT_GITIGNORE = "//div[contains(text(), '%s')]//ancestor::label"; 28 | 29 | 30 | public static final Target ADD_LICENSE = Target 31 | .the("Add a license") 32 | .locatedBy(" //*[contains(text(),'License:')]"); 33 | 34 | public static final Target FILTER_LICENSE = Target 35 | .the("filter of the license") 36 | .locatedBy("//input[@aria-label = 'License']"); 37 | 38 | public static final String SELECTOR_FORMAT_LICENSE = "//div[contains(text(), '%s')]//ancestor::label"; 39 | 40 | 41 | public static final Target CREATE_REPOSITORY = Target 42 | .the("Create repository") 43 | .locatedBy("div.js-with-permission-fields > .btn-primary"); 44 | 45 | public static final Target MESSAGE_REPOSITORY_ALREADY_EXISTS = Target 46 | .the("Error message") 47 | .locatedBy(".error > strong"); 48 | } -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/userinterface/GitHubLoginPage.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.userinterface; 2 | 3 | import net.serenitybdd.core.pages.PageObject; 4 | import net.serenitybdd.screenplay.targets.Target; 5 | import net.thucydides.core.annotations.DefaultUrl; 6 | import org.openqa.selenium.By; 7 | 8 | @DefaultUrl("https://github.com/login") 9 | public class GitHubLoginPage extends PageObject { 10 | public static final Target USERNAME_OR_EMAIL_ADDRESS = Target.the("Username or email address field") 11 | .located(By.id("login_field")); 12 | public static final Target PASSWORD = Target.the("Password field").located(By.id("password")); 13 | public static final Target SIGN_IN = Target.the("Sign in").located(By.name("commit")); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/userinterface/RepositoryPage.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.userinterface; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | 5 | public class RepositoryPage { 6 | public static final Target REPOSITORY_NAME = Target.the("repository name") 7 | .locatedBy("//*[@id=\"js-repo-pjax-container\"]//strong[@itemprop='name']/a"); 8 | } 9 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/userinterface/UserGitHubHomePage.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.userinterface; 2 | 3 | import net.serenitybdd.screenplay.targets.Target; 4 | import org.openqa.selenium.By; 5 | 6 | public class UserGitHubHomePage { 7 | public static final Target NEW_REPOSITORY = Target.the("New repository") 8 | .located(By.linkText("New")); 9 | 10 | public static final Target DASHBOARD = Target.the("Dashboard of the home page") 11 | .located(By.id("dashboard")); 12 | } -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/util/builder/Builder.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.util.builder; 2 | 3 | @FunctionalInterface 4 | public interface Builder { 5 | T build(); 6 | } 7 | -------------------------------------------------------------------------------- /src/main/java/co/com/yourcompany/certification/nameproject/util/validations/Validations.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.util.validations; 2 | 3 | public class Validations { 4 | 5 | private Validations() { 6 | } 7 | 8 | public static boolean isNotEmptyOrNull(String value) { 9 | return !isEmptyOrNull(value); 10 | } 11 | 12 | public static boolean isEmptyOrNull(String value) { 13 | return value == null || value.isEmpty(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/test/java/co/com/yourcompany/certification/nameproject/runners/GitHubTestRunner.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.runners; 2 | 3 | import io.cucumber.junit.CucumberOptions; 4 | import net.serenitybdd.cucumber.CucumberWithSerenity; 5 | import org.junit.runner.RunWith; 6 | 7 | @RunWith(CucumberWithSerenity.class) 8 | @CucumberOptions(features = "src/test/resources/features/create_repository.feature", 9 | glue = {"co.com.yourcompany.certification.nameproject.stepdefinitions"}, 10 | snippets = CucumberOptions.SnippetType.CAMELCASE) 11 | public class GitHubTestRunner { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/co/com/yourcompany/certification/nameproject/stepdefinitions/CreateRepositoryInGitHubStepDefinition.java: -------------------------------------------------------------------------------- 1 | package co.com.yourcompany.certification.nameproject.stepdefinitions; 2 | 3 | import co.com.yourcompany.certification.nameproject.questions.TheCurrent; 4 | import co.com.yourcompany.certification.nameproject.questions.TheRepository; 5 | import co.com.yourcompany.certification.nameproject.tasks.CreateRepository; 6 | import co.com.yourcompany.certification.nameproject.tasks.Start; 7 | import io.cucumber.java.Before; 8 | import io.cucumber.java.en.Given; 9 | import io.cucumber.java.en.Then; 10 | import io.cucumber.java.en.When; 11 | import net.serenitybdd.screenplay.abilities.BrowseTheWeb; 12 | import net.serenitybdd.screenplay.actors.OnStage; 13 | import net.serenitybdd.screenplay.actors.OnlineCast; 14 | import org.openqa.selenium.opera.OperaDriver; 15 | import org.openqa.selenium.opera.OperaOptions; 16 | 17 | import static co.com.yourcompany.certification.nameproject.model.builders.RepositoryBuilder.name; 18 | import static co.com.yourcompany.certification.nameproject.model.builders.UserBuilder.theUser; 19 | import static co.com.yourcompany.certification.nameproject.model.enumerables.GitIgnore.JAVA; 20 | import static co.com.yourcompany.certification.nameproject.model.enumerables.License.MIT; 21 | import static net.serenitybdd.screenplay.GivenWhenThen.seeThat; 22 | import static net.serenitybdd.screenplay.actors.OnStage.theActorCalled; 23 | import static net.serenitybdd.screenplay.actors.OnStage.theActorInTheSpotlight; 24 | import static org.hamcrest.core.Is.is; 25 | 26 | public class CreateRepositoryInGitHubStepDefinition { 27 | 28 | private static final String CESAR = "Cesar"; 29 | private static final String GITHUB_USER = System.getProperty("github-user"); 30 | private static final String SECRET = System.getProperty("password"); 31 | private static final String OPERA = "opera"; 32 | public static final String REPOSITORY_NAME = "TEST_BDD"; 33 | private static final String BASE_URL_OF_REPOSITORY_CREATED = String.format("https://github.com/%s/%s", GITHUB_USER, REPOSITORY_NAME); 34 | 35 | @Before 36 | public void setTheStage() { 37 | OnStage.setTheStage(new OnlineCast()); 38 | verifyIfDriverIsOpera(); 39 | } 40 | 41 | private void verifyIfDriverIsOpera() { 42 | if(OPERA.equals(System.getProperty("context"))){ 43 | OperaOptions operaOptions = new OperaOptions(); 44 | operaOptions.setBinary(System.getProperty("binary")); 45 | BrowseTheWeb.as(theActorCalled(CESAR)).setDriver(new OperaDriver(operaOptions)); 46 | } 47 | } 48 | 49 | @Given("^Cesar wants to start versioning$") 50 | public void startVersioning() { 51 | theActorCalled(CESAR).wasAbleTo( 52 | Start.authenticating(theUser(GITHUB_USER) 53 | .withPassword(SECRET))); 54 | } 55 | 56 | @When("^Cesar creates a repository$") 57 | public void createRepository() { 58 | theActorInTheSpotlight().attemptsTo( 59 | CreateRepository.withTheFollowingData( 60 | name(REPOSITORY_NAME) 61 | .description("repository for bdd tests") 62 | .initializeWithREADME() 63 | .gitIgnore(JAVA) 64 | .license(MIT) 65 | ) 66 | ); 67 | } 68 | 69 | @Then("^Cesar should see the repository created$") 70 | public void shouldSeeTheRepositorioCreated() { 71 | theActorInTheSpotlight().should(seeThat(TheRepository.name(), is(REPOSITORY_NAME))); 72 | theActorInTheSpotlight().should(seeThat(TheCurrent.url(), is(BASE_URL_OF_REPOSITORY_CREATED))); 73 | } 74 | 75 | } -------------------------------------------------------------------------------- /src/test/resources/features/create_repository.feature: -------------------------------------------------------------------------------- 1 | Feature: Create repository 2 | As a free user 3 | I want to create a repository 4 | So that start with the version of my source code 5 | 6 | Scenario: Creation of the repository 7 | Given Cesar wants to start versioning 8 | When Cesar creates a repository 9 | Then Cesar should see the repository created 10 | 11 | --------------------------------------------------------------------------------