├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── java │ └── com │ └── testninja │ └── pageobjects │ ├── examples │ ├── amazon │ │ ├── components │ │ │ ├── header │ │ │ │ ├── NavBar.java │ │ │ │ └── SearchContainer.java │ │ │ └── searchfilters │ │ │ │ ├── BaseProductFilter.java │ │ │ │ ├── CheckBoxFilter.java │ │ │ │ ├── MultiChoiceButtonFilter.java │ │ │ │ └── PriceRangeFilter.java │ │ └── pages │ │ │ ├── AmazonBasePage.java │ │ │ ├── HomePage.java │ │ │ └── SearchResultsPage.java │ └── spotify │ │ ├── components │ │ ├── Header.java │ │ ├── LeftNavBar.java │ │ ├── Player.java │ │ └── playlist │ │ │ ├── PlayButton.java │ │ │ ├── SaveButton.java │ │ │ └── SongRow.java │ │ └── pages │ │ ├── LoginPage.java │ │ ├── PlaylistPage.java │ │ ├── SpotifyBasePage.java │ │ └── SpotifyHomePage.java │ ├── utils │ ├── Interactions.java │ └── WaitHandler.java │ └── wrappers │ ├── BasePage.java │ ├── BaseWebComponent.java │ ├── BaseWebComponentFieldDecorator.java │ ├── PageObjectFactory.java │ ├── ScriptHelper.java │ └── annotations │ ├── Page.java │ └── PageObject.java └── test └── java └── com └── testning └── pageobjects ├── examples ├── amazon │ └── AmazonSearchFiltersTest.java └── spotify │ └── SpotifyPlaylistTest.java └── wrappers └── BaseTest.java /README.md: -------------------------------------------------------------------------------- 1 | # What is Page Object? 2 | Page Object is a Design Pattern which has become popular in test automation for enhancing test maintenance and reducing code duplication. A page object is an object-oriented class that serves as an interface to a page of your AUT. The tests then use the methods of this page object class whenever they need to interact with the UI of that page. The benefit is that if the UI changes for the page, the tests themselves don’t need to change, only the code within the page object needs to change. Subsequently all changes to support that new UI are located in one place. 3 | 4 | # Advantages: 5 | 6 | - There is a clean separation between test code and page specific code such as locators (or their use if you’re using a UI Map) and layout. 7 | - There is a single repository for the services or operations offered by the page rather than having these services scattered throughout the tests. 8 | 9 | # Example: 10 | > A page object does not necessarily need to represent all the parts of a page itself. The same principles used for page objects can be used to create “Page Component Objects” that represent discrete chunks of the page and can be included in page objects. These component objects can provide references the elements inside those discrete chunks, and methods to leverage the functionality provided by them. You can even nest component objects inside other component objects for more complex pages. If a page in the AUT has multiple components, or common components used throughout the site (e.g. a navigation bar), then it may improve maintainability and reduce code duplication. 11 | -- Quote from selenium offical site 12 | 13 | Let's use https://www.amazon.in and see how UI elements can be represented as reusable webcomponents using page objects. 14 | 15 | 16 | 17 | Below snippet is the representation of filter component in selenium pageobject: 18 | ```java 19 | public class CheckBoxFilter extends BaseProductFilter { 20 | 21 | public CheckBoxFilter(ScriptHelper scriptHelper, String filterHeader) { 22 | super(scriptHelper, filterHeader); 23 | } 24 | 25 | public void apply(List optionsToSelect) { 26 | optionsToSelect 27 | .stream() 28 | .forEach(option -> { 29 | waitForFilterToAppear(); 30 | clickSeeMore(); 31 | selectOption(getOptionCheckbox(option)); 32 | }); 33 | } 34 | 35 | public List getSelectedOptions() { 36 | waitForFilterToAppear(); 37 | clickSeeMore(); 38 | 39 | return getChildElement() 40 | .findElements(By.xpath(".//li/descendant::a[.//input[@type='checkbox'][@checked]]/descendant::span")) 41 | .stream() 42 | .map(interactions::getText) 43 | .filter(text -> !text.trim().equals("")) 44 | .collect(Collectors.toList()); 45 | 46 | } 47 | 48 | private void selectOption(WebElement element) { 49 | if (!interactions.isSelected(element)) { 50 | interactions.javaScriptClick(element); 51 | } 52 | } 53 | 54 | private void deselectOption(WebElement element) { 55 | if (interactions.isSelected(element)) { 56 | interactions.click(element); 57 | } 58 | } 59 | 60 | private WebElement getOptionCheckbox(String label) { 61 | return getChildElement().findElement(By.xpath(".//li/descendant::a[.//span[text()='" + label + "']]/descendant::input[@type='checkbox']")); 62 | } 63 | } 64 | ``` 65 | 66 | Now the component can be used in the tests like: 67 | 68 | ```java 69 | /* Test Material filter */ 70 | List material = Arrays.asList("Canvas", "Rubber"); 71 | CheckBoxFilter materialFilter = new CheckBoxFilter(scriptHelper, "Material"); 72 | materialFilter.apply(material); 73 | 74 | assertEquals(materialFilter.getSelectedOptions(), material); 75 | assertTrue(materialFilter.isClearLinkPresent()); 76 | assertFalse(materialFilter.isSeeMoreLinkPresent()); 77 | 78 | /* Test Brand filter */ 79 | 80 | List brands = Arrays.asList("Campus"); 81 | CheckBoxFilter brandFilter = new CheckBoxFilter(scriptHelper, "Brand"); 82 | brandFilter.apply(brands); 83 | 84 | assertEquals(brandFilter.getSelectedOptions(), brands); 85 | assertTrue(brandFilter.isClearLinkPresent()); 86 | assertTrue(brandFilter.isSeeMoreLinkPresent()); 87 | ``` -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | } 4 | 5 | group 'org.example' 6 | version '1.0-SNAPSHOT' 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | test { 13 | useTestNG() 14 | } 15 | 16 | dependencies { 17 | compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59' 18 | compile group: 'com.github.webdriverextensions', name: 'webdriverextensions', version: '3.11.2' 19 | compile group: 'org.testng', name: 'testng', version: '7.1.0' 20 | compile group : 'io.github.bonigarcia', name: 'webdrivermanager', version: '4.4.0' 21 | } 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sudharsan-selvaraj/pageobject-examples/c5d256b9f45ba0883f01b01e01ce12fa91d6ef63/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Apr 11 12:44:21 IST 2021 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /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 | 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 | # Determine the Java command to use to start the JVM. 86 | if [ -n "$JAVA_HOME" ] ; then 87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 88 | # IBM's JDK on AIX uses strange locations for the executables 89 | JAVACMD="$JAVA_HOME/jre/sh/java" 90 | else 91 | JAVACMD="$JAVA_HOME/bin/java" 92 | fi 93 | if [ ! -x "$JAVACMD" ] ; then 94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 95 | 96 | Please set the JAVA_HOME variable in your environment to match the 97 | location of your Java installation." 98 | fi 99 | else 100 | JAVACMD="java" 101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 102 | 103 | Please set the JAVA_HOME variable in your environment to match the 104 | location of your Java installation." 105 | fi 106 | 107 | # Increase the maximum file descriptors if we can. 108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 109 | MAX_FD_LIMIT=`ulimit -H -n` 110 | if [ $? -eq 0 ] ; then 111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 112 | MAX_FD="$MAX_FD_LIMIT" 113 | fi 114 | ulimit -n $MAX_FD 115 | if [ $? -ne 0 ] ; then 116 | warn "Could not set maximum file descriptor limit: $MAX_FD" 117 | fi 118 | else 119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 120 | fi 121 | fi 122 | 123 | # For Darwin, add options to specify how the application appears in the dock 124 | if $darwin; then 125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 126 | fi 127 | 128 | # For Cygwin or MSYS, switch paths to Windows format before running java 129 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 132 | JAVACMD=`cygpath --unix "$JAVACMD"` 133 | 134 | # We build the pattern for arguments to be converted via cygpath 135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 136 | SEP="" 137 | for dir in $ROOTDIRSRAW ; do 138 | ROOTDIRS="$ROOTDIRS$SEP$dir" 139 | SEP="|" 140 | done 141 | OURCYGPATTERN="(^($ROOTDIRS))" 142 | # Add a user-defined pattern to the cygpath arguments 143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 145 | fi 146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 147 | i=0 148 | for arg in "$@" ; do 149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 151 | 152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 154 | else 155 | eval `echo args$i`="\"$arg\"" 156 | fi 157 | i=`expr $i + 1` 158 | done 159 | case $i in 160 | 0) set -- ;; 161 | 1) set -- "$args0" ;; 162 | 2) set -- "$args0" "$args1" ;; 163 | 3) set -- "$args0" "$args1" "$args2" ;; 164 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 165 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 166 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 167 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 168 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 169 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 170 | esac 171 | fi 172 | 173 | # Escape application args 174 | save () { 175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 176 | echo " " 177 | } 178 | APP_ARGS=`save "$@"` 179 | 180 | # Collect all arguments for the java command, following the shell quoting and substitution rules 181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 182 | 183 | exec "$JAVACMD" "$@" 184 | -------------------------------------------------------------------------------- /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 Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 34 | 35 | @rem Find java.exe 36 | if defined JAVA_HOME goto findJavaFromJavaHome 37 | 38 | set JAVA_EXE=java.exe 39 | %JAVA_EXE% -version >NUL 2>&1 40 | if "%ERRORLEVEL%" == "0" goto init 41 | 42 | echo. 43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 44 | echo. 45 | echo Please set the JAVA_HOME variable in your environment to match the 46 | echo location of your Java installation. 47 | 48 | goto fail 49 | 50 | :findJavaFromJavaHome 51 | set JAVA_HOME=%JAVA_HOME:"=% 52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 53 | 54 | if exist "%JAVA_EXE%" goto init 55 | 56 | echo. 57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 58 | echo. 59 | echo Please set the JAVA_HOME variable in your environment to match the 60 | echo location of your Java installation. 61 | 62 | goto fail 63 | 64 | :init 65 | @rem Get command-line arguments, handling Windows variants 66 | 67 | if not "%OS%" == "Windows_NT" goto win9xME_args 68 | 69 | :win9xME_args 70 | @rem Slurp the command line arguments. 71 | set CMD_LINE_ARGS= 72 | set _SKIP=2 73 | 74 | :win9xME_args_slurp 75 | if "x%~1" == "x" goto execute 76 | 77 | set CMD_LINE_ARGS=%* 78 | 79 | :execute 80 | @rem Setup the command line 81 | 82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 83 | 84 | @rem Execute Gradle 85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 86 | 87 | :end 88 | @rem End local scope for the variables with windows NT shell 89 | if "%ERRORLEVEL%"=="0" goto mainEnd 90 | 91 | :fail 92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 93 | rem the _cmd.exe /c_ return code! 94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 95 | exit /b 1 96 | 97 | :mainEnd 98 | if "%OS%"=="Windows_NT" endlocal 99 | 100 | :omega 101 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'page-object-examples' 2 | 3 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/components/header/NavBar.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.components.header; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import org.openqa.selenium.support.FindBy; 5 | 6 | public class NavBar extends BaseWebComponent { 7 | 8 | @FindBy(css = "#nav-search") 9 | private SearchContainer searchContainer; 10 | 11 | 12 | public SearchContainer getSearchContainer() { 13 | return searchContainer; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/components/header/SearchContainer.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.components.header; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | import org.openqa.selenium.support.FindBy; 7 | import org.openqa.selenium.support.ui.Select; 8 | 9 | public class SearchContainer extends BaseWebComponent { 10 | 11 | @FindBy(id = "twotabsearchtextbox") 12 | private WebElement searchInput; 13 | 14 | @FindBy(id = "nav-search-dropdown-card") 15 | private WebElement categoryDropDown; 16 | 17 | 18 | public SearchContainer searchFor(String searchKeyword) { 19 | return searchFor(searchKeyword, null); 20 | } 21 | 22 | public SearchContainer searchFor(String searchKeyword, String category) { 23 | if (category != null) { 24 | selectCategoryFromDropdown(category); 25 | } 26 | 27 | if (searchKeyword != null) { 28 | enterSearchKeyword(searchKeyword, true); 29 | } 30 | return this; 31 | } 32 | 33 | public void pressSearch() { 34 | interactions.pressEnter(searchInput); 35 | } 36 | 37 | private void enterSearchKeyword(String keyword) { 38 | enterSearchKeyword(keyword, false); 39 | } 40 | 41 | private void enterSearchKeyword(String keyword, boolean pressEnter) { 42 | interactions. 43 | clear(searchInput) 44 | .type(searchInput, keyword); 45 | 46 | if(pressEnter) { 47 | pressSearch(); 48 | } 49 | } 50 | 51 | private void selectCategoryFromDropdown(String category) { 52 | interactions.click(categoryDropDown); 53 | new Select(categoryDropDown.findElement(By.id("searchDropdownBox"))).selectByVisibleText(category); 54 | } 55 | 56 | public String getSelectedCategory() { 57 | return new Select(categoryDropDown.findElement(By.id("searchDropdownBox"))).getFirstSelectedOption().getText(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/components/searchfilters/BaseProductFilter.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.components.searchfilters; 2 | 3 | import com.gargoylesoftware.htmlunit.ElementNotFoundException; 4 | import com.testninja.pageobjects.utils.Interactions; 5 | import com.testninja.pageobjects.wrappers.BaseWebComponentFieldDecorator; 6 | import com.testninja.pageobjects.wrappers.ScriptHelper; 7 | import org.openqa.selenium.By; 8 | import org.openqa.selenium.WebDriver; 9 | import org.openqa.selenium.WebElement; 10 | import org.openqa.selenium.support.PageFactory; 11 | 12 | import java.util.List; 13 | 14 | public class BaseProductFilter { 15 | 16 | protected Interactions interactions; 17 | protected WebDriver driver; 18 | private final String filterHeaderValue; 19 | 20 | private static final By seeMoreLink, clearLink; 21 | 22 | static { 23 | seeMoreLink = By.cssSelector("a.s-expander-text"); 24 | clearLink = By.cssSelector(".s-navigation-clear-link"); 25 | } 26 | 27 | public BaseProductFilter(ScriptHelper scriptHelper, String filterHeaderValue) { 28 | this.interactions = scriptHelper.getInteractions(); 29 | this.driver = scriptHelper.getDriver(); 30 | 31 | this.filterHeaderValue = filterHeaderValue; 32 | PageFactory.initElements(new BaseWebComponentFieldDecorator(scriptHelper), this); 33 | } 34 | 35 | public WebElement getChildElement() { 36 | WebElement filterContainer = getFilterContainer(); 37 | return driver.findElement(By.cssSelector("[aria-labelledby='" + filterContainer.getAttribute("id") + "']")); 38 | } 39 | 40 | public boolean isSeeMoreLinkPresent() { 41 | return getChildElement().findElements(seeMoreLink).size() > 0; 42 | } 43 | 44 | public void clickSeeMore() { 45 | List link = getChildElement().findElements(seeMoreLink); 46 | if (link.size() > 0) { 47 | interactions.click(link.get(0)); 48 | } 49 | } 50 | 51 | public boolean isClearLinkPresent() { 52 | return getChildElement().findElements(clearLink).size() > 0; 53 | } 54 | 55 | public void clickClear() { 56 | List clear = getChildElement().findElements(clearLink); 57 | if (clear.size() > 0) { 58 | interactions.click(clear.get(0)); 59 | } 60 | } 61 | 62 | private By getFilterContainerBy() { 63 | return By.xpath(".//*[@id='s-refinements']/descendant::*[starts-with(@id, 'p_') and contains(@id, '-title') and contains(.,'" + filterHeaderValue + "')]"); 64 | } 65 | 66 | public WebElement getFilterContainer() { 67 | return driver 68 | .findElement(getFilterContainerBy()); 69 | } 70 | 71 | public void waitForFilterToAppear() { 72 | interactions.waitHandler.waitForElement(getFilterContainerBy()); 73 | interactions.scrollIntoView(getFilterContainer()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/components/searchfilters/CheckBoxFilter.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.components.searchfilters; 2 | 3 | import com.gargoylesoftware.htmlunit.ElementNotFoundException; 4 | import com.testninja.pageobjects.wrappers.ScriptHelper; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | public class CheckBoxFilter extends BaseProductFilter { 12 | 13 | private boolean isOptionAnImage = false; 14 | 15 | public CheckBoxFilter(ScriptHelper scriptHelper, 16 | String filterHeader) { 17 | super(scriptHelper, filterHeader); 18 | } 19 | 20 | public CheckBoxFilter(ScriptHelper scriptHelper, 21 | String filterHeader, 22 | boolean isOptionAnImage) { 23 | super(scriptHelper, filterHeader); 24 | this.isOptionAnImage = isOptionAnImage; 25 | } 26 | 27 | public void apply(List optionsToSelect) { 28 | optionsToSelect 29 | .stream() 30 | .forEach(option -> { 31 | waitForFilterToAppear(); 32 | clickSeeMore(); 33 | selectOption(getOptionCheckbox(option)); 34 | }); 35 | } 36 | 37 | public List getSelectedOptions() { 38 | waitForFilterToAppear(); 39 | clickSeeMore(); 40 | 41 | return getChildElement() 42 | .findElements(By.xpath(".//li/descendant::a[.//input[@type='checkbox'][@checked]]/descendant::span")) 43 | .stream() 44 | .map(interactions::getText) 45 | .filter(text -> !text.trim().equals("")) 46 | .collect(Collectors.toList()); 47 | 48 | } 49 | 50 | private void selectOption(WebElement element) { 51 | if (!interactions.isSelected(element)) { 52 | interactions.javaScriptClick(element); 53 | } 54 | } 55 | 56 | private void deselectOption(WebElement element) { 57 | if (interactions.isSelected(element)) { 58 | interactions.click(element); 59 | } 60 | } 61 | 62 | private WebElement getOptionCheckbox(String label) { 63 | if (isOptionAnImage) { 64 | return getChildElement().findElement(By.xpath(".//li/descendant::a[.//span[aria-label='" + label + "']]/descendant::input[@type='checkbox']")); 65 | } else { 66 | return getChildElement().findElement(By.xpath(".//li/descendant::a[.//span[text()='" + label + "']]/descendant::input[@type='checkbox']")); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/components/searchfilters/MultiChoiceButtonFilter.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.components.searchfilters; 2 | 3 | import com.testninja.pageobjects.wrappers.ScriptHelper; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | public class MultiChoiceButtonFilter extends BaseProductFilter { 11 | 12 | public MultiChoiceButtonFilter(ScriptHelper scriptHelper, 13 | String filterHeader) { 14 | super(scriptHelper, filterHeader); 15 | } 16 | 17 | public void apply(List optionsToSelect) { 18 | optionsToSelect 19 | .stream() 20 | .forEach(option -> { 21 | waitForFilterToAppear(); 22 | selectOption(getOptionButton(option)); 23 | }); 24 | } 25 | 26 | public List getSelectedOptions() { 27 | waitForFilterToAppear(); 28 | clickSeeMore(); 29 | 30 | return getChildElement() 31 | .findElements(By.xpath(".//li/descendant::*[contains(@class, 'a-button-selected')]")) 32 | .stream() 33 | .map(interactions::getText) 34 | .filter(text -> !text.trim().equals("")) 35 | .collect(Collectors.toList()); 36 | 37 | } 38 | 39 | private void selectOption(WebElement element) { 40 | if (!interactions.isSelected(element)) { 41 | clickSeeMore(); 42 | interactions.javaScriptClick(element); 43 | } 44 | } 45 | 46 | private void deselectOption(WebElement element) { 47 | if (interactions.isSelected(element)) { 48 | interactions.click(element); 49 | } 50 | } 51 | 52 | private WebElement getOptionButton(String label) { 53 | return getChildElement().findElement(By.xpath(".//li/descendant::button/span[.='"+ label +"']")); 54 | } 55 | 56 | private void isSelected() { 57 | 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/components/searchfilters/PriceRangeFilter.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.components.searchfilters; 2 | 3 | import com.testninja.pageobjects.wrappers.ScriptHelper; 4 | import org.openqa.selenium.By; 5 | import org.openqa.selenium.WebElement; 6 | 7 | public class PriceRangeFilter extends BaseProductFilter { 8 | 9 | public PriceRangeFilter(ScriptHelper scriptHelper) { 10 | super(scriptHelper, "Price"); 11 | } 12 | 13 | public void apply(String lowPrice, String highPrice) { 14 | waitForFilterToAppear(); 15 | interactions.clearAndType(getLowPriceInput(), lowPrice) 16 | .clearAndType(getHighPriceInput(), highPrice) 17 | .click(getSubmitButton()); 18 | 19 | } 20 | 21 | private WebElement getLowPriceInput() { 22 | return getChildElement().findElement(By.id("low-price")); 23 | } 24 | 25 | private WebElement getHighPriceInput() { 26 | return getChildElement().findElement(By.id("high-price")); 27 | } 28 | 29 | private WebElement getSubmitButton() { 30 | return getChildElement().findElement(By.xpath(".//input[@type='submit']")); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/pages/AmazonBasePage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.pages; 2 | 3 | import com.testninja.pageobjects.examples.amazon.components.header.NavBar; 4 | import com.testninja.pageobjects.wrappers.BasePage; 5 | import com.testninja.pageobjects.wrappers.ScriptHelper; 6 | import com.testninja.pageobjects.wrappers.annotations.Page; 7 | import org.openqa.selenium.support.FindBy; 8 | 9 | @Page 10 | public class AmazonBasePage extends BasePage { 11 | 12 | @FindBy(id = "navbar") 13 | private NavBar navBar; 14 | 15 | public AmazonBasePage(ScriptHelper scriptHelper) { 16 | super(scriptHelper); 17 | } 18 | 19 | public void searchProduct(String productName) { 20 | searchProduct(productName, null); 21 | } 22 | 23 | public void searchProduct(String productName, String productCategory) { 24 | navBar.getSearchContainer() 25 | .searchFor(productName, productCategory); 26 | } 27 | 28 | public void changeCategory(String category) { 29 | if(category == null) { 30 | category = "All Categories"; 31 | } 32 | navBar.getSearchContainer() 33 | .searchFor(null, category) 34 | .pressSearch(); 35 | 36 | } 37 | 38 | public void resetCategory() { 39 | changeCategory(null); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.pages; 2 | 3 | import com.testninja.pageobjects.wrappers.ScriptHelper; 4 | import com.testninja.pageobjects.wrappers.annotations.Page; 5 | 6 | @Page 7 | public class HomePage extends AmazonBasePage { 8 | 9 | public HomePage(ScriptHelper scriptHelper) { 10 | super(scriptHelper); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/amazon/pages/SearchResultsPage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.amazon.pages; 2 | 3 | import com.testninja.pageobjects.examples.amazon.components.searchfilters.CheckBoxFilter; 4 | import com.testninja.pageobjects.examples.amazon.components.searchfilters.PriceRangeFilter; 5 | import com.testninja.pageobjects.wrappers.ScriptHelper; 6 | import com.testninja.pageobjects.wrappers.annotations.Page; 7 | 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | @Page 12 | public class SearchResultsPage extends AmazonBasePage { 13 | 14 | public SearchResultsPage(ScriptHelper scriptHelper) { 15 | super(scriptHelper); 16 | } 17 | 18 | public CheckBoxFilter applyPrimeFilter() { 19 | CheckBoxFilter filter = new CheckBoxFilter(scriptHelper, "Amazon Prime", true); 20 | filter.apply(Arrays.asList("Prime Eligible")); 21 | return filter; 22 | } 23 | 24 | public CheckBoxFilter applyBrandFilter(List brands) { 25 | CheckBoxFilter filter = new CheckBoxFilter(scriptHelper, "Brand"); 26 | filter.apply(brands); 27 | return filter; 28 | } 29 | 30 | public PriceRangeFilter applyPriceFilter(String minPrice, String maxPrice) { 31 | PriceRangeFilter filter = new PriceRangeFilter(scriptHelper); 32 | filter.apply(minPrice, maxPrice); 33 | return filter; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/components/Header.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.components; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import com.testninja.pageobjects.wrappers.ScriptHelper; 5 | import org.openqa.selenium.By; 6 | 7 | public class Header extends BaseWebComponent { 8 | 9 | public void clickLogin() { 10 | interactions.click(findElement(getChildByTestId("login-button"))); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/components/LeftNavBar.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.components; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import org.openqa.selenium.By; 5 | 6 | public class LeftNavBar extends BaseWebComponent { 7 | 8 | public void clickHome() { 9 | clickMenu("Home"); 10 | } 11 | 12 | public void clickSearch() { 13 | clickMenu("Search"); 14 | } 15 | 16 | public void clickYourLibrary() { 17 | clickMenu("Your Library"); 18 | } 19 | 20 | private void clickMenu(String menuTitle) { 21 | interactions.click(findElement(By.linkText(menuTitle))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/components/Player.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.components; 2 | 3 | import com.testninja.pageobjects.examples.spotify.components.playlist.PlayButton; 4 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 5 | import org.openqa.selenium.support.FindBy; 6 | 7 | import java.util.List; 8 | import java.util.stream.Collectors; 9 | 10 | public class Player extends BaseWebComponent { 11 | 12 | @FindBy(xpath = ".//button[@data-testid='control-button-play' or @data-testid='control-button-pause']") 13 | private PlayButton playButton; 14 | 15 | public String getSongName() { 16 | return interactions.getText(findElement(getChildByTestId("nowplaying-track-link"))); 17 | } 18 | 19 | public List getArtists() { 20 | return findElements(getChildByTestId("nowplaying-artist")) 21 | .stream() 22 | .map(interactions::getText) 23 | .collect(Collectors.toList()); 24 | } 25 | 26 | public boolean isPlaying() { 27 | return playButton.isPlaying(); 28 | } 29 | 30 | public boolean isPaused() { 31 | return playButton.isPaused(); 32 | } 33 | 34 | public void play() { 35 | playButton.play(); 36 | } 37 | 38 | public void pause() { 39 | playButton.pause(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/components/playlist/PlayButton.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.components.playlist; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import com.testninja.pageobjects.wrappers.ScriptHelper; 5 | 6 | public class PlayButton extends BaseWebComponent { 7 | 8 | public void play() { 9 | if (!isPlaying()) { 10 | interactions.click(this); 11 | } 12 | } 13 | 14 | public void pause() { 15 | if (isPlaying()) { 16 | interactions.click(this); 17 | } 18 | } 19 | 20 | public boolean isPlaying() { 21 | return checkState("Pause"); 22 | } 23 | 24 | public boolean isPaused() { 25 | return checkState("Play"); 26 | } 27 | 28 | private boolean checkState(String state) { 29 | return getAttribute("aria-label").equals(state); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/components/playlist/SaveButton.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.components.playlist; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import com.testninja.pageobjects.wrappers.ScriptHelper; 5 | 6 | public class SaveButton extends BaseWebComponent { 7 | 8 | public boolean isSaved() { 9 | return checkState("Save to Your Library"); 10 | } 11 | 12 | public void clickSave() { 13 | if (!isSaved()) { 14 | interactions.click(getWrappedWebElement()); 15 | } 16 | } 17 | 18 | private boolean checkState(String state) { 19 | return getAttribute("aria-label").equals(state); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/components/playlist/SongRow.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.components.playlist; 2 | 3 | import com.testninja.pageobjects.wrappers.BaseWebComponent; 4 | import com.testninja.pageobjects.wrappers.ScriptHelper; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebElement; 7 | 8 | import java.util.List; 9 | import java.util.stream.Collectors; 10 | 11 | public class SongRow extends BaseWebComponent { 12 | 13 | public String getRowNumber() { 14 | return interactions.getText(getColumn(1)); 15 | } 16 | 17 | public String getSongName() { 18 | return interactions.getText(getColumn(2).findElement(By.cssSelector("[as=\"div\"]"))); 19 | } 20 | 21 | public List getArtists() { 22 | return getColumn(2) 23 | .findElements(By.xpath(".//span/a")) 24 | .stream() 25 | .map(interactions::getText) 26 | .collect(Collectors.toList()); 27 | } 28 | 29 | public String getAlbum() { 30 | return interactions.getText(getColumn(3)); 31 | } 32 | 33 | public String getDateAdded() { 34 | return interactions.getText(getColumn(4)); 35 | } 36 | 37 | public String getDuration() { 38 | return interactions.getText(getColumn(5)); 39 | } 40 | 41 | public void playAndPause() { 42 | play(); 43 | play(); 44 | } 45 | 46 | public void play() { 47 | WebElement playIcon = getColumn(1); 48 | interactions.mouseHover(playIcon).click(playIcon); 49 | } 50 | 51 | private WebElement getColumn(Integer index) { 52 | return findElement(By.xpath(".//div[" + index + "]")); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/pages/LoginPage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.pages; 2 | 3 | import com.testninja.pageobjects.wrappers.BasePage; 4 | import com.testninja.pageobjects.wrappers.ScriptHelper; 5 | import com.testninja.pageobjects.wrappers.annotations.Page; 6 | import org.openqa.selenium.WebElement; 7 | import org.openqa.selenium.support.FindBy; 8 | 9 | @Page 10 | public class LoginPage extends BasePage { 11 | 12 | @FindBy(css = "[ng-model=\"form.username\"]") 13 | private WebElement emailInput; 14 | 15 | @FindBy(css = "[ng-model=\"form.password\"]") 16 | private WebElement passwordInput; 17 | 18 | @FindBy(id = "login-button") 19 | private WebElement loginButton; 20 | 21 | public LoginPage(ScriptHelper scriptHelper) { 22 | super(scriptHelper); 23 | } 24 | 25 | public void loginWithEmail(String email, String password) { 26 | interactions.clearAndType(emailInput, email) 27 | .clearAndType(passwordInput, password) 28 | .click(loginButton); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/pages/PlaylistPage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.pages; 2 | 3 | import com.testninja.pageobjects.examples.spotify.components.playlist.PlayButton; 4 | import com.testninja.pageobjects.examples.spotify.components.playlist.SaveButton; 5 | import com.testninja.pageobjects.examples.spotify.components.playlist.SongRow; 6 | import com.testninja.pageobjects.wrappers.ScriptHelper; 7 | import com.testninja.pageobjects.wrappers.annotations.Page; 8 | import org.apache.xpath.operations.Bool; 9 | import org.checkerframework.checker.nullness.compatqual.NullableDecl; 10 | import org.openqa.selenium.WebDriver; 11 | import org.openqa.selenium.WebElement; 12 | import org.openqa.selenium.support.FindBy; 13 | import org.openqa.selenium.support.ui.ExpectedCondition; 14 | 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | @Page 19 | public class PlaylistPage extends SpotifyBasePage { 20 | 21 | @FindBy(css = "[data-testid=\"action-bar-row\"] > [data-testid='play-button']") 22 | private PlayButton playButton; 23 | 24 | @FindBy(xpath = ".//*=[@data-testid='action-bar-row']/button[2]") 25 | private SaveButton saveButton; 26 | 27 | @FindBy(css = "[data-testid='tracklist-row']") 28 | private List songRows; 29 | 30 | @FindBy(xpath = ".//span/h1") 31 | private WebElement playlistName; 32 | 33 | public PlaylistPage(ScriptHelper scriptHelper) { 34 | super(scriptHelper); 35 | } 36 | 37 | public void waitForPageLoad() { 38 | interactions.waitHandler.waitFor(new ExpectedCondition() { 39 | @Override 40 | public Boolean apply(@NullableDecl WebDriver input) { 41 | return getSongs().size() > 0; 42 | } 43 | }); 44 | } 45 | 46 | public String getPlaylistName() { 47 | return interactions.getText(playlistName); 48 | } 49 | 50 | public PlaylistPage play() { 51 | playButton.play(); 52 | return this; 53 | } 54 | 55 | public PlaylistPage playAndWait() { 56 | play(); 57 | interactions.waitHandler.waitFor(new ExpectedCondition() { 58 | @Override 59 | public Boolean apply(@NullableDecl WebDriver input) { 60 | return isSongPlaying(); 61 | } 62 | }); 63 | return this; 64 | } 65 | 66 | public boolean isSongPlaying() { 67 | return playButton.isPlaying(); 68 | } 69 | 70 | public boolean isSongPaused() { 71 | return playButton.isPaused(); 72 | } 73 | 74 | public PlaylistPage saveToFavourites() { 75 | saveButton.clickSave(); 76 | return this; 77 | } 78 | 79 | public boolean isSavedToFavourites() { 80 | return saveButton.isSaved(); 81 | } 82 | 83 | public SongRow findSongByName(String name) { 84 | return getSongs() 85 | .stream() 86 | .filter(song -> song.getSongName().equals(name)) 87 | .findFirst() 88 | .get(); 89 | 90 | } 91 | 92 | public SongRow findSongByIndex(Integer index) { 93 | return getSongs().get(index); 94 | } 95 | 96 | private List getSongs() { 97 | return songRows 98 | .stream() 99 | .map(song -> { 100 | song.setScriptHelper(scriptHelper); 101 | return song; 102 | }).collect(Collectors.toList()); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/pages/SpotifyBasePage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.pages; 2 | 3 | import com.testninja.pageobjects.examples.spotify.components.Header; 4 | import com.testninja.pageobjects.examples.spotify.components.LeftNavBar; 5 | import com.testninja.pageobjects.examples.spotify.components.Player; 6 | import com.testninja.pageobjects.wrappers.BasePage; 7 | import com.testninja.pageobjects.wrappers.ScriptHelper; 8 | import com.testninja.pageobjects.wrappers.annotations.Page; 9 | import com.testninja.pageobjects.wrappers.annotations.PageObject; 10 | import org.openqa.selenium.support.FindBy; 11 | 12 | @Page 13 | public class SpotifyBasePage extends BasePage { 14 | 15 | @FindBy(css = ".Root__nav-bar") 16 | private LeftNavBar navBar; 17 | 18 | @FindBy(css = ".Root__top-bar") 19 | private Header header; 20 | 21 | @FindBy(css = ".Root__now-playing-bar") 22 | private Player player; 23 | 24 | @PageObject 25 | private LoginPage loginPage; 26 | 27 | public SpotifyBasePage(ScriptHelper scriptHelper) { 28 | super(scriptHelper); 29 | } 30 | 31 | public void loginWithCredentials(String email, String password) { 32 | header.clickLogin(); 33 | loginPage.loginWithEmail(email, password); 34 | interactions.waitHandler.waitForElementToBePresent(header); 35 | } 36 | 37 | public Player getPlayer() { 38 | return player; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/examples/spotify/pages/SpotifyHomePage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.examples.spotify.pages; 2 | 3 | import com.testninja.pageobjects.wrappers.ScriptHelper; 4 | import com.testninja.pageobjects.wrappers.annotations.Page; 5 | 6 | @Page 7 | public class SpotifyHomePage extends SpotifyBasePage { 8 | 9 | public SpotifyHomePage(ScriptHelper scriptHelper) { 10 | super(scriptHelper); 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/utils/Interactions.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.utils; 2 | 3 | import org.openqa.selenium.*; 4 | import org.openqa.selenium.interactions.Actions; 5 | 6 | import java.awt.*; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class Interactions { 11 | 12 | WebDriver driver; 13 | public WaitHandler waitHandler; 14 | 15 | public Interactions(WebDriver driver) { 16 | this.driver = driver; 17 | waitHandler = new WaitHandler(driver); 18 | } 19 | 20 | public void refreshBrowser() { 21 | driver.navigate().refresh(); 22 | 23 | } 24 | 25 | public void open(String url) { 26 | driver.navigate().to(url); 27 | 28 | } 29 | 30 | public Interactions mouseHover(WebElement element) { 31 | 32 | waitHandler.waitForElementToBePresent(element); 33 | new Actions(driver).moveToElement(element).moveToElement(element).build().perform(); 34 | return this; 35 | } 36 | 37 | public Interactions mouseHover(WebElement element, int xOffset, int yOffset) { 38 | 39 | waitHandler.waitForElementToBePresent(element); 40 | new Actions(driver).moveToElement(element, xOffset, yOffset).build().perform(); 41 | return this; 42 | } 43 | 44 | public Interactions mouseHoverOnInvisibleElement(WebElement element) { 45 | 46 | new Actions(driver).moveToElement(element).perform(); 47 | return this; 48 | } 49 | 50 | public Interactions click(WebElement element) { 51 | waitHandler.waitForElementToBeClickable(element); 52 | element.click(); 53 | 54 | return this; 55 | } 56 | 57 | public Interactions selectMultipleOption(List elements) { 58 | Actions actions = new Actions(driver); 59 | actions.keyDown(Keys.CONTROL); 60 | for (WebElement element: elements) { 61 | actions.click(element); 62 | } 63 | actions.keyDown(Keys.CONTROL) 64 | .build() 65 | .perform(); 66 | 67 | return this; 68 | } 69 | public Interactions mouseClick(WebElement element) { 70 | waitHandler.waitForElementToDisplay(element); 71 | new Actions(driver).moveToElement(element).click().build().perform(); 72 | 73 | return this; 74 | } 75 | 76 | public Interactions mouseClickOnInvisibleElement(WebElement element) { 77 | new Actions(driver).moveToElement(element).click().perform(); 78 | 79 | return this; 80 | } 81 | 82 | public Interactions mouseSet(WebElement element, String text) { 83 | new Actions(driver).sendKeys(element, text).perform(); 84 | return this; 85 | } 86 | 87 | public Interactions javaScriptClick(WebElement element) { 88 | waitHandler.waitForElementToDisplay(element); 89 | executeScript("arguments[0].click()", element); 90 | 91 | return this; 92 | } 93 | 94 | public Interactions javaScriptClear(WebElement element) { 95 | executeScript("arguments[0].value=arguments[1]", element, ""); 96 | 97 | return this; 98 | } 99 | 100 | public Interactions javaScriptType(WebElement element, String text) { 101 | executeScript("arguments[0].value=arguments[1]", element, text); 102 | 103 | return this; 104 | } 105 | 106 | public Interactions javaScriptClearAndType(WebElement element, String text) { 107 | javaScriptClear(element).javaScriptType(element, text); 108 | return this; 109 | } 110 | 111 | public void doubleClick(WebElement element) { 112 | waitHandler.waitForElementToDisplay(element); 113 | new Actions(driver).moveToElement(element).doubleClick().perform(); 114 | 115 | } 116 | 117 | public void dragAndDrop(WebElement source, WebElement destination) { 118 | waitHandler.waitForElementToBeClickable(source); 119 | waitHandler.waitForElementToBeClickable(destination); 120 | new Actions(driver).clickAndHold(source).moveToElement(destination).release().perform(); 121 | } 122 | 123 | public void dragAndDropOnInVisibleElement(WebElement source, WebElement destination) { 124 | new Actions(driver).clickAndHold(source).moveToElement(destination).release().perform(); 125 | } 126 | 127 | public void dragAndDropBy(WebElement source, int x, int y) { 128 | waitHandler.waitForElementToBeClickable(source); 129 | new Actions(driver).dragAndDropBy(source, x, y).build().perform(); 130 | } 131 | 132 | public void rightClick(WebElement element) { 133 | waitHandler.waitForElementToBeClickable(element); 134 | new Actions(driver).moveToElement(element).contextClick().perform(); 135 | } 136 | 137 | public void type(WebElement element, String text) { 138 | if (text == null) { 139 | return; 140 | } 141 | element.sendKeys(text); 142 | } 143 | 144 | public void type(WebElement element, String[] text) { 145 | if (text == null) { 146 | return; 147 | } 148 | for (String val : text) { 149 | element.sendKeys(val); 150 | element.sendKeys(Keys.TAB); 151 | } 152 | } 153 | 154 | public void type(WebElement element, List text) { 155 | if (text == null) { 156 | return; 157 | } 158 | for (String val : text) { 159 | element.sendKeys(val); 160 | element.sendKeys(Keys.TAB); 161 | } 162 | } 163 | 164 | public void type(WebElement webElement, double number) { 165 | type(webElement, Double.toString(number)); 166 | } 167 | 168 | public Interactions clear(WebElement element) { 169 | element.clear(); 170 | return this; 171 | } 172 | 173 | public Interactions clearAndType(WebElement webElement, String text) { 174 | waitHandler.waitForElementToBeClickable(webElement); 175 | clear(webElement); 176 | type(webElement, text); 177 | return this; 178 | } 179 | 180 | public Interactions switchToFrameByIndex(Integer index) { 181 | 182 | driver.switchTo().frame(index); 183 | return this; 184 | } 185 | 186 | public Interactions switchToDefaultContent() { 187 | driver.switchTo().defaultContent(); 188 | return this; 189 | } 190 | public Interactions typeAndEnter(WebElement webElement, String text) { 191 | waitHandler.waitForElementToBeClickable(webElement); 192 | clear(webElement); 193 | type(webElement, text); 194 | pressEnter(webElement); 195 | return this; 196 | } 197 | 198 | public void clearAndType(WebElement webElement, String[] text) { 199 | clear(webElement); 200 | type(webElement, text); 201 | } 202 | 203 | public void clearAndType(WebElement webElement, double number) { 204 | clear(webElement); 205 | type(webElement, number); 206 | } 207 | 208 | public void pressEnter(WebElement webElement) { 209 | pressKeys(webElement, Keys.ENTER); 210 | } 211 | 212 | public void pressDelete(WebElement element, int noOfTimes) { 213 | for (int i = 0; i < noOfTimes; i++) { 214 | pressKeys(element, Keys.BACK_SPACE); 215 | } 216 | } 217 | 218 | public void pressKeys(WebElement element, CharSequence... keys) { 219 | waitHandler.waitForElementToBeClickable(element); 220 | element.sendKeys(keys); 221 | 222 | } 223 | 224 | /* Select/Deselect */ 225 | public void select(WebElement webElement) { 226 | if (!isSelected(webElement)) { 227 | webElement.click(); 228 | } 229 | } 230 | 231 | public void deselect(WebElement webElement) { 232 | if (isSelected(webElement)) { 233 | webElement.click(); 234 | } 235 | } 236 | 237 | 238 | public void executeScript(String script) { 239 | ((JavascriptExecutor) driver).executeScript(script); 240 | } 241 | 242 | public Object executeScript(String script, Object... args) { 243 | return ((JavascriptExecutor) driver).executeScript(script, args); 244 | } 245 | 246 | public Interactions scrollIntoView(WebElement element) { 247 | ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView();", element); 248 | return this; 249 | } 250 | 251 | public Interactions removeTableRowVirtualization() { 252 | ((JavascriptExecutor) driver).executeScript("$.fn.visible = function () {return true};"); 253 | return this; 254 | } 255 | 256 | public void scrollIntoViewAndClick(WebElement element) { 257 | ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(); arguments[0].click()", element); 258 | } 259 | 260 | public void scrollIntoViewRelativeAndClick(WebElement element) { 261 | ((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView({block: \"end\"}); arguments[0].click()", element); 262 | } 263 | 264 | public boolean isSelected(WebElement webElement) { 265 | return webElement.isSelected(); 266 | } 267 | 268 | /* Enabled/Disabled */ 269 | public boolean isEnabled(WebElement webElement) { 270 | return webElement.isEnabled(); 271 | } 272 | 273 | public boolean isDisabled(WebElement webElement) { 274 | return !isEnabled(webElement); 275 | } 276 | 277 | /* get values*/ 278 | 279 | public String getText(WebElement webElement) { 280 | waitHandler.waitForElementToBePresent(webElement); 281 | return webElement.getText(); 282 | } 283 | 284 | public List getText(List webElements) { 285 | List listOfTexts = new ArrayList<>(); 286 | for (WebElement webElement : webElements) { 287 | //waitHandler.waitForElementToDisplay(webElement); 288 | String text = webElement.getText(); 289 | if(!text.equals("")) 290 | listOfTexts.add(text); 291 | } 292 | return listOfTexts; 293 | } 294 | 295 | public String getTextFieldValue(WebElement webElement) { 296 | return getAttribute(webElement, "value"); 297 | } 298 | 299 | public String getAttribute(WebElement webElement, String attributeName) { 300 | return webElement.getAttribute(attributeName); 301 | } 302 | 303 | public Integer getIndex(List lisOfWebElements, String headerName) { 304 | return getText(lisOfWebElements).indexOf(headerName); 305 | } 306 | 307 | 308 | /* Js Methods*/ 309 | 310 | public Interactions tabOut(WebElement element) { 311 | this.click(element).pressKeys(element, Keys.TAB); 312 | return this; 313 | } 314 | 315 | public String getCssValue(WebElement webElement, String propertyName) { 316 | waitHandler.waitForElementToDisplay(webElement); 317 | return webElement.getCssValue(propertyName); 318 | } 319 | 320 | public Interactions toggleCheckBox(WebElement element, Boolean selectionState) { 321 | Boolean checkBoxAlreadySelected = element.isSelected(); 322 | if (checkBoxAlreadySelected != selectionState) { 323 | waitHandler.waitForElementToBePresent(element); 324 | // interaction.click() is not working in permission panel. 325 | element.click(); 326 | //this.mouseClick(element); 327 | } 328 | return this; 329 | } 330 | 331 | public String formatDate(String utcDate) { 332 | if (utcDate == null) { 333 | return "-"; 334 | } 335 | return (String) executeScript("return moment(new Date(arguments[0])).format('MMM D, YYYY | h:mm a')", utcDate); 336 | } 337 | 338 | public String getBorderColor (WebElement element) { 339 | return getCssValue(element, "border-bottom-color"); 340 | } 341 | 342 | public String getBorderColorHexCode(WebElement element) { 343 | return getColorHexCode(getBorderColor(element)); 344 | } 345 | 346 | public String getComputedBackgroundColor(WebElement element) { 347 | return executeScript("return window.getComputedStyle(arguments[0],':before').getPropertyValue('background-color')", element).toString(); 348 | } 349 | 350 | public String getBackgroundColorHexCode(WebElement element) { 351 | return getColorHexCode(getComputedBackgroundColor(element)); 352 | } 353 | 354 | private String getColorHexCode(String RgbColor) { 355 | String[] rgb = RgbColor.replace("rgba(", "").replace(")", "").replace("rgb(", "").split(","); 356 | Color c = new Color(Integer.valueOf(rgb[0].trim()), Integer.valueOf(rgb[1].trim()), Integer.valueOf(rgb[2].trim())); 357 | return "#"+ Integer.toHexString(c.getRGB() & 0xffffff); 358 | } 359 | 360 | } 361 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/utils/WaitHandler.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.utils; 2 | 3 | import org.openqa.selenium.*; 4 | import org.openqa.selenium.support.ui.ExpectedCondition; 5 | import org.openqa.selenium.support.ui.ExpectedConditions; 6 | import org.openqa.selenium.support.ui.WebDriverWait; 7 | 8 | import java.util.List; 9 | 10 | public class WaitHandler { 11 | 12 | WebDriver driver; 13 | private int defaultWaitTime = 20; 14 | 15 | public WaitHandler(WebDriver driver) { 16 | this.driver = driver; 17 | } 18 | 19 | public void waitFor(ExpectedCondition condition) { 20 | new WebDriverWait(driver, defaultWaitTime).until(condition); 21 | } 22 | 23 | public WebElement waitForElementToDisplay(WebElement webElement) { 24 | return waitForElementToDisplay(webElement, defaultWaitTime); 25 | } 26 | 27 | public WebElement waitForElementToDisplay(WebElement webElement, long waitTime) { 28 | return new WebDriverWait(driver, waitTime).until(ExpectedConditions.visibilityOf(webElement)); 29 | } 30 | 31 | 32 | public void waitForElementToBeClickable(WebElement webElement) { 33 | waitForElementToBeClickable(webElement, defaultWaitTime); 34 | } 35 | 36 | public void waitForElementToBeClickable(WebElement webElement, long waitTime) { 37 | new WebDriverWait(driver, waitTime).until(ExpectedConditions.elementToBeClickable(webElement)); 38 | } 39 | 40 | public void waitForElementToBePresent(WebElement webElement) { 41 | waitForElementToBePresent(webElement, defaultWaitTime); 42 | } 43 | 44 | public void waitForElementToBePresent(WebElement webElement, long waitTime) { 45 | new WebDriverWait(driver, waitTime).until(new ExpectedCondition() { 46 | @Override 47 | public WebElement apply(WebDriver driver) { 48 | try { 49 | webElement.isDisplayed(); 50 | return webElement; 51 | } catch (NoSuchElementException e) { 52 | return null; 53 | } 54 | } 55 | }); 56 | } 57 | 58 | public List waitForElementsToDisplay(List webElements) { 59 | return waitForElementsToDisplay((List) webElements, defaultWaitTime); 60 | } 61 | 62 | public void waitForElement(By locator) { 63 | for (int i = 0; i < defaultWaitTime; i++) { 64 | try { 65 | driver.findElement(locator).isDisplayed(); 66 | return; 67 | } catch (Exception e) { 68 | sleep(1000); 69 | } 70 | } 71 | } 72 | 73 | public List waitForElementsToDisplay(List webElements, long waitTime) { 74 | return new WebDriverWait(driver, waitTime).until(ExpectedConditions.visibilityOfAllElements((List) webElements)); 75 | } 76 | 77 | public void waitForPageToLoad() { 78 | waitForPageToLoad(defaultWaitTime); 79 | } 80 | 81 | public void waitForPageToLoad(int seconds) { 82 | try { 83 | new WebDriverWait(driver, seconds).until((WebDriver) -> { 84 | return String.valueOf(executeJavascript("return document.readyState")) 85 | .equals("complete"); 86 | }); 87 | } catch (TimeoutException ex) { 88 | // don't throw if page is still loading. Some pages never 89 | // archive readyState == complete, but are functionaly correct 90 | } 91 | } 92 | 93 | public void sleep(int timeInMilliSeconds) { 94 | executeScriptAsync("var callback = arguments[arguments.length-1]; setTimeout(function(){ callback() }, arguments[0]);", timeInMilliSeconds); 95 | } 96 | 97 | /* Execute Javascript */ 98 | public Object executeJavascript(String script, Object... arguments) { 99 | return ((JavascriptExecutor) driver).executeScript(script, arguments); 100 | } 101 | 102 | public void executeScriptAsync(String script, Object... arguments) { 103 | ((JavascriptExecutor) driver).executeAsyncScript(script, arguments); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/BasePage.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers; 2 | 3 | import com.testninja.pageobjects.utils.Interactions; 4 | import org.openqa.selenium.*; 5 | import org.openqa.selenium.support.PageFactory; 6 | 7 | import java.util.Arrays; 8 | 9 | public class BasePage { 10 | 11 | protected Interactions interactions; 12 | protected WebDriver driver; 13 | protected ScriptHelper scriptHelper; 14 | 15 | public BasePage(ScriptHelper scriptHelper) { 16 | this.scriptHelper = scriptHelper; 17 | this.driver = scriptHelper.getDriver(); 18 | this.interactions = scriptHelper.getInteractions(); 19 | 20 | PageFactory.initElements(new BaseWebComponentFieldDecorator(scriptHelper), this); 21 | PageObjectFactory.init(this, Arrays.asList(new Class[]{ScriptHelper.class}), Arrays.asList(new Object[]{scriptHelper})); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/BaseWebComponent.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers; 2 | 3 | import com.github.webdriverextensions.WebComponent; 4 | import com.testninja.pageobjects.utils.Interactions; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.WebDriver; 7 | import org.openqa.selenium.support.PageFactory; 8 | 9 | public class BaseWebComponent extends WebComponent { 10 | 11 | protected ScriptHelper scriptHelper; 12 | protected Interactions interactions; 13 | 14 | public BaseWebComponent() { 15 | super(); 16 | } 17 | 18 | public BaseWebComponent(ScriptHelper scriptHelper) { 19 | super(); 20 | setScriptHelper(scriptHelper); 21 | } 22 | 23 | public void setScriptHelper(ScriptHelper scriptHelper) { 24 | this.scriptHelper = scriptHelper; 25 | this.interactions = scriptHelper.getInteractions(); 26 | PageFactory.initElements(new BaseWebComponentFieldDecorator(scriptHelper), this); 27 | } 28 | 29 | public WebDriver getDriver() { 30 | return scriptHelper.getDriver(); 31 | } 32 | 33 | protected static By getChildByTestId(String testId) { 34 | return By.cssSelector("[data-testid='" + testId + "']"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/BaseWebComponentFieldDecorator.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers; 2 | 3 | import com.github.webdriverextensions.WebDriverExtensionFieldDecorator; 4 | import org.openqa.selenium.support.pagefactory.FieldDecorator; 5 | 6 | import java.lang.reflect.Field; 7 | 8 | public class BaseWebComponentFieldDecorator implements FieldDecorator { 9 | 10 | private ScriptHelper scriptHelper; 11 | 12 | public BaseWebComponentFieldDecorator(ScriptHelper scriptHelper) { 13 | this.scriptHelper = scriptHelper; 14 | } 15 | 16 | @Override 17 | public Object decorate(ClassLoader loader, Field field) { 18 | Object proxyWebElement = new WebDriverExtensionFieldDecorator(scriptHelper.getDriver()).decorate(loader, field); 19 | 20 | if(proxyWebElement instanceof BaseWebComponent) { 21 | ((BaseWebComponent)proxyWebElement).setScriptHelper(scriptHelper); 22 | } 23 | return proxyWebElement; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/PageObjectFactory.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers; 2 | 3 | import com.testninja.pageobjects.wrappers.annotations.Page; 4 | import com.testninja.pageobjects.wrappers.annotations.PageObject; 5 | 6 | import java.lang.annotation.Annotation; 7 | import java.lang.reflect.Field; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class PageObjectFactory { 12 | 13 | public static void init(Object classObject, 14 | List> constructorParams, 15 | List constructorArguments){ 16 | try { 17 | assignPageObject(classObject, constructorParams, constructorArguments); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | } 21 | } 22 | 23 | private static void assignPageObject(Object classObject, 24 | List> constructorParams, 25 | List constructorArguments) throws Exception { 26 | List pageObjectFields = getPageObjectFields(classObject); 27 | 28 | for (Field f : pageObjectFields) { 29 | Class pageObjectClass = f.getType(); 30 | if (isValidPage(pageObjectClass)) { 31 | initializeFieldValue(pageObjectClass, f, classObject, constructorParams, constructorArguments); 32 | } else { 33 | throw new Exception("Field " + f.getName() + " in class " + f.getDeclaringClass() + "" + 34 | " has invalid page object annotation for type " + pageObjectClass.getName()); 35 | } 36 | } 37 | } 38 | 39 | private static void initializeFieldValue(Class pageObjectTypeClass, 40 | Field field, 41 | Object classObject, 42 | List> constructorParams, 43 | List constructorArguments) throws Exception { 44 | try { 45 | Object newInstance = pageObjectTypeClass 46 | .getConstructor(constructorParams.toArray(new Class[]{})) 47 | .newInstance(constructorArguments.toArray(new Object[]{})); 48 | field.setAccessible(true); 49 | field.set(classObject, newInstance); 50 | } catch (Throwable t) { 51 | t.printStackTrace(); 52 | } 53 | } 54 | 55 | private static List getPageObjectFields(Object classObject) { 56 | Class objectClass = classObject.getClass(); 57 | List pageObjectFields = new ArrayList<>(); 58 | for (Field f : objectClass.getDeclaredFields()) { 59 | if (isPageObjectField(f)) { 60 | pageObjectFields.add(f); 61 | } 62 | } 63 | for (Field f : classObject.getClass().getSuperclass().getDeclaredFields()) { 64 | if (isPageObjectField(f)) { 65 | pageObjectFields.add(f); 66 | } 67 | } 68 | return pageObjectFields; 69 | } 70 | 71 | private static Boolean isValidPage(Class clazz) { 72 | Annotation annotation = clazz.getAnnotation(Page.class); 73 | return annotation != null; 74 | } 75 | 76 | private static Boolean isPageObjectField(Field f) { 77 | Annotation annotation = f.getAnnotation(PageObject.class); 78 | return annotation != null; 79 | } 80 | } -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/ScriptHelper.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers; 2 | 3 | import com.testninja.pageobjects.utils.Interactions; 4 | import org.openqa.selenium.WebDriver; 5 | 6 | /** 7 | * Acts as a holder for commonly used objects across tests and page object classes 8 | * Instance of ScriptHelper will be passed as constructor arguments for page object classes; 9 | */ 10 | 11 | public class ScriptHelper { 12 | 13 | private Interactions interactions; 14 | private WebDriver driver; 15 | 16 | public ScriptHelper(WebDriver driver, 17 | Interactions interactions) { 18 | this.driver = driver; 19 | this.interactions = interactions; 20 | } 21 | 22 | public WebDriver getDriver() { 23 | return driver; 24 | } 25 | 26 | 27 | public Interactions getInteractions() { 28 | return interactions; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/annotations/Page.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.TYPE) 10 | public @interface Page { 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/com/testninja/pageobjects/wrappers/annotations/PageObject.java: -------------------------------------------------------------------------------- 1 | package com.testninja.pageobjects.wrappers.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | @Retention(RetentionPolicy.RUNTIME) 9 | @Target(ElementType.FIELD) 10 | public @interface PageObject { 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/com/testning/pageobjects/examples/amazon/AmazonSearchFiltersTest.java: -------------------------------------------------------------------------------- 1 | package com.testning.pageobjects.examples.amazon; 2 | 3 | import com.testning.pageobjects.wrappers.BaseTest; 4 | import com.testninja.pageobjects.examples.amazon.components.searchfilters.CheckBoxFilter; 5 | import com.testninja.pageobjects.examples.amazon.components.searchfilters.MultiChoiceButtonFilter; 6 | import com.testninja.pageobjects.examples.amazon.pages.HomePage; 7 | import com.testninja.pageobjects.examples.amazon.pages.SearchResultsPage; 8 | import com.testninja.pageobjects.wrappers.annotations.PageObject; 9 | import org.testng.annotations.BeforeMethod; 10 | import org.testng.annotations.Test; 11 | 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | import static org.testng.Assert.*; 17 | 18 | public class AmazonSearchFiltersTest extends BaseTest { 19 | 20 | @PageObject 21 | HomePage amazonHomePage; 22 | 23 | @PageObject 24 | private SearchResultsPage resultsPage; 25 | 26 | @BeforeMethod 27 | public void openAmazon() { 28 | driver.get("https://www.amazon.in"); 29 | amazonHomePage 30 | .searchProduct("shoes"); 31 | } 32 | 33 | 34 | @Test 35 | public void BrandFilterTest() { 36 | List brands = Arrays.asList("Campus"); 37 | CheckBoxFilter brandFilter = new CheckBoxFilter(scriptHelper, "Brand"); 38 | brandFilter.apply(brands); 39 | 40 | assertEquals(brandFilter.getSelectedOptions(), brands); 41 | assertTrue(brandFilter.isClearLinkPresent()); 42 | assertTrue(brandFilter.isSeeMoreLinkPresent()); 43 | } 44 | 45 | @Test 46 | public void MaterialFilterTest() { 47 | List material = Arrays.asList("Canvas", "Rubber"); 48 | CheckBoxFilter materialFilter = new CheckBoxFilter(scriptHelper, "Material"); 49 | materialFilter.apply(material); 50 | 51 | assertEquals(materialFilter.getSelectedOptions(), material); 52 | assertTrue(materialFilter.isClearLinkPresent()); 53 | assertFalse(materialFilter.isSeeMoreLinkPresent()); 54 | 55 | /* 56 | CheckBoxFilter component can be further reused to test some of other below filter types: 57 | 1. Delivery Day 58 | 2. Deals 59 | 3. Material 60 | 4. Shoes Fashion Brands 61 | 5. Running Surface 62 | */ 63 | } 64 | 65 | @Test 66 | public void SizeFilterTest() { 67 | List size = Collections.singletonList("8.5"); 68 | 69 | MultiChoiceButtonFilter sizeFilter = new MultiChoiceButtonFilter(scriptHelper, "Size"); 70 | assertFalse(sizeFilter.isSeeMoreLinkPresent()); 71 | sizeFilter.apply(size); 72 | 73 | assertEquals(sizeFilter.getSelectedOptions(), size); 74 | assertTrue(sizeFilter.isClearLinkPresent()); 75 | assertFalse(sizeFilter.isSeeMoreLinkPresent()); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/test/java/com/testning/pageobjects/examples/spotify/SpotifyPlaylistTest.java: -------------------------------------------------------------------------------- 1 | package com.testning.pageobjects.examples.spotify; 2 | 3 | import com.testning.pageobjects.wrappers.BaseTest; 4 | import com.testninja.pageobjects.examples.spotify.components.Player; 5 | import com.testninja.pageobjects.examples.spotify.components.playlist.SongRow; 6 | import com.testninja.pageobjects.examples.spotify.pages.PlaylistPage; 7 | import com.testninja.pageobjects.examples.spotify.pages.SpotifyHomePage; 8 | import com.testninja.pageobjects.wrappers.annotations.PageObject; 9 | import org.testng.annotations.BeforeClass; 10 | import org.testng.annotations.BeforeMethod; 11 | import org.testng.annotations.Test; 12 | 13 | import java.util.Arrays; 14 | 15 | import static org.testng.Assert.*; 16 | 17 | public class SpotifyPlaylistTest extends BaseTest { 18 | 19 | private static final String playlistUrl, email, password; 20 | 21 | static { 22 | playlistUrl = "https://open.spotify.com/playlist/69Th2qi7qhSDySe6D6XfCl"; 23 | email = "fawogi9556@zcai55.com"; //Test user credentials 😋 24 | password = "fawogi9556"; 25 | } 26 | 27 | @PageObject 28 | SpotifyHomePage spotifyHomePage; 29 | 30 | @PageObject 31 | PlaylistPage playlistPage; 32 | 33 | @BeforeClass 34 | public void loginToSpotify() { 35 | driver.get("https://open.spotify.com"); 36 | spotifyHomePage.loginWithCredentials(email, password); 37 | driver.get(playlistUrl); 38 | playlistPage.waitForPageLoad(); 39 | playlistPage.findSongByIndex(0).playAndPause(); 40 | } 41 | 42 | @BeforeMethod 43 | public void resetPage() { 44 | driver.get(playlistUrl); 45 | playlistPage.waitForPageLoad(); 46 | } 47 | 48 | @Test 49 | public void PlayListPageSongDetailsTest() { 50 | 51 | assertEquals(playlistPage.getPlaylistName(), "Best of The Chainsmokers"); 52 | assertFalse(playlistPage.isSongPlaying()); 53 | 54 | SongRow firstSong = playlistPage.findSongByIndex(0); 55 | 56 | assertEquals(firstSong.getSongName(), "Closer"); 57 | assertEquals(firstSong.getArtists(), Arrays.asList("The Chainsmokers", "Halsey")); 58 | assertEquals(firstSong.getAlbum(), "Closer"); 59 | assertEquals(firstSong.getDateAdded(), "Jan 9, 2017"); 60 | assertEquals(firstSong.getDuration(), "4:04"); 61 | } 62 | 63 | @Test 64 | public void PlayListPageSongPlayTest() { 65 | Player player = spotifyHomePage.getPlayer(); 66 | /* 67 | * Play the song with global playlist play button 68 | * */ 69 | playlistPage.playAndWait(); 70 | assertEquals(player.getSongName(), playlistPage.findSongByIndex(0).getSongName()); 71 | assertTrue(playlistPage.isSongPlaying()); 72 | 73 | /* 74 | * Pause the song using pause button in track player 75 | * */ 76 | player.pause(); 77 | interactions.waitHandler.sleep(1000); 78 | assertTrue(player.isPaused()); 79 | assertFalse(playlistPage.isSongPlaying()); 80 | 81 | /* 82 | * Play the song using play button near the track list. 83 | * */ 84 | playlistPage.findSongByIndex(0).play(); 85 | assertTrue(player.isPlaying()); 86 | assertTrue(playlistPage.isSongPlaying()); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/com/testning/pageobjects/wrappers/BaseTest.java: -------------------------------------------------------------------------------- 1 | package com.testning.pageobjects.wrappers; 2 | 3 | import com.testninja.pageobjects.utils.Interactions; 4 | import com.testninja.pageobjects.wrappers.PageObjectFactory; 5 | import com.testninja.pageobjects.wrappers.ScriptHelper; 6 | import io.github.bonigarcia.wdm.WebDriverManager; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.chrome.ChromeDriver; 9 | import org.testng.annotations.*; 10 | 11 | 12 | import java.util.*; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | public class BaseTest { 16 | 17 | protected WebDriver driver; 18 | 19 | protected Interactions interactions; 20 | protected ScriptHelper scriptHelper; 21 | 22 | @BeforeSuite 23 | public void setupDriver() { 24 | WebDriverManager.chromedriver().setup(); 25 | } 26 | 27 | @BeforeClass 28 | protected void setup() { 29 | try { 30 | driver = new ChromeDriver(); 31 | driver.manage().timeouts().setScriptTimeout(60, TimeUnit.SECONDS); 32 | 33 | interactions = new Interactions(driver); 34 | scriptHelper = new ScriptHelper(driver, interactions); 35 | PageObjectFactory.init(this, Arrays.asList(ScriptHelper.class), Arrays.asList(scriptHelper)); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | } 39 | } 40 | 41 | @AfterClass 42 | protected void tearDownDriver() { 43 | if (driver != null) { 44 | driver.quit(); 45 | } 46 | } 47 | 48 | } 49 | --------------------------------------------------------------------------------