From 1e97217b6267953ba33e0b729f4a03e120f535fc Mon Sep 17 00:00:00 2001 From: Mark Collin Date: Wed, 31 Oct 2018 22:43:42 +0000 Subject: [PATCH] Make API more fluent and flexible Query objects now only throw exceptions when trying to perform an action it cannot perform, this gives you more flexibility when constructing objects Default locator is now optional (useful for Appium where you don't really have a default in some cases) --- .../com/lazerycode/selenium/util/Query.java | 84 ++++++++++++------- .../lazerycode/selenium/util/QueryTest.java | 83 +++++++++++++----- 2 files changed, 115 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/lazerycode/selenium/util/Query.java b/src/main/java/com/lazerycode/selenium/util/Query.java index 45c0842..9b9b2a2 100644 --- a/src/main/java/com/lazerycode/selenium/util/Query.java +++ b/src/main/java/com/lazerycode/selenium/util/Query.java @@ -13,58 +13,70 @@ public class Query { private RemoteWebDriver driver; - private String currentBrowserName; - private boolean isAppium; + private String currentType; + private By defaultLocator; + private HashMap customLocators = new HashMap<>(); + private boolean isAppiumDriver; /** - * Set a static driver object that wil be used for all instances of Query + * Specify a default locator that will be used if a more specific locator cannot be detected. * - * @param driverObject + * @param locator + * @return this */ - public Query initQueryObject(RemoteWebDriver driverObject) { - driver = driverObject; - if (null != driver) { - currentBrowserName = driver.getCapabilities().getBrowserName(); - Object automationName = driver.getCapabilities().getCapability("automationName"); - isAppium = (null != automationName) && automationName.toString().toLowerCase().equals("appium"); - } + public Query defaultLocator(By locator) { + this.defaultLocator = locator; return this; } - private final By defaultLocator; - private HashMap customLocators = new HashMap<>(); - - public Query(By defaultLocator, RemoteWebDriver driver) { - if (null == defaultLocator) throw new NullPointerException("Query locator cannot be null!"); - this.defaultLocator = defaultLocator; - initQueryObject(driver); - } - - public Query(By defaultLocator) { - if (null == defaultLocator) throw new NullPointerException("Query locator cannot be null!"); - this.defaultLocator = defaultLocator; - } - /** * Specify a alternate locator for a specific browser. *

* Any actions that use a By object will examine the `browserName` capability of the current driver, * if it matches what you have specified here this locator will be used instead. *

- * It is Suggested you pass in a org.openqa.selenium.remote.BrowserType field to ensure accuracy, example: + * It is Suggested you pass in a org.openqa.selenium.remote.BrowserType object to ensure accuracy + * (or if you are using Appium a io.appium.java_client.remote.MobileBrowserType, or io.appium.java_client.remoteMobilePlatform), + * examples: *

* Query query = newQuery(By.id("foo"); * query.addAlternateLocator(BrowserType.GOOGLECHROME, By.id("bar"); + * query.addAlternateLocator(MobileBrowserType.BROWSER, By.id("oof"); + * query.addAlternateLocator(MobilePlatform.ANDROID, By.id("rab"); *

* This is intentionally a String for future compatibility. * - * @param browser String value matching a browsername capability + * @param browser String value matching a BrowserType, MobileBrowserType, or MobilePlatform capability * @param locator A By object used for locating webElements */ - public void addAlternateLocator(String browser, By locator) { + public Query addAlternateLocator(String browser, By locator) { customLocators.put(browser, locator); + + return this; + } + + /** + * Specify the driver object that will be used to find elements + * + * @param driverObject + * @return this + */ + public Query usingDriver(RemoteWebDriver driverObject) { + if (null != driverObject) { + driver = driverObject; + Object automationName = driver.getCapabilities().getCapability("automationName"); + isAppiumDriver = (null != automationName) && automationName.toString().toLowerCase().equals("appium"); + currentType = driver.getCapabilities().getBrowserName(); + if (isAppiumDriver && (null == currentType || currentType.isEmpty())) { + currentType = driver.getCapabilities().getPlatform().toString(); + } + } else { + throw new NullPointerException("Driver object is null!"); + } + + return this; } /** @@ -82,7 +94,7 @@ public WebElement findWebElement() { * @return MobileElement */ public MobileElement findMobileElement() { - if (isAppium) { + if (isAppiumDriver) { return (MobileElement) driver.findElement(locator()); } throw new UnsupportedOperationException("You don't seem to be using Appium!"); @@ -103,7 +115,7 @@ public List findWebElements() { * @return List<MobileElement>> */ public List findMobileElements() { - if (isAppium) { + if (isAppiumDriver) { List elementsFound = driver.findElements(locator()); List mobileElementsToReturn = new ArrayList<>(); for (WebElement element : elementsFound) { @@ -131,7 +143,17 @@ public Select findSelectElement() { */ public By locator() { checkDriverIsSet(); - return customLocators.getOrDefault(currentBrowserName, defaultLocator); + By locatorToReturn = customLocators.getOrDefault(currentType, defaultLocator); + + return checkLocatorIsNotNull(locatorToReturn); + } + + private By checkLocatorIsNotNull(By locator) { + if (null == locator) { + throw new IllegalStateException(String.format("Unable to detect valid locator for '%s' and a default locator has not been set!", currentType)); + } + + return locator; } private void checkDriverIsSet() { diff --git a/src/test/java/com/lazerycode/selenium/util/QueryTest.java b/src/test/java/com/lazerycode/selenium/util/QueryTest.java index 695306c..4955bfe 100644 --- a/src/test/java/com/lazerycode/selenium/util/QueryTest.java +++ b/src/test/java/com/lazerycode/selenium/util/QueryTest.java @@ -3,7 +3,6 @@ import io.appium.java_client.MobileElement; import io.appium.java_client.android.AndroidDriver; import io.appium.java_client.remote.MobilePlatform; -import org.junit.After; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.Capabilities; @@ -31,31 +30,31 @@ public class QueryTest { private static final List MOCKED_MOBILE_ELEMENT_LIST_FOR_DEFAULT = Collections.singletonList(MOCKED_MOBILE_ELEMENT_FOR_DEFAULT); @Test(expected = NullPointerException.class) - public void thowsErrorIfInstantiatedWithNull() { - new Query(null); + public void throwsErrorIfDriverIsNull() { + new Query().usingDriver(null); } @Test(expected = IllegalStateException.class) public void throwsIllegalStateExceptionWhenCallingLocatorWithNoInit() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); query.locator(); } @Test(expected = IllegalStateException.class) public void throwsIllegalStateExceptionWhenCallingFindWebElementWithNoInit() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); query.findWebElement(); } @Test(expected = IllegalStateException.class) public void throwsIllegalStateExceptionWhenCallingFindWebElementsWithNoInit() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); query.findWebElements(); } @Test(expected = IllegalStateException.class) public void throwsIllegalStateExceptionWhenCallingFindSelectElementWithNoInit() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); query.findSelectElement(); } @@ -63,7 +62,7 @@ public void throwsIllegalStateExceptionWhenCallingFindSelectElementWithNoInit() public void returnsAValidSelectElement() { when(MOCKED_WEB_ELEMENT_FOR_DEFAULT.getTagName()).thenReturn("select"); - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); Select element = query.findSelectElement(); @@ -73,7 +72,7 @@ public void returnsAValidSelectElement() { @Test public void returnsDefaultLocator() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); assertThat(query.locator()).isEqualTo(DEFAULT_LOCATOR); @@ -82,7 +81,7 @@ public void returnsDefaultLocator() { @Test public void returnsChromeLocatorIfSet() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); query.addAlternateLocator(BrowserType.GOOGLECHROME, CHROME_LOCATOR); @@ -92,7 +91,7 @@ public void returnsChromeLocatorIfSet() { @Test public void returnsDefaultLocatorIfDifferentBrowserIsSet() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); query.addAlternateLocator(BrowserType.FIREFOX, FIREFOX_LOCATOR); @@ -102,7 +101,7 @@ public void returnsDefaultLocatorIfDifferentBrowserIsSet() { @Test public void returnsWebElement() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); WebElement element = query.findWebElement(); @@ -112,7 +111,7 @@ public void returnsWebElement() { @Test public void returnsWebElementList() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); List element = query.findWebElements(); @@ -122,7 +121,7 @@ public void returnsWebElementList() { @Test public void returnsMobileElement() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObjectWithAppiumAndroid(query); MobileElement element = query.findMobileElement(); @@ -132,7 +131,7 @@ public void returnsMobileElement() { @Test public void returnsMobileElementList() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObjectWithAppiumAndroid(query); List element = query.findMobileElements(); @@ -142,7 +141,7 @@ public void returnsMobileElementList() { @Test(expected = UnsupportedOperationException.class) public void findMobileElementThrowsUnsupportedOperationExceptionIfPlatformIsNotAMobileType() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); query.findMobileElement(); } @@ -150,7 +149,7 @@ public void findMobileElementThrowsUnsupportedOperationExceptionIfPlatformIsNotA @Test(expected = UnsupportedOperationException.class) public void findMobileElementThrowsUnsupportedOperationExceptionIfPlatformIsAGenericName() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryObject(query); query.findMobileElement(); } @@ -158,7 +157,7 @@ public void findMobileElementThrowsUnsupportedOperationExceptionIfPlatformIsAGen @Test(expected = UnsupportedOperationException.class) public void findMobileElementsThrowsUnsupportedOperationExceptionIfPlatformIsNotAMobileType() { - Query query = new Query(DEFAULT_LOCATOR); + Query query = new Query().defaultLocator(DEFAULT_LOCATOR); initQueryWithGenericAutomationNameObject(query); query.findMobileElements(); } @@ -173,7 +172,7 @@ private void initQueryObject(Query queryObject) { when(mockedWebDriver.findElement(DEFAULT_LOCATOR)).thenReturn(MOCKED_WEB_ELEMENT_FOR_DEFAULT); when(mockedWebDriver.findElements(DEFAULT_LOCATOR)).thenReturn(MOCKED_WEB_ELEMENT_LIST_FOR_DEFAULT); - queryObject.initQueryObject(mockedWebDriver); + queryObject.usingDriver(mockedWebDriver); } private void initQueryObjectWithAppiumAndroid(Query queryObject) { @@ -187,7 +186,7 @@ private void initQueryObjectWithAppiumAndroid(Query queryObject) { when(mockedWebDriver.findElement(DEFAULT_LOCATOR)).thenReturn(MOCKED_MOBILE_ELEMENT_FOR_DEFAULT); when(mockedWebDriver.findElements(DEFAULT_LOCATOR)).thenReturn(MOCKED_MOBILE_ELEMENT_LIST_FOR_DEFAULT); - queryObject.initQueryObject(mockedWebDriver); + queryObject.usingDriver(mockedWebDriver); } private void initQueryWithGenericAutomationNameObject(Query queryObject) { @@ -201,6 +200,48 @@ private void initQueryWithGenericAutomationNameObject(Query queryObject) { when(mockedWebDriver.findElement(DEFAULT_LOCATOR)).thenReturn(MOCKED_WEB_ELEMENT_FOR_DEFAULT); when(mockedWebDriver.findElements(DEFAULT_LOCATOR)).thenReturn(MOCKED_WEB_ELEMENT_LIST_FOR_DEFAULT); - queryObject.initQueryObject(mockedWebDriver); + queryObject.usingDriver(mockedWebDriver); + } + + @Test(expected = IllegalStateException.class) + public void throwsIllegalStateExceptionIfDefaultLocatorIsNull() { + Capabilities mockedCapabilities = mock(Capabilities.class); + when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME); + when(mockedCapabilities.getPlatform()).thenReturn(Platform.YOSEMITE); + when(mockedCapabilities.getCapability("automationName")).thenReturn("Generic"); + + RemoteWebDriver mockedWebDriver = mock(RemoteWebDriver.class); + when(mockedWebDriver.getCapabilities()).thenReturn(mockedCapabilities); + + Query query = new Query().usingDriver(mockedWebDriver); + query.locator(); + } + + @Test(expected = IllegalStateException.class) + public void throwsIllegalStateExceptionIfDefaultLocatorIsNullAndCurrentTypeDoesNotMatch() { + Capabilities mockedCapabilities = mock(Capabilities.class); + when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME); + when(mockedCapabilities.getPlatform()).thenReturn(Platform.YOSEMITE); + when(mockedCapabilities.getCapability("automationName")).thenReturn("Generic"); + + RemoteWebDriver mockedWebDriver = mock(RemoteWebDriver.class); + when(mockedWebDriver.getCapabilities()).thenReturn(mockedCapabilities); + + Query query = new Query().addAlternateLocator(BrowserType.FIREFOX, FIREFOX_LOCATOR).usingDriver(mockedWebDriver); + query.locator(); + } + + @Test + public void doesNotThrowIllegalStateExceptionIfDefaultLocatorIsNullAndCurrentTypeDoesMatch() { + Capabilities mockedCapabilities = mock(Capabilities.class); + when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME); + when(mockedCapabilities.getPlatform()).thenReturn(Platform.YOSEMITE); + when(mockedCapabilities.getCapability("automationName")).thenReturn("Generic"); + + RemoteWebDriver mockedWebDriver = mock(RemoteWebDriver.class); + when(mockedWebDriver.getCapabilities()).thenReturn(mockedCapabilities); + + Query query = new Query().addAlternateLocator(BrowserType.GOOGLECHROME, CHROME_LOCATOR).usingDriver(mockedWebDriver); + query.locator(); } }