From 1c4023ccc06e633233ed642eb9d1ac85e82feaf0 Mon Sep 17 00:00:00 2001 From: "marian.vaclavik@telekom.com" Date: Mon, 31 Jul 2023 10:59:39 +0200 Subject: Initial upload of E2E test project. Issue-ID: PORTALNG-35 Change-Id: I606b3f265dfdb98d7eb9cfd8ab021e2895ee5152 Signed-off-by: marian.vaclavik@telekom.com --- .gitignore | 9 + README.md | 60 +++++ build.gradle | 115 +++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 24 ++ gradlew | 169 ++++++++++++ gradlew.bat | 89 +++++++ settings.gradle | 2 + .../java/org/onap/portalng/e2e/RunUiTests.java | 58 +++++ .../org/onap/portalng/e2e/helpers/BeforeAfter.java | 31 +++ .../org/onap/portalng/e2e/helpers/CommonUtils.java | 34 +++ .../portalng/e2e/helpers/ConfigFileReader.java | 62 +++++ .../e2e/helpers/SerenitySessionVariable.java | 51 ++++ .../portalng/e2e/helpers/UiSessionVariables.java | 24 ++ .../java/org/onap/portalng/e2e/hooks/Hooks.java | 41 +++ .../portalng/e2e/hooks/SelenideConfiguration.java | 55 ++++ .../org/onap/portalng/e2e/pages/LoginPage.java | 39 +++ .../java/org/onap/portalng/e2e/pages/MainPage.java | 34 +++ .../org/onap/portalng/e2e/pages/PageWithTable.java | 31 +++ .../onap/portalng/e2e/pages/PopUpDialogPage.java | 32 +++ .../portalng/e2e/pages/UserAdministrationPage.java | 84 ++++++ .../e2e/step_definitions/common/CommonStepDef.java | 43 ++++ .../e2e/step_definitions/login/LoginStepDef.java | 65 +++++ .../e2e/step_definitions/main/MainStepDef.java | 46 ++++ .../UserAdministrationStepDef.java | 132 ++++++++++ .../portalng/e2e/steps/common/CommonSteps.java | 92 +++++++ .../onap/portalng/e2e/steps/common/TableSteps.java | 95 +++++++ .../onap/portalng/e2e/steps/login/LoginSteps.java | 61 +++++ .../onap/portalng/e2e/steps/main/MainSteps.java | 42 +++ .../UserAdministrationSteps.java | 282 +++++++++++++++++++++ .../java/org/onap/portalng/e2e/types/Button.java | 27 ++ .../java/org/onap/portalng/e2e/types/Page.java | 27 ++ .../java/org/onap/portalng/e2e/types/UserRole.java | 36 +++ src/main/resources/test-local.properties | 20 ++ src/main/resources/test-remote.properties | 20 ++ src/test/resources/cucumber.properties | 20 ++ src/test/resources/features/login.feature | 32 +++ .../resources/features/user_administration.feature | 121 +++++++++ 38 files changed, 2205 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/org/onap/portalng/e2e/RunUiTests.java create mode 100644 src/main/java/org/onap/portalng/e2e/helpers/BeforeAfter.java create mode 100644 src/main/java/org/onap/portalng/e2e/helpers/CommonUtils.java create mode 100644 src/main/java/org/onap/portalng/e2e/helpers/ConfigFileReader.java create mode 100644 src/main/java/org/onap/portalng/e2e/helpers/SerenitySessionVariable.java create mode 100644 src/main/java/org/onap/portalng/e2e/helpers/UiSessionVariables.java create mode 100644 src/main/java/org/onap/portalng/e2e/hooks/Hooks.java create mode 100644 src/main/java/org/onap/portalng/e2e/hooks/SelenideConfiguration.java create mode 100644 src/main/java/org/onap/portalng/e2e/pages/LoginPage.java create mode 100644 src/main/java/org/onap/portalng/e2e/pages/MainPage.java create mode 100644 src/main/java/org/onap/portalng/e2e/pages/PageWithTable.java create mode 100644 src/main/java/org/onap/portalng/e2e/pages/PopUpDialogPage.java create mode 100644 src/main/java/org/onap/portalng/e2e/pages/UserAdministrationPage.java create mode 100644 src/main/java/org/onap/portalng/e2e/step_definitions/common/CommonStepDef.java create mode 100644 src/main/java/org/onap/portalng/e2e/step_definitions/login/LoginStepDef.java create mode 100644 src/main/java/org/onap/portalng/e2e/step_definitions/main/MainStepDef.java create mode 100644 src/main/java/org/onap/portalng/e2e/step_definitions/user_administration/UserAdministrationStepDef.java create mode 100644 src/main/java/org/onap/portalng/e2e/steps/common/CommonSteps.java create mode 100644 src/main/java/org/onap/portalng/e2e/steps/common/TableSteps.java create mode 100644 src/main/java/org/onap/portalng/e2e/steps/login/LoginSteps.java create mode 100644 src/main/java/org/onap/portalng/e2e/steps/main/MainSteps.java create mode 100644 src/main/java/org/onap/portalng/e2e/steps/user_administration/UserAdministrationSteps.java create mode 100644 src/main/java/org/onap/portalng/e2e/types/Button.java create mode 100644 src/main/java/org/onap/portalng/e2e/types/Page.java create mode 100644 src/main/java/org/onap/portalng/e2e/types/UserRole.java create mode 100644 src/main/resources/test-local.properties create mode 100644 src/main/resources/test-remote.properties create mode 100644 src/test/resources/cucumber.properties create mode 100644 src/test/resources/features/login.feature create mode 100644 src/test/resources/features/user_administration.feature diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef9a2c1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +allure-report/ +allure-results/ +out/ +build/ +target/ +.gradle/ +.idea/ +src/main/java/de/.DS_Store +results.html diff --git a/README.md b/README.md new file mode 100644 index 0000000..e81a777 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +# portal-ng end-to-end ui tests +This project contains portal-ng edition end-to-end UI tests. + +This project is using Java, Cucumber, Selenide and Allure. + +## Run tests +If you want to test a remote instance of the Portal, change the $PORTAL_ENV variable: +`export PORTAL_ENV=test-remote.properties` + +or provide the base url in an environment variable PORTAL_BASE_URL=https://external-host.org + +`export PORTAL_BASE_URL=https://external-host.org` + +Then adjust the properties file as needed. + + +By default `test-local.properties` is used. + +### In Chrome +To run the tests with Chrome from gradle wrapper: +```shell +./gradlew cucumber +``` +or with +```shell +./gradlew clean cucumber +``` +### In headless mode +There's also a task for running in a headless mode (used in pipelines): +```shell +./gradlew cucumberCli +``` +## Local development + +If you want to run a single scenario for debugging while developing any of the tests or creating a new one, you can do so. + +First you have to specify a `@debug` tag in any of the `.feature` files adding the `@debug` tag above the line `Scenario:` +and then you can run the task to only run this scenario: + +```shell +./gradlew cucumberLocalDebug +``` + +You can also add `@debug` to more scenarios to be executed within the project and run the task above again. + +This will also work in IntelliJ Idea when you create a gradle configuration, so you can easily run tests that you are currently developing. + +Don't forget to add `PORTAL_ENV=test-local.properties` as an environment variable in your IntelliJ configuration. + +## Test Reports + +To generate allure reports on MAC +you must install allure via **brew** and then: + +```shell +allure generate --clean +``` + +the report will appear: +`./allure-report/index.html` diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..abc7675 --- /dev/null +++ b/build.gradle @@ -0,0 +1,115 @@ +plugins { + id 'java' + id 'io.qameta.allure' version '2.9.3' +} +apply plugin: 'io.qameta.allure' +group 'org.onap.portalng.e2e' +version '1.0' + +repositories { + mavenCentral() +} + +dependencies { + implementation 'io.cucumber:cucumber-junit:7.3.3' + implementation 'io.cucumber:cucumber-java:7.3.3' + implementation 'com.codeborne:selenide:6.14.0' + implementation 'io.qameta.allure:allure-cucumber7-jvm:2.20.1' + implementation 'net.serenity-bdd:serenity-cucumber:3.4.3' + implementation 'net.serenity-bdd:serenity-core:3.4.3' + implementation 'net.serenity-bdd:serenity-junit:3.4.3' + implementation 'io.qameta.allure:allure-selenide:2.20.1' + implementation 'org.assertj:assertj-core:3.22.0' + + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter:5.8.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-params:5.8.2' + testImplementation 'org.junit.vintage:junit-vintage-engine:5.8.2' +} + +configurations { + cucumberRuntime { + extendsFrom testImplementation + } +} + +allprojects { + repositories { + mavenLocal() + mavenCentral() + } + + apply plugin: 'idea' + apply plugin: 'java' + apply plugin: 'java-library' + apply plugin: 'io.qameta.allure' + + java { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + test { + useJUnitPlatform() + testLogging.showStandardStreams = true + systemProperty "cucumber.filter.tags", System.getProperty("cucumber.filter.tags") + } + gradle.startParameter.continueOnFailure = true +} + +tasks.register('cucumber') { + cleanupAllure + dependsOn assemble, testClasses + doLast { + javaexec { + systemProperties['selenide.headless'] = 'false' + main = "io.cucumber.core.cli.Main" + classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output + args = [ + '--plugin', 'pretty', + '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm', + '--glue', 'org.onap.portalng.e2e', + 'src/test/resources'] + } + } +} + +tasks.register('cucumberLocalDebug') { + cleanupAllure + dependsOn assemble, testClasses + doLast { + javaexec { + systemProperties['selenide.headless'] = 'false' + main = "io.cucumber.core.cli.Main" + classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output + args = [ + '--plugin', 'pretty', + '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm', + '--glue', 'org.onap.portalng.e2e', + '--tags', '@debug', + 'src/test/resources'] + } + } +} + +tasks.register('cucumberCli') { + cleanupAllure + dependsOn assemble, testClasses + doLast { + javaexec { + systemProperties['selenide.headless'] = 'true' + main = "io.cucumber.core.cli.Main" + classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output + args = [ + '--plugin', 'pretty', + '--plugin', 'io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm', + '--glue', 'org.onap.portalng.e2e', + 'src/test/resources'] + } + } +} + +tasks.register('cleanupAllure') { + delete "allure-results" +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..7454180 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..800614d --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,24 @@ +# +# Copyright (c) 2023. Deutsche Telekom AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +# + +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..ca8867d --- /dev/null +++ b/gradlew @@ -0,0 +1,169 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..fc9e571 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'portal-e2e-test' + diff --git a/src/main/java/org/onap/portalng/e2e/RunUiTests.java b/src/main/java/org/onap/portalng/e2e/RunUiTests.java new file mode 100644 index 0000000..159d575 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/RunUiTests.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e; + +import com.codeborne.selenide.Configuration; +import com.codeborne.selenide.logevents.SelenideLogger; +import io.cucumber.junit.CucumberOptions; +import io.qameta.allure.selenide.AllureSelenide; +import net.serenitybdd.cucumber.CucumberWithSerenity; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +@RunWith(CucumberWithSerenity.class) +@CucumberOptions( + glue = {"org.onap.portalng.e2e.step_definitions"}, + plugin = {"pretty", "io.qameta.allure.cucumber7jvm.AllureCucumber7Jvm"}, + stepNotifications = true, + monochrome = true, + features = {"src/test/resources/features"}, + snippets = CucumberOptions.SnippetType.CAMELCASE) +public class RunUiTests { + + @BeforeClass + public static void setupAllureReports() { + + SelenideLogger.addListener("AllureSelenide", new AllureSelenide() + .screenshots(true) + .savePageSource(false) + ); + Configuration.headless = true; + Configuration.browser = "chrome"; + Configuration.holdBrowserOpen = false; + Configuration.reportsFolder = "target/surefire-reports"; + } + + @AfterClass + public static void tear() { + SelenideLogger.removeListener("AllureSelenide"); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/helpers/BeforeAfter.java b/src/main/java/org/onap/portalng/e2e/helpers/BeforeAfter.java new file mode 100644 index 0000000..5649fe1 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/helpers/BeforeAfter.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.helpers; + +import io.cucumber.java.After; +import org.onap.portalng.e2e.steps.user_administration.UserAdministrationSteps; + +public class BeforeAfter { + + @After("@delete_user") + public void deleteUserAfterTest() { + UserAdministrationSteps.deleteUser(UiSessionVariables.USERNAME.get()); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/helpers/CommonUtils.java b/src/main/java/org/onap/portalng/e2e/helpers/CommonUtils.java new file mode 100644 index 0000000..a316439 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/helpers/CommonUtils.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.helpers; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.SelenideElement; + +import static com.codeborne.selenide.Condition.visible; + +public class CommonUtils { + public static void checkTextOfElement(SelenideElement element, String text) { + element.shouldHave(Condition.text(text)); + } + public static void checkPresenceOfElement(SelenideElement element) { + element.shouldBe(visible); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/helpers/ConfigFileReader.java b/src/main/java/org/onap/portalng/e2e/helpers/ConfigFileReader.java new file mode 100644 index 0000000..681b191 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/helpers/ConfigFileReader.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.helpers; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +public class ConfigFileReader { + + private final Properties properties; + private String propertyFileName= "test-local.properties"; + + + public ConfigFileReader(String fileName) { + if(fileName != null) this.propertyFileName = fileName; + BufferedReader reader; + try { + ClassLoader classLoader = this.getClass().getClassLoader(); + try{ + reader = new BufferedReader(new FileReader(classLoader.getResource(propertyFileName).getFile())); + }catch (FileNotFoundException fileNotFoundException){ + fileNotFoundException.printStackTrace(); + throw new FileNotFoundException("Configuration file not found. Check your PORTAL_ENV variable."); + } + properties = new Properties(); + try { + properties.load(reader); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException("Configuration.properties not found at " + propertyFileName + "Check your PORTAL_ENV variable."); + } + } + + public Properties getProperties() { + if (properties != null) return properties; + else throw new RuntimeException("Properties file: " + propertyFileName + " not found. Check your PORTAL_ENV variable."); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/helpers/SerenitySessionVariable.java b/src/main/java/org/onap/portalng/e2e/helpers/SerenitySessionVariable.java new file mode 100644 index 0000000..77ebef7 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/helpers/SerenitySessionVariable.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.helpers; + +import net.serenitybdd.core.Serenity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.NoSuchElementException; +import java.util.Optional; + +public interface SerenitySessionVariable { + + Logger log = LoggerFactory.getLogger(SerenitySessionVariable.class); + + String name(); + default T get() { + final Optional maybe = getOptional(); + if (!maybe.isPresent()) { + throw new NoSuchElementException("No value present for: " + name()); + } + return maybe.get(); + } + + default Optional getOptional() { + final T value = Serenity.sessionVariableCalled(this); + return Optional.ofNullable(value); + } + + default void set(T value) { + log.info("Setting {} to {}", this, value); + Serenity.setSessionVariable(this).to(value); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/helpers/UiSessionVariables.java b/src/main/java/org/onap/portalng/e2e/helpers/UiSessionVariables.java new file mode 100644 index 0000000..b7d6bf5 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/helpers/UiSessionVariables.java @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.helpers; + +public enum UiSessionVariables implements SerenitySessionVariable { + USERNAME +} diff --git a/src/main/java/org/onap/portalng/e2e/hooks/Hooks.java b/src/main/java/org/onap/portalng/e2e/hooks/Hooks.java new file mode 100644 index 0000000..76f7b75 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/hooks/Hooks.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.hooks; + +import com.codeborne.selenide.Configuration; +import com.codeborne.selenide.WebDriverRunner; +import io.cucumber.java.AfterAll; +import io.cucumber.java.Before; + +public class Hooks { + @Before + public void BeforeScenario() { + SelenideConfiguration.getBrowser(); + Configuration.holdBrowserOpen = true; + Configuration.baseUrl = SelenideConfiguration.getBaseUrl(); + Configuration.reportsFolder = "target/surefire-reports"; + } + + @AfterAll + public static void AfterAll() { + WebDriverRunner.closeWindow(); + SelenideConfiguration.closeSession(); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/hooks/SelenideConfiguration.java b/src/main/java/org/onap/portalng/e2e/hooks/SelenideConfiguration.java new file mode 100644 index 0000000..b9788a8 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/hooks/SelenideConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.hooks; + +import com.codeborne.selenide.Configuration; +import com.codeborne.selenide.WebDriverRunner; +import org.onap.portalng.e2e.helpers.ConfigFileReader; + +import java.util.Properties; + +import static java.lang.Boolean.parseBoolean; + +public class SelenideConfiguration { + + private static final String REPORTS_FOLDER = "target"; + private static final Properties testProperties = new ConfigFileReader(System.getenv("PORTAL_ENV")).getProperties(); + + public static String getBaseUrl() { + if (System.getenv("PORTAL_BASE_URL") != null) { + testProperties.setProperty("baseUrl", System.getenv("PORTAL_BASE_URL")); + } + return testProperties.getProperty("baseUrl"); + } + + public static void getBrowser() { + String browser = System.getProperty("selenide.browser", "chrome"); + boolean headless = parseBoolean(System.getProperty("selenide.headless", "false")); + + Configuration.browser = browser; + Configuration.headless = headless; + Configuration.screenshots = true; + Configuration.reportsFolder = REPORTS_FOLDER; + } + + public static void closeSession() { + WebDriverRunner.closeWebDriver(); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/pages/LoginPage.java b/src/main/java/org/onap/portalng/e2e/pages/LoginPage.java new file mode 100644 index 0000000..6e57cfe --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/pages/LoginPage.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.pages; + +import org.openqa.selenium.By; + +public class LoginPage { + + public static final By SIGN_IN_BTN = By.id("kc-login"); + public static final By USERNAME_LBL = By.xpath("//label[contains(text(),'Username or email')]"); + public static final By PASSWORD_LBL = By.xpath("//label[contains(text(),'Password')]"); + public static final By USERNAME_INPUT = By.id("username"); + public static final By PASSWORD_INPUT = By.id("password"); + + public static final By CURRENT_PAGE_SPAN = By.xpath("//span[@aria-current='page']"); + public static final By CURRENT_PAGE_HEADING_TITLE = By.xpath("//h2[@class='qa_title']"); + + public static final By DROPDOWN_MENU = By.id("dropdownMenu"); + public static final By LOGOUT_BUTTON = By.xpath("//button[contains(text(), \"Logout\")]"); + public static final By INPUT_ERROR_SPAN = By.id("input-error"); + +} diff --git a/src/main/java/org/onap/portalng/e2e/pages/MainPage.java b/src/main/java/org/onap/portalng/e2e/pages/MainPage.java new file mode 100644 index 0000000..3d91bb9 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/pages/MainPage.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.pages; + +import org.openqa.selenium.By; + +public class MainPage { + + public static final By NAV_LINKS = By.xpath("//a[@class='nav-link']"); + public static final By SPINNER = By.xpath("//div[contains(@class, 'loading-spinner')]"); + + public static final By DASHBOARD_BTN = By.className("qa_menu_home"); + public static final By APP_STARTER_BTN = By.className("qa_menu_app_starter"); + public static final By USERS_BTN = By.className("qa_menu_users"); + +} + diff --git a/src/main/java/org/onap/portalng/e2e/pages/PageWithTable.java b/src/main/java/org/onap/portalng/e2e/pages/PageWithTable.java new file mode 100644 index 0000000..941c63f --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/pages/PageWithTable.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.pages; + +import org.openqa.selenium.By; + +public class PageWithTable { + + public static final By PAGINATION = By.xpath("//ul[contains(@class, 'pagination')]"); + public static final By NEXT_PAGE = By.xpath("//ul[contains(@class, 'pagination')]//li[last()-1]"); + public static final By TABLE_ROWS = By.xpath("//table//tbody/tr"); + public static final By ROW_CELLS = By.xpath("td"); + public static final By ROW_DELETE_BUTTON = By.xpath("td//button[contains(@class, 'qa_delete_button')]"); +} diff --git a/src/main/java/org/onap/portalng/e2e/pages/PopUpDialogPage.java b/src/main/java/org/onap/portalng/e2e/pages/PopUpDialogPage.java new file mode 100644 index 0000000..dcb9b9a --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/pages/PopUpDialogPage.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.pages; + +import org.openqa.selenium.By; + +public class PopUpDialogPage { + public static final By DIALOG_HEADER = By.className("qa_modal_header"); + public static final By DIALOG_BODY = By.className("qa_modal_body"); + public static final By DIALOG_APPLY_BUTTON = By.className("qa_apply_button"); + public static final By DIALOG_CANCEL_BUTTON = By.className("qa_cancel_button"); + public static final By ALERT_SUCCESS = By.className("alert-success"); + public static final By ALERT_ERROR = By.className("alert-error"); + public static final By ALERT_WARNING = By.className("alert-danger"); +} diff --git a/src/main/java/org/onap/portalng/e2e/pages/UserAdministrationPage.java b/src/main/java/org/onap/portalng/e2e/pages/UserAdministrationPage.java new file mode 100644 index 0000000..77fd534 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/pages/UserAdministrationPage.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.pages; + +import org.openqa.selenium.By; + +public class UserAdministrationPage { + + + //ALERT + public static final By ALERT_DANGER = By.className("alert-danger"); + public static final By ALERT_SUCCESS = By.className("alert-success"); + + //TITLES + public static final By TITLE_H2 = By.tagName("h2"); + public static final By TITLE_H4 = By.tagName("h4"); + public static final By TITLE_H5 = By.tagName("h5"); + + + //BUTTONS + public static final By BUTTON_CREATE = By.className("qa_create_button"); + public static final By BUTTON_CANCEL = By.className("qa_submit_cancel"); + public static final By BUTTON_SAVE = By.className("qa_submit_button"); + public static final By BUTTON_EDIT = By.className("qa_edit_button"); + + //LABELS + public static final By LABEL_ID = By.xpath("//label[@for = 'id']"); + public static final By LABEL_USERNAME = By.xpath("//label[@for = 'username']"); + public static final By LABEL_EMAIL = By.xpath("//label[@for = 'email']"); + public static final By LABEL_FIRST_NAME = By.xpath("//label[@for = 'firstName']"); + public static final By LABEL_LAST_NAME = By.xpath("//label[@for = 'lastName']"); + //INPUT + public static final By INPUT_ID = By.xpath("//input[@id = 'id']"); + public static final By INPUT_USERNAME = By.xpath("//input[@id = 'username']"); + public static final By INPUT_EMAIL = By.xpath("//input[@id = 'email']"); + public static final By INPUT_FIRST_NAME = By.xpath("//input[@id = 'firstName']"); + public static final By INPUT_LAST_NAME = By.xpath("//input[@id = 'lastName']"); + + public static final By INVALID_INPUT = By.className("ng-invalid"); + public static final By REQUIRED_EMAIL = By.className("qa_required_email"); + public static final By REQUIRED_USERNAME = By.className("qa_required_user_name"); + public static final By INVALID_USERNAME = By.className("qa_invalid_user_name"); + public static final By INVALID_EMAIL = By.className("qa_invalid_email"); + public static final By WRONG_EMAIL_FORMAT = By.className("qa_wrong_format_email"); + + //FORM + public static final By FORM_CHECK = By.className("form-check"); + //TABLE + public static final By TABLE_ROWS = By.xpath("//tbody/tr"); + + public static final By TITLE_LBL = By.className("qa_title"); + public static final By USER_DATA_HEADER = By.xpath("//*[contains(text(), 'Set User Data')]"); + public static final By ROLES_HEADER = By.xpath("//*[contains(text(), 'Set Roles')]"); + + public static final By AVAILABLE_ROLES = By.className("qa_available_roles"); + public static final By ASSIGNED_ROLES = By.className("qa_assigned_roles"); + //ROLES + public static final By ONAP_DESIGNER_ROLE = By.id("onap_designer"); + public static final By ONAP_OPERATOR_ROLE = By.id("onap_operator"); + public static final By ONAP_ADMIN_ROLE = By.id("onap_admin"); + public static final By AVAILABLE_ROLES_HEADER = By.className("qa_available_roles"); + public static final By ASSIGNED_ROLES_HEADER = By.className("qa_assigned_roles"); + + public static By roleCheckbox(String role) { + return By.xpath("div/input[contains(@type,checkbox) and contains(@aria-labelledby, '" + role + "')]"); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/step_definitions/common/CommonStepDef.java b/src/main/java/org/onap/portalng/e2e/step_definitions/common/CommonStepDef.java new file mode 100644 index 0000000..bcbf3b4 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/step_definitions/common/CommonStepDef.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.step_definitions.common; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import org.onap.portalng.e2e.steps.common.CommonSteps; +import org.onap.portalng.e2e.types.Button; +import org.onap.portalng.e2e.types.Page; + +public class CommonStepDef { + + @Given("User clicks on {} button in main menu") + public void userClicksOnButtonInMainMenu(Button item) { + CommonSteps.userClicksOnButtonInMainMenu(item); + } + @Given("User can see {}") + public void userCanSeePage(Page page) { + CommonSteps.userCanSeePage(page); + } + + @Then("User should see error message with text {}") + public void userClicksOnSubmitButtonAndErrorMessageIsDisplayed(String errorCode) { + CommonSteps.userClicksOnSubmitButtonAndErrorMessageIsDisplayed(errorCode); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/step_definitions/login/LoginStepDef.java b/src/main/java/org/onap/portalng/e2e/step_definitions/login/LoginStepDef.java new file mode 100644 index 0000000..660fd4e --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/step_definitions/login/LoginStepDef.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.step_definitions.login; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import org.onap.portalng.e2e.steps.login.LoginSteps; +import org.onap.portalng.e2e.steps.main.MainSteps; + +public class LoginStepDef { + @And("User verifies presence of all elements on Sign In form") + public void verifySignInForm() { + LoginSteps.verifySignInForm(); + } + + @When("User fills log in form with USERNAME value {string} and PASSWORD value {string}") + public void fillFormWithUsernameAndPasswordValues(String username, String password) { + LoginSteps.fillFormWithUsernameAndPasswordValues(username, password); + } + + @Then("User submits credentials with Sign In button") + public void submitCredentialsForLoginBySignInButton() { + LoginSteps.submitCredentialsForLoginBySignInButton(); + } + + @And("User checks if is signed in to the Portal") + public void userChecksIfSignedInToThePortal(){ + LoginSteps.userChecksIfSignedInToThePortal(); + } + + @And("User clicks on Logout button to log out from the Portal") + public void userClicksOnLogoutButton(){ + LoginSteps.userClicksOnLogoutButton(); + } + + @Then("User sees error message {string} after incorrect credentials input") + public void errorIsShownAfterWrongCredentialsInput(String errorMsg) { + LoginSteps.errorIsShownAfterWrongCredentialsInput(errorMsg); + } + + @And("User is logged in Portal as ADMIN") + public void userIsLoggedInPortalAsAdmin() { + MainSteps.userVisitsTheIndexPage(); + LoginSteps.fillFormWithUsernameAndPasswordValues("onap-admin", "password"); + LoginSteps.submitCredentialsForLoginBySignInButton(); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/step_definitions/main/MainStepDef.java b/src/main/java/org/onap/portalng/e2e/step_definitions/main/MainStepDef.java new file mode 100644 index 0000000..f088a7d --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/step_definitions/main/MainStepDef.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.step_definitions.main; + +import io.cucumber.java.en.Given; +import io.cucumber.java.en.When; +import org.onap.portalng.e2e.steps.common.CommonSteps; +import org.onap.portalng.e2e.steps.main.MainSteps; +import org.onap.portalng.e2e.steps.user_administration.UserAdministrationSteps; +import org.onap.portalng.e2e.types.Page; + +public class MainStepDef { + + @Given("User opens the Portal page") + public void userVisitsTheIndexPage() { + MainSteps.userVisitsTheIndexPage(); + } + + @Given("User visits the {} page") + public void userVisitsTheUsersPage(Page page) { + MainSteps.userClicksOnUserMenuBtn(); + CommonSteps.userCanSeePage(page); + } + + @When("User clicks on Create User button") + public void userClicksOnCreateUserButton() { + UserAdministrationSteps.userClicksOnCreateUserButton(); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/step_definitions/user_administration/UserAdministrationStepDef.java b/src/main/java/org/onap/portalng/e2e/step_definitions/user_administration/UserAdministrationStepDef.java new file mode 100644 index 0000000..8d8dfec --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/step_definitions/user_administration/UserAdministrationStepDef.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.step_definitions.user_administration; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import org.onap.portalng.e2e.steps.main.MainSteps; +import org.onap.portalng.e2e.steps.user_administration.UserAdministrationSteps; +import org.onap.portalng.e2e.types.UserRole; + +public class UserAdministrationStepDef { + + @And("User verifies Create User Form") + public void userVerifiesCreateUserForm() { + UserAdministrationSteps.userVerifiesCreateUserForm(); + } + + @And("User fills data necessary for creating the user with USERNAME value {} in the form") + public void userFillsDataNecessaryForCreatingTheUserInTheForm(String username) { + UserAdministrationSteps.userFillsDataNecessaryForCreatingTheUserInTheForm(username); + } + + @When("User set parameter {} with value {} on User create or edit page") + public void userFillsSpecificValuesForUserCreation(String input, String username) { + UserAdministrationSteps.userFillsSpecificValuesForUserCreation(input, username); + } + + @And("User clicks on Save button in the form") + public void userClicksOnSaveButtonInTheForm() { + UserAdministrationSteps.userClicksOnSaveButtonInTheForm(); + } + + @And("User clicks on Cancel button in the form") + public void userClicksOnCancelButtonInTheForm() { + UserAdministrationSteps.userClicksOnCancelButtonInTheForm(); + } + + + @And("User should see {} feedback {}") + public void userSeeFeedback(String invalidInput, String message) { + UserAdministrationSteps.userSeeFeedback(invalidInput, message); + } + + @Then("User verifies newly created User in the User List") + public void userVerifiesNewUserInUserList() throws InterruptedException { + UserAdministrationSteps.userVerifiesNewUserInUserList(); + } + + @And("User with USERNAME value {} is created") + public void userIsCreated(String username) { + MainSteps.userClicksOnUserMenuBtn(); + UserAdministrationSteps.userClicksOnCreateUserButton(); + UserAdministrationSteps.userVerifiesCreateUserForm(); + UserAdministrationSteps.userFillsDataNecessaryForCreatingTheUserInTheForm(username); + UserAdministrationSteps.userClicksOnSaveButtonInTheForm(); +// UserAdministrationSteps.userVerifiesNewUserInUserList(); + } + + @Then("User with USERNAME {} is successfully deleted") + public void deleteUser(String username) { + UserAdministrationSteps.deleteUser(username); + } + + @Given("User clicks on EDIT button for user with USERNAME {} on Users page") + public void userClickOnBtnForUser(String username) { + UserAdministrationSteps.clickOnEditBtn(username); + } + + @Given("User checks presence of elements on User edit page") + public void userCheckAllElementsOnUpdatePage() { + UserAdministrationSteps.userCheckAllElementsOnEditPage(); + } + + @Given("User fills all possible values to User edit page") + public void userFillsValuesToEditFormPage() { + UserAdministrationSteps.userFillsValuesToEditFormPage(); + } + + @Given("User clicks on {} button for user on User edit page") + public void userClickOnBtnOnEditPage(String button) { + UserAdministrationSteps.userClickOnBtnOnEditPage(button); + } + + @When("User fills EMAIL {} in User edit page") + public void userFillsEmailValuesForUserCreation(String email) { + UserAdministrationSteps.userFillsEmailValuesForUserCreation(email); + } + + @Given("User checks {} pop-up on user page with text {}") + public void userChecksPopupOnUserPage(String popUpType, String text) { + UserAdministrationSteps.userChecksPopupOnUserPage(popUpType, text); + } + + @When("User clicks on {} available role checkbox") + public void assignAvailableRolesToUser(UserRole userRole) { + UserAdministrationSteps.assignAvailableRolesToUser(userRole); + } + + @When("{} role is assigned to user") + public void selectedRoleIsAssignedToUser(UserRole userRole) { + UserAdministrationSteps.verifyThatUserRoleIsAssigned(userRole); + } + + @When("User clicks on {} assigned role checkbox") + public void unAssignRolesToUser(UserRole userRole) { + UserAdministrationSteps.unAssignRoleFromUser(userRole); + } + + @When("{} role is unassigned from user") + public void selectedRoleIsUnassignedFromUser(UserRole userRole) { + UserAdministrationSteps.verifyThatUserRoleIsAvailable(userRole); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/steps/common/CommonSteps.java b/src/main/java/org/onap/portalng/e2e/steps/common/CommonSteps.java new file mode 100644 index 0000000..fa96438 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/steps/common/CommonSteps.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.steps.common; + +import com.codeborne.selenide.Condition; +import org.onap.portalng.e2e.types.Button; +import org.onap.portalng.e2e.types.Page; + +import java.time.Duration; + +import static com.codeborne.selenide.Condition.disappear; +import static com.codeborne.selenide.Selenide.$; +import static org.onap.portalng.e2e.helpers.CommonUtils.checkTextOfElement; +import static org.onap.portalng.e2e.pages.MainPage.*; +import static org.onap.portalng.e2e.pages.PopUpDialogPage.ALERT_WARNING; +import static org.onap.portalng.e2e.pages.UserAdministrationPage.TITLE_H2; + + +public class CommonSteps { + + public static void spinnerShouldDisappear() { + try { + $(SPINNER).shouldBe(Condition.visible, Duration.ofSeconds(3)); + } catch (Throwable ignored) { + } finally { + $(SPINNER).shouldBe(disappear, Duration.ofSeconds(80)); + } + } + + public static void userClicksOnButtonInMainMenu(Button button) { + switch (button) { + case DASHBOARD: + checkTextOfElement($(DASHBOARD_BTN), "Dashboard"); + $(DASHBOARD_BTN).click(); + break; + case APP_STARTER: + checkTextOfElement($(APP_STARTER_BTN), "App Starter"); + $(APP_STARTER_BTN).click(); + break; + case USERS: + checkTextOfElement($(USERS_BTN), "Users"); + $(USERS_BTN).click(); + break; + default: + throw new IllegalStateException("Sidebar Menu Menu button" + button + "not recognized"); + } + } + + public static void userCanSeePage(Page page) { + switch (page) { + case DASHBOARD: + spinnerShouldDisappear(); + checkTextOfElement($(TITLE_H2), "Dashboard"); + break; + case APP_STARTER_PAGE: + spinnerShouldDisappear(); + checkTextOfElement($(TITLE_H2), "App Starter"); + break; + case USERS_PAGE: + spinnerShouldDisappear(); + checkTextOfElement($(TITLE_H2), "User Administration"); + break; + case USER_EDIT_PAGE: + spinnerShouldDisappear(); + checkTextOfElement($(TITLE_H2), "Edit User"); + break; + default: + throw new IllegalStateException("Page not recognized"); + } + } + + public static void userClicksOnSubmitButtonAndErrorMessageIsDisplayed(String error) { + checkTextOfElement($(ALERT_WARNING), error); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/steps/common/TableSteps.java b/src/main/java/org/onap/portalng/e2e/steps/common/TableSteps.java new file mode 100644 index 0000000..182c2f6 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/steps/common/TableSteps.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.steps.common; + +import com.codeborne.selenide.ElementsCollection; +import com.codeborne.selenide.Selenide; +import com.codeborne.selenide.SelenideElement; +import org.openqa.selenium.By; + +import java.util.List; +import java.util.Optional; + +import static com.codeborne.selenide.Condition.*; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; +import static java.util.stream.Collectors.toList; +import static org.onap.portalng.e2e.pages.PageWithTable.*; + +public class TableSteps { + + public static Optional findRowWithText(String text, boolean exactMatch) { + return findRowsWithText(text, exactMatch, false).stream().findAny(); + } + + public static List findRowsWithText(String text, boolean exactMatch, boolean isContaining) { + $(TABLE_ROWS).should(exist); + List foundedRows = findRowsOnActivePage(text, exactMatch, isContaining); + while (foundedRows.isEmpty() && hasNextPage()) { + goToNextPage(); + foundedRows = findRowsOnActivePage(text, exactMatch, isContaining); + } + return foundedRows; + } + + public static boolean hasNextPage() { + return $(PAGINATION).exists() && $(NEXT_PAGE).has(not(cssClass("disabled"))); + } + + public static void goToNextPage() { + Selenide.executeJavaScript("arguments[0].click()", $(NEXT_PAGE).$(By.xpath("a")).getWrappedElement()); + CommonSteps.spinnerShouldDisappear(); + } + + + public static int countRowsOnAllPages() { + int numberOfRows = Selenide.$$(TABLE_ROWS).size(); + while (hasNextPage()) { + goToNextPage(); + numberOfRows += Selenide.$$(TABLE_ROWS).size(); + } + return numberOfRows; + } + + private static List findRowsOnActivePage(String text, boolean exactMatch, boolean isContaining) { + return $$(TABLE_ROWS).stream() + .filter(row -> { + ElementsCollection rowValues = row.$$(ROW_CELLS); + String textInRow = getTextFromCell(rowValues.first()); + if (exactMatch) { + return text.equals(textInRow); + } else if (isContaining) { + return textInRow.contains(text); + } else { + return textInRow.startsWith(text); + } + }).collect(toList()); + } + + private static String getTextFromCell(SelenideElement cell) { + SelenideElement anchor = cell.find(By.xpath("a")); + if (anchor.exists()) { + return anchor.getText(); + } else { + return cell.getText(); + } + } + +} diff --git a/src/main/java/org/onap/portalng/e2e/steps/login/LoginSteps.java b/src/main/java/org/onap/portalng/e2e/steps/login/LoginSteps.java new file mode 100644 index 0000000..5d3e927 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/steps/login/LoginSteps.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.steps.login; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.Selenide; +import org.onap.portalng.e2e.pages.LoginPage; + +import static com.codeborne.selenide.Condition.text; +import static org.assertj.core.api.Assertions.assertThat; + +public class LoginSteps { + + public static void verifySignInForm() { + Selenide.$(LoginPage.USERNAME_LBL).shouldHave(text("Username or email")); + Selenide.$(LoginPage.PASSWORD_LBL).shouldHave(Condition.text("Password")); + Selenide.$(LoginPage.SIGN_IN_BTN).shouldHave(Condition.value("Sign In")); + } + + public static void fillFormWithUsernameAndPasswordValues(String username, String password) { + Selenide.$(LoginPage.USERNAME_INPUT).setValue(username); + Selenide.$(LoginPage.PASSWORD_INPUT).setValue(password); + } + + public static void submitCredentialsForLoginBySignInButton() { + Selenide.$(LoginPage.SIGN_IN_BTN).click(); + } + + public static void userChecksIfSignedInToThePortal(){ + Selenide.$(LoginPage.CURRENT_PAGE_SPAN).shouldHave(text("Dashboard")); + Selenide.$(LoginPage.CURRENT_PAGE_HEADING_TITLE).shouldHave(text("Dashboard")); + } + + public static void userClicksOnLogoutButton(){ + Selenide.$(LoginPage.DROPDOWN_MENU).click(); + Selenide.$(LoginPage.LOGOUT_BUTTON).click(); + } + + public static void errorIsShownAfterWrongCredentialsInput(String errorMsg) { + assertThat(Selenide.$(LoginPage.INPUT_ERROR_SPAN).getText()) + .describedAs("Text is not as expected") + .isEqualTo(errorMsg); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/steps/main/MainSteps.java b/src/main/java/org/onap/portalng/e2e/steps/main/MainSteps.java new file mode 100644 index 0000000..ffb0a96 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/steps/main/MainSteps.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.steps.main; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.Configuration; + +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.open; +import static org.onap.portalng.e2e.pages.MainPage.USERS_BTN; +import static org.onap.portalng.e2e.pages.UserAdministrationPage.TITLE_H2; + +public class MainSteps { + public static void userVisitsTheIndexPage() { + open(Configuration.baseUrl); + } + + public static void userClicksOnUserMenuBtn() { + $(USERS_BTN).click(); + } + + public void userCanSeeUserAdministrationPage() { + $(TITLE_H2).shouldHave(Condition.text("User Administration")); + } +} diff --git a/src/main/java/org/onap/portalng/e2e/steps/user_administration/UserAdministrationSteps.java b/src/main/java/org/onap/portalng/e2e/steps/user_administration/UserAdministrationSteps.java new file mode 100644 index 0000000..1460e37 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/steps/user_administration/UserAdministrationSteps.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.steps.user_administration; + +import com.codeborne.selenide.Condition; +import com.codeborne.selenide.Selenide; +import com.codeborne.selenide.SelenideElement; +import org.junit.Assert; +import org.onap.portalng.e2e.steps.main.MainSteps; +import org.onap.portalng.e2e.helpers.UiSessionVariables; +import org.onap.portalng.e2e.pages.PopUpDialogPage; +import org.onap.portalng.e2e.steps.common.CommonSteps; +import org.onap.portalng.e2e.steps.common.TableSteps; +import org.onap.portalng.e2e.types.Button; +import org.onap.portalng.e2e.types.UserRole; +import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.support.ui.ExpectedConditions; + +import java.util.Optional; + +import static com.codeborne.selenide.Condition.*; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; +import static org.assertj.core.api.Assertions.assertThat; +import static org.onap.portalng.e2e.helpers.CommonUtils.checkPresenceOfElement; +import static org.onap.portalng.e2e.helpers.CommonUtils.checkTextOfElement; +import static org.onap.portalng.e2e.pages.PageWithTable.ROW_DELETE_BUTTON; +import static org.onap.portalng.e2e.pages.PopUpDialogPage.ALERT_SUCCESS; +import static org.onap.portalng.e2e.pages.PopUpDialogPage.*; +import static org.onap.portalng.e2e.pages.UserAdministrationPage.*; + +public class UserAdministrationSteps { + + public static void userClicksOnCreateUserButton() { + $(BUTTON_CREATE).shouldHave(Condition.text("Create User")); + $(BUTTON_CREATE).click(); + } + + public static void userVerifiesCreateUserForm() { + $(TITLE_H2).shouldHave(Condition.text("Create User")); + + $$(TITLE_H4).get(0).shouldHave(Condition.text("Set User Data")); + $$(TITLE_H4).get(1).shouldHave(Condition.text("Set Roles")); + + $$(TITLE_H5).get(1).shouldHave(Condition.text("Available")); + $$(TITLE_H5).get(2).shouldHave(Condition.text("Assigned")); + + $(LABEL_ID).shouldHave(Condition.text("ID")); + $(LABEL_USERNAME).shouldHave(Condition.text("Username")); + $(LABEL_EMAIL).shouldHave(Condition.text("Email")); + $(LABEL_FIRST_NAME).shouldHave(Condition.text("First Name")); + $(LABEL_LAST_NAME).shouldHave(Condition.text("Last Name")); + + $(INPUT_ID).shouldBe(Condition.disabled); + } + + public static void userFillsDataNecessaryForCreatingTheUserInTheForm(String username) { + $(INPUT_USERNAME).setValue(username); + $(INPUT_EMAIL).setValue(username + "@test.user"); + $(INPUT_FIRST_NAME).setValue("E2E"); + $(INPUT_LAST_NAME).setValue("TestUser"); + UiSessionVariables.USERNAME.set(username); + + $$(FORM_CHECK).findBy(Condition.text("onap_admin")).$("input").click(); + } + public static void userFillsSpecificValuesForUserCreation(String input, String value) { + switch (input) { + case "EMAIL": + if (value.equals("clear")) { + $(INPUT_EMAIL).setValue(" "); + $(INPUT_EMAIL).sendKeys(Keys.BACK_SPACE); + } else { + $(INPUT_EMAIL).setValue(" "); + $(INPUT_EMAIL).sendKeys(Keys.BACK_SPACE); + $(INPUT_EMAIL).setValue(value); + } + break; + case "USERNAME": + if (value.equals("clear")) { + $(INPUT_USERNAME).setValue(" "); + $(INPUT_USERNAME).sendKeys(Keys.BACK_SPACE); + } else { + $(INPUT_USERNAME).setValue(value); + } + break; + case "LAST_NAME": + $(INPUT_LAST_NAME).setValue(value); + break; + case "FIRST_NAME": + $(INPUT_FIRST_NAME).setValue(value); + break; + default: + throw new IllegalStateException("Unexpected value: " + input); + } + } + + public static void userClicksOnSaveButtonInTheForm() { + $(BUTTON_SAVE).click(); + } + + public static void userClicksOnCancelButtonInTheForm() { + $(BUTTON_CANCEL).click(); + } + + public static void userSeeFeedback(String invalidInput, String message) { + switch (invalidInput) { + case "REQUIRED_USERNAME": + checkTextOfElement($(REQUIRED_USERNAME), message); + checkPresenceOfElement($(INVALID_INPUT)); + break; + case "REQUIRED_EMAIL": + checkTextOfElement($(REQUIRED_EMAIL), message); + checkPresenceOfElement($(INVALID_INPUT)); + break; + case "INVALID_USERNAME": + checkTextOfElement($(INVALID_USERNAME), message); + checkPresenceOfElement($(INVALID_INPUT)); + break; + case "INVALID_EMAIL": + checkTextOfElement($(INVALID_EMAIL), message); + checkPresenceOfElement($(INVALID_INPUT)); + break; + case "WRONG_EMAIL_FORMAT": + checkTextOfElement($(WRONG_EMAIL_FORMAT), message); + checkPresenceOfElement($(INVALID_INPUT)); + break; + default: + throw new IllegalArgumentException(invalidInput + " is not implemented yet"); + + } + } + + + public static void userVerifiesNewUserInUserList() throws InterruptedException { + Selenide.Wait().until(ExpectedConditions.visibilityOf($$(TABLE_ROWS).get(0))); + + for (SelenideElement row : $$(TABLE_ROWS)) { + if ($(row).findAll(By.id("td")).findBy(Condition.text("e2e-test-user")).exists()) { + Assert.assertEquals("e2e-test-user", $(row).findAll(By.id("td")).get(0).getText()); + Assert.assertEquals("E2e", $(row).findAll(By.id("td")).get(1).getText()); + Assert.assertEquals("TestUser", $(row).findAll(By.id("td")).get(2).getText()); + Assert.assertEquals("e2e@test.user", $(row).findAll(By.id("td")).get(3).getText()); + Assert.assertEquals("onap_admin", $(row).findAll(By.id("td")).get(4).getText()); + } + } + } + + public static void deleteUser(String username) { + MainSteps.userClicksOnUserMenuBtn(); + + Optional userRow = TableSteps.findRowWithText(username, true); + if (userRow.isPresent()) { + assertThat(userRow.isPresent()).as("User cannot be deleted, user with " + username + " was not found.").isTrue(); + userRow.get().$(ROW_DELETE_BUTTON).click(); + $(DIALOG_HEADER).shouldHave(text("Delete User")); + $(DIALOG_BODY).shouldHave(text("Are you sure, that you want to delete user: " + username + " ? ")); + $(DIALOG_APPLY_BUTTON).shouldHave(text("Delete")); + $(DIALOG_APPLY_BUTTON).click(); + $$(ALERT_SUCCESS).last().shouldHave(text("User successfully deleted.")); + userRow.get().should(not(exist)); + } + } + + public static void clickOnEditBtn(String username) { + CommonSteps.userClicksOnButtonInMainMenu(Button.USERS); + + Optional userRow = TableSteps.findRowWithText(username, true); + assertThat(userRow.isPresent()).as("User cannot be updated, user with " + username + " was not found.").isTrue(); + userRow.get().$(BUTTON_EDIT).click(); + userRow.get().should(not(exist)); + } + + public static void userCheckAllElementsOnEditPage() { + checkTextOfElement($(TITLE_LBL), "Edit User"); + checkPresenceOfElement($(USER_DATA_HEADER)); + checkPresenceOfElement($(INPUT_ID)); + checkPresenceOfElement($(INPUT_USERNAME)); + checkPresenceOfElement($(INPUT_EMAIL)); + checkPresenceOfElement($(INPUT_FIRST_NAME)); + checkPresenceOfElement($(INPUT_LAST_NAME)); + checkTextOfElement($(LABEL_ID), "ID"); + checkTextOfElement($(LABEL_USERNAME), "Username"); + checkTextOfElement($(LABEL_EMAIL), "Email"); + checkTextOfElement($(LABEL_FIRST_NAME), "First Name"); + checkTextOfElement($(LABEL_LAST_NAME), "Last Name"); + checkPresenceOfElement($(ROLES_HEADER)); + checkTextOfElement($(AVAILABLE_ROLES), "Available"); + checkTextOfElement($(ASSIGNED_ROLES), "Assigned"); + checkTextOfElement($(ONAP_DESIGNER_ROLE), "onap_designer"); + checkTextOfElement($(ONAP_OPERATOR_ROLE), "onap_operator"); + checkTextOfElement($(ONAP_ADMIN_ROLE), "onap_admin"); + checkTextOfElement($(BUTTON_CANCEL), "Cancel"); + checkTextOfElement($(BUTTON_SAVE), "Save"); + } + + public static void userFillsValuesToEditFormPage() { + $(INPUT_FIRST_NAME).setValue("firstName"); + $(INPUT_LAST_NAME).setValue("lastName"); + $(INPUT_EMAIL).setValue("e2e" + "@test.com"); + } + + public static void userClickOnBtnOnEditPage(String button) { + switch (button) { + case "Edit": + $(BUTTON_SAVE).click(); + break; + case "Cancel": + $(BUTTON_CANCEL).click(); + break; + default: + throw new IllegalArgumentException("Button was not implemented"); + } + } + + public static void userFillsEmailValuesForUserCreation(String email) { + $(INPUT_EMAIL).clear(); + $(INPUT_EMAIL).setValue(email); + } + + public static void userChecksPopupOnUserPage(String popUpType, String text) { + if (popUpType.equals("SUCCESS")) { + checkTextOfElement($(PopUpDialogPage.ALERT_SUCCESS), text); + } else if (popUpType.equals("ERROR")) { + checkTextOfElement($(PopUpDialogPage.ALERT_ERROR), text); + } + } + + public static void assignAvailableRolesToUser(UserRole userRole) { + SelenideElement availableRolesBlock = $(AVAILABLE_ROLES_HEADER).parent(); + SelenideElement availableRole = availableRolesBlock.find(userRoleCheckBox(userRole)); + availableRole.click(); + availableRole.should(not(exist)); + } + + public static void unAssignRoleFromUser(UserRole userRole) { + SelenideElement assignedRolesBlock = $(ASSIGNED_ROLES_HEADER).parent(); + SelenideElement assignedRole = assignedRolesBlock.find(userRoleCheckBox(userRole)); + assignedRole.click(); + assignedRole.should(not(exist)); + } + + public static void verifyThatUserRoleIsAvailable(UserRole userRole) { + SelenideElement availableRolesBlock = $(AVAILABLE_ROLES_HEADER).parent(); + availableRolesBlock.find(userRoleCheckBox(userRole)).should(exist); + } + + public static void verifyThatUserRoleIsAssigned(UserRole userRole) { + SelenideElement assignedRolesBlock = $(ASSIGNED_ROLES_HEADER).parent(); + assignedRolesBlock.find(userRoleCheckBox(userRole)).should(exist); + } + + public static By userRoleCheckBox(UserRole userRole) { + switch (userRole) { + case ONAP_DESIGNER: + return roleCheckbox("onap_designer"); + case ONAP_OPERATOR: + return roleCheckbox("onap_operator"); + case ONAP_ADMIN: + return roleCheckbox("onap_admin"); + default: + throw new IllegalArgumentException("Not recognized role"); + } + } +} diff --git a/src/main/java/org/onap/portalng/e2e/types/Button.java b/src/main/java/org/onap/portalng/e2e/types/Button.java new file mode 100644 index 0000000..a434b4f --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/types/Button.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.types; + +public enum Button { + DROPDOWN_MENU, + DASHBOARD, + APP_STARTER, + USERS +} diff --git a/src/main/java/org/onap/portalng/e2e/types/Page.java b/src/main/java/org/onap/portalng/e2e/types/Page.java new file mode 100644 index 0000000..1ec1e33 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/types/Page.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.types; + +public enum Page { + DASHBOARD, + APP_STARTER_PAGE, + USERS_PAGE, + USER_EDIT_PAGE +} diff --git a/src/main/java/org/onap/portalng/e2e/types/UserRole.java b/src/main/java/org/onap/portalng/e2e/types/UserRole.java new file mode 100644 index 0000000..e1a0871 --- /dev/null +++ b/src/main/java/org/onap/portalng/e2e/types/UserRole.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023. Deutsche Telekom AG + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +package org.onap.portalng.e2e.types; + +public enum UserRole { + ONAP_DESIGNER("onap_designer"), + ONAP_OPERATOR("onap_operator"), + ONAP_ADMIN("onap_admin"); + + private String value; + + UserRole(final String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/resources/test-local.properties b/src/main/resources/test-local.properties new file mode 100644 index 0000000..d1648e9 --- /dev/null +++ b/src/main/resources/test-local.properties @@ -0,0 +1,20 @@ +# +# Copyright (c) 2023. Deutsche Telekom AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +# + +baseUrl=http://localhost \ No newline at end of file diff --git a/src/main/resources/test-remote.properties b/src/main/resources/test-remote.properties new file mode 100644 index 0000000..a4ea8cc --- /dev/null +++ b/src/main/resources/test-remote.properties @@ -0,0 +1,20 @@ +# +# Copyright (c) 2023. Deutsche Telekom AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +# + +baseUrl=https://remote-url \ No newline at end of file diff --git a/src/test/resources/cucumber.properties b/src/test/resources/cucumber.properties new file mode 100644 index 0000000..869613f --- /dev/null +++ b/src/test/resources/cucumber.properties @@ -0,0 +1,20 @@ +# +# Copyright (c) 2023. Deutsche Telekom AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +# + +cucumber.publish.quiet=true \ No newline at end of file diff --git a/src/test/resources/features/login.feature b/src/test/resources/features/login.feature new file mode 100644 index 0000000..5fecc34 --- /dev/null +++ b/src/test/resources/features/login.feature @@ -0,0 +1,32 @@ +# Copyright (c) 2023. Deutsche Telekom AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +Feature: Login and Logout + + Scenario: User can sign in to Portal with valid credentials + Given User opens the Portal page + And User verifies presence of all elements on Sign In form + When User fills log in form with USERNAME value 'onap-admin' and PASSWORD value 'password' + Then User submits credentials with Sign In button + And User checks if is signed in to the Portal + And User clicks on Logout button to log out from the Portal + + Scenario: User cannot login to Portal with invalid username or password + Given User opens the Portal page + And User verifies presence of all elements on Sign In form + When User fills log in form with USERNAME value 'onap-admin' and PASSWORD value 'invalidPassword' + And User submits credentials with Sign In button + Then User sees error message 'Invalid username or password.' after incorrect credentials input diff --git a/src/test/resources/features/user_administration.feature b/src/test/resources/features/user_administration.feature new file mode 100644 index 0000000..3e402db --- /dev/null +++ b/src/test/resources/features/user_administration.feature @@ -0,0 +1,121 @@ +# Copyright (c) 2023. Deutsche Telekom AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +Feature: User Administration + + @delete_user + Scenario: User can create a new user in Portal + Given User is logged in Portal as ADMIN + Given User visits the USERS_PAGE page + When User clicks on Create User button + And User verifies Create User Form + And User fills data necessary for creating the user with USERNAME value e2e-test-user in the form + And User clicks on Save button in the form + Given User visits the USERS_PAGE page + Then User verifies newly created User in the User List + + Scenario: User can cancel user creation + Given User visits the USERS_PAGE page + When User clicks on Create User button + And User verifies Create User Form + And User clicks on Cancel button in the form + And User can see USERS_PAGE + + Scenario: User cannot create a new user in Portal without mandatory parameters + Given User visits the USERS_PAGE page + When User clicks on Create User button + And User verifies Create User Form + And User clicks on Save button in the form + Then User should see REQUIRED_USERNAME feedback Required + And User should see REQUIRED_EMAIL feedback Cannot be empty + + @delete_user + Scenario: User cannot be created with already existing USERNAME + Given User with USERNAME value e2e-test-user is created + And User clicks on USERS button in main menu + When User clicks on Create User button + And User fills data necessary for creating the user with USERNAME value e2e-test-user in the form + And User clicks on Save button in the form + Then User should see error message with text Error while creating user account! Error reported by "Keycloak" system: "User exists with same username" Please, try to create user with different username. + + Scenario: User cannot be created with already existing EMAIL + Given User with USERNAME value e2e-test-user is created + And User clicks on USERS button in main menu + When User clicks on Create User button + And User fills data necessary for creating the user with USERNAME value e2e-test-user-2 in the form + And User set parameter EMAIL with value e2e-test-user@test.user on User create or edit page + And User clicks on Save button in the form + Then User should see error message with text Error while creating user account! Error reported by "Keycloak" system: "User exists with same email" Please, try to create user with different email address. + #deletion after test + Then User with USERNAME e2e-test-user is successfully deleted + + Scenario: User cannot be created with USERNAME value as empty string + Given User clicks on USERS button in main menu + And User clicks on Create User button + When User fills data necessary for creating the user with USERNAME value "" in the form + And User set parameter EMAIL with value test@test.user on User create or edit page + And User clicks on Save button in the form + Then User should see INVALID_USERNAME feedback Invalid character + + Scenario: User cannot be created with EMAIL value as empty string + Given User clicks on USERS button in main menu + And User clicks on Create User button + And User fills data necessary for creating the user with USERNAME value e2e-test-user in the form + When User set parameter EMAIL with value "" on User create or edit page + And User clicks on Save button in the form + Then User should see INVALID_EMAIL feedback Invalid character + And User should see WRONG_EMAIL_FORMAT feedback Wrong email format + + Scenario: User can be deleted in Portal + Given User with USERNAME value e2e-test-user is created + Then User with USERNAME e2e-test-user is successfully deleted + + @delete_user + Scenario: User can be edited in Portal + Given User with USERNAME value e2e-test-user is created + And User clicks on EDIT button for user with USERNAME e2e-test-user on Users page + And User can see USER_EDIT_PAGE + And User checks presence of elements on User edit page + And User clicks on Cancel button for user on User edit page + And User can see USERS_PAGE + And User clicks on EDIT button for user with USERNAME e2e-test-user on Users page + And User fills all possible values to User edit page + When User clicks on Edit button for user on User edit page + Then User checks SUCCESS pop-up on user page with text User successfully updated. + And User can see USERS_PAGE + + Scenario: User cannot be created with already existing EMAIL + Given User with USERNAME value e2e-test-user-1 is created + And User with USERNAME value e2e-test-user-2 is created + And User clicks on USERS button in main menu + And User can see USERS_PAGE + And User clicks on EDIT button for user with USERNAME e2e-test-user-1 on Users page + And User can see USER_EDIT_PAGE + When User fills EMAIL e2e-test-user-2@test.user in User edit page + And User clicks on Edit button for user on User edit page + Then User should see error message with text Error, changing user account failed! Error reported by "Keycloak" system: "User exists with same username or email" Please, try to create user with different email address. + #deletion after + Then User with USERNAME e2e-test-user-1 is successfully deleted + Then User with USERNAME e2e-test-user-2 is successfully deleted + + @delete_user + Scenario: User role can be assigned or unassigned on Edit page + Given User with USERNAME value e2e-test-user is created + And User clicks on EDIT button for user with USERNAME e2e-test-user on Users page + When User clicks on ONAP_DESIGNER available role checkbox + Then ONAP_DESIGNER role is assigned to user + And User clicks on ONAP_DESIGNER assigned role checkbox + Then ONAP_DESIGNER role is unassigned from user -- cgit 1.2.3-korg