Skip to content

Commit

Permalink
Add ability to bulk apply a driver object to all Query objects in a c…
Browse files Browse the repository at this point in the history
…lass
  • Loading branch information
Ardesco committed Nov 11, 2018
1 parent 5e59518 commit ff58e4d
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 31 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ Do you want to have different locators for different browsers? You can add over
query.addAlternateLocator(BrowserType.GOOGLECHROME, By.id("bar")
.addAlternateLocator("custom_driver", By.id("custom");

Once you have set custom locators the query object will check the desired capabilities of the current instantiated driver and just use the appropriate locator
Once you have set custom locators the query object will check the desired capabilities of the current instantiated driver and just use the appropriate locator

## Setting a driver object for every Query object is a real PITA, isn't there an easier way?

Instead of passing a `.usingDriver(driver)` command to each driver object you can instead put the following code into your constructor:

initQueryObjects(this, driver);

This will scan the current class for valid Query objects and then assign the supplied driver object to each Query object. This does need to be an instantiated driver object, passing in a null will result in an error. You can then of course still modify the driver object assigned to a Query object at any point in the future using the `.usingDriver(driver)` command on individual Query objects.

## OK, I have a query object. Now what?

Expand All @@ -55,6 +63,6 @@ Ok, that's kind of useful, anything else?
Have you ever got frustrated trying to get locators out of element to use in expected conditions? No longer a problem:

WebDriverWait wait = new WebDriverWait(driver, 15, 100);
wait.until(ExpectedConditions.visibilityOfElementLocated(query.locator));
wait.until(ExpectedConditions.visibilityOfElementLocated(query.by()));

That's all for now, if you can think of any useful additions just raise an issue.
27 changes: 27 additions & 0 deletions src/main/java/com/lazerycode/selenium/util/AssignDriver.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.lazerycode.selenium.util;

import org.openqa.selenium.remote.RemoteWebDriver;

import java.lang.reflect.Field;

public class AssignDriver {
public static void initQueryObjects(Object object, RemoteWebDriver driver) {
Class<?> clazz = object.getClass();
// Object obj = null;
try {
// obj = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getType() == Query.class) {
field.setAccessible(true);
Query queryObject = (Query) field.get(object);
if (null != queryObject) {
queryObject.usingDriver(driver);
}
}
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
52 changes: 36 additions & 16 deletions src/main/java/com/lazerycode/selenium/util/Query.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;

Expand All @@ -21,7 +22,7 @@ public class Query {
private boolean isAppiumDriver;

/**
* Specify a default locator that will be used if a more specific locator cannot be detected.
* Specify a default by that will be used if a more specific by cannot be detected.
*
* @param locator
* @return this
Expand All @@ -33,10 +34,10 @@ public Query defaultLocator(By locator) {
}

/**
* Specify a alternate locator for a specific browser.
* Specify a alternate by for a specific browser.
* <p>
* 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.
* if it matches what you have specified here this by will be used instead.
* The browserName check is case insensitive!
* <p>
* It is Suggested you pass in a org.openqa.selenium.remote.BrowserType object to ensure accuracy
Expand Down Expand Up @@ -83,43 +84,43 @@ public Query usingDriver(RemoteWebDriver driverObject) {
}

/**
* This will return a WebElement object if the supplied locator could find a valid WebElement.
* This will return a WebElement object if the supplied by could find a valid WebElement.
*
* @return WebElement
*/
public WebElement findWebElement() {
return driver.findElement(locator());
return driver.findElement(by());
}

/**
* This will return a MobileElement object if the supplied locator could find a valid MobileElement.
* This will return a MobileElement object if the supplied by could find a valid MobileElement.
*
* @return MobileElement
*/
public MobileElement findMobileElement() {
if (isAppiumDriver) {
return (MobileElement) driver.findElement(locator());
return (MobileElement) driver.findElement(by());
}
throw new UnsupportedOperationException("You don't seem to be using Appium!");
}

/**
* This will return a list of WebElement objects, it may be empty if the supplied locator does not match any elements on screen
* This will return a list of WebElement objects, it may be empty if the supplied by does not match any elements on screen
*
* @return List&lt;WebElement>&gt;
*/
public List<WebElement> findWebElements() {
return driver.findElements(locator());
return driver.findElements(by());
}

/**
* This will return a list of MobileElement objects, it may be empty if the supplied locator does not match any elements on screen
* This will return a list of MobileElement objects, it may be empty if the supplied by does not match any elements on screen
*
* @return List&lt;MobileElement>&gt;
*/
public List<MobileElement> findMobileElements() {
if (isAppiumDriver) {
List<WebElement> elementsFound = driver.findElements(locator());
List<WebElement> elementsFound = driver.findElements(by());
List<MobileElement> mobileElementsToReturn = new ArrayList<>();
for (WebElement element : elementsFound) {
mobileElementsToReturn.add((MobileElement) element);
Expand All @@ -130,7 +131,7 @@ public List<MobileElement> findMobileElements() {
}

/**
* This will return a Select object if the supplied locator could find a valid WebElement.
* This will return a Select object if the supplied by could find a valid WebElement.
*
* @return Select
*/
Expand All @@ -139,12 +140,12 @@ public Select findSelectElement() {
}

/**
* This will return the locator currently associated with your driver object.
* This will return the by currently associated with your driver object.
* This is useful for passing into ExpectedConditions
*
* @return By
*/
public By locator() {
public By by() {
checkDriverIsSet();
By locatorToReturn = customLocators.getOrDefault(currentType.toUpperCase(), defaultLocator);

Expand All @@ -153,15 +154,34 @@ public By locator() {

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));
throw new IllegalStateException(String.format("Unable to detect valid by for '%s' and a default by has not been set!", currentType));
}

return locator;
}

private void checkDriverIsSet() {
boolean checkDriverIsSet() {
if (null == driver) {
throw new IllegalStateException("Driver object has not been set... You must call 'Query.initQueryObject(driver);'!");
}

return true;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Query query = (Query) o;
return isAppiumDriver == query.isAppiumDriver &&
Objects.equals(driver, query.driver) &&
Objects.equals(currentType, query.currentType) &&
Objects.equals(defaultLocator, query.defaultLocator) &&
Objects.equals(customLocators, query.customLocators);
}

@Override
public int hashCode() {
return Objects.hash(driver, currentType, defaultLocator, customLocators, isAppiumDriver);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.lazerycode.selenium.util;

import io.appium.java_client.AppiumDriver;
import io.appium.java_client.remote.MobilePlatform;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Platform;

import static com.lazerycode.selenium.util.AssignDriver.initQueryObjects;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;

public class AssignAppiumDriverTest {
private static final AppiumDriver MOCKED_APPIUM_DRIVER = mock(AppiumDriver.class);

private Query valid = new Query().defaultLocator(By.id("foo"));
private Query empty;

public AssignAppiumDriverTest() {
Capabilities mockedCapabilities = mock(Capabilities.class);
when(mockedCapabilities.getBrowserName()).thenReturn("");
when(mockedCapabilities.getCapability(PLATFORM_NAME)).thenReturn(Platform.fromString(MobilePlatform.ANDROID));
when(mockedCapabilities.getCapability("automationName")).thenReturn("Appium");
when(MOCKED_APPIUM_DRIVER.getCapabilities()).thenReturn(mockedCapabilities);

initQueryObjects(this, MOCKED_APPIUM_DRIVER);
}

@Test
public void something() {
assertThat(empty).isNull();
assertThat(valid.checkDriverIsSet()).isTrue();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.lazerycode.selenium.util;

import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.Platform;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.BrowserType;
import org.openqa.selenium.remote.RemoteWebDriver;

import static com.lazerycode.selenium.util.AssignDriver.initQueryObjects;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.openqa.selenium.remote.CapabilityType.PLATFORM_NAME;

public class AssignRemoteWebDriverTest {
private static final RemoteWebDriver MOCKED_CHROME_DRIVER = mock(ChromeDriver.class);

private Query valid = new Query().defaultLocator(By.id("foo"));
private Query empty;

public AssignRemoteWebDriverTest() {
Capabilities mockedCapabilities = mock(Capabilities.class);
when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME);
when(mockedCapabilities.getCapability(PLATFORM_NAME)).thenReturn(Platform.YOSEMITE);
when(MOCKED_CHROME_DRIVER.getCapabilities()).thenReturn(mockedCapabilities);

initQueryObjects(this, MOCKED_CHROME_DRIVER);
}

@Test
public void something() {
assertThat(empty).isNull();
assertThat(valid.checkDriverIsSet()).isTrue();
}
}
26 changes: 13 additions & 13 deletions src/test/java/com/lazerycode/selenium/util/QueryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void throwsErrorIfDriverIsNull() {
@Test(expected = IllegalStateException.class)
public void throwsIllegalStateExceptionWhenCallingLocatorWithNoInit() {
Query query = new Query().defaultLocator(DEFAULT_LOCATOR);
query.locator();
query.by();
}

@Test(expected = IllegalStateException.class)
Expand Down Expand Up @@ -76,7 +76,7 @@ public void returnsDefaultLocator() {
Query query = new Query().defaultLocator(DEFAULT_LOCATOR);
initQueryObject(query);

assertThat(query.locator()).isEqualTo(DEFAULT_LOCATOR);
assertThat(query.by()).isEqualTo(DEFAULT_LOCATOR);
}

@Test
Expand All @@ -86,7 +86,7 @@ public void returnsChromeLocatorIfSet() {
initQueryObject(query);
query.addSpecificLocator(BrowserType.GOOGLECHROME, CHROME_LOCATOR);

assertThat(query.locator()).isEqualTo(CHROME_LOCATOR);
assertThat(query.by()).isEqualTo(CHROME_LOCATOR);
}

@Test
Expand All @@ -96,7 +96,7 @@ public void checkAlternateLocatorIsCaseInsensitiveWithUpper() {
initQueryObject(query);
query.addSpecificLocator(BrowserType.GOOGLECHROME.toUpperCase(), CHROME_LOCATOR);

assertThat(query.locator()).isEqualTo(CHROME_LOCATOR);
assertThat(query.by()).isEqualTo(CHROME_LOCATOR);
}

@Test
Expand All @@ -106,7 +106,7 @@ public void checkAlternateLocatorIsCaseInsensitiveWithLower() {
initQueryObject(query);
query.addSpecificLocator(BrowserType.GOOGLECHROME.toLowerCase(), CHROME_LOCATOR);

assertThat(query.locator()).isEqualTo(CHROME_LOCATOR);
assertThat(query.by()).isEqualTo(CHROME_LOCATOR);
}

@Test
Expand All @@ -116,7 +116,7 @@ public void returnsDefaultLocatorIfDifferentBrowserIsSet() {
initQueryObject(query);
query.addSpecificLocator(BrowserType.FIREFOX, FIREFOX_LOCATOR);

assertThat(query.locator()).isEqualTo(DEFAULT_LOCATOR);
assertThat(query.by()).isEqualTo(DEFAULT_LOCATOR);
}

@Test
Expand Down Expand Up @@ -186,7 +186,7 @@ public void findMobileElementsThrowsUnsupportedOperationExceptionIfPlatformIsNot
private void initQueryObject(Query queryObject) {
Capabilities mockedCapabilities = mock(Capabilities.class);
when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME);
when(mockedCapabilities.getPlatform()).thenReturn(Platform.YOSEMITE);
when(mockedCapabilities.getCapability(PLATFORM_NAME)).thenReturn(Platform.YOSEMITE);

RemoteWebDriver mockedWebDriver = mock(RemoteWebDriver.class);
when(mockedWebDriver.getCapabilities()).thenReturn(mockedCapabilities);
Expand Down Expand Up @@ -228,41 +228,41 @@ private void initQueryWithGenericAutomationNameObject(Query queryObject) {
public void throwsIllegalStateExceptionIfDefaultLocatorIsNull() {
Capabilities mockedCapabilities = mock(Capabilities.class);
when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME);
when(mockedCapabilities.getPlatform()).thenReturn(Platform.YOSEMITE);
when(mockedCapabilities.getCapability(PLATFORM_NAME)).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();
query.by();
}

@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(PLATFORM_NAME)).thenReturn(Platform.YOSEMITE);
when(mockedCapabilities.getCapability("automationName")).thenReturn("Generic");

RemoteWebDriver mockedWebDriver = mock(RemoteWebDriver.class);
when(mockedWebDriver.getCapabilities()).thenReturn(mockedCapabilities);

Query query = new Query().addSpecificLocator(BrowserType.FIREFOX, FIREFOX_LOCATOR).usingDriver(mockedWebDriver);
query.locator();
query.by();
}

@Test
public void doesNotThrowIllegalStateExceptionIfDefaultLocatorIsNullAndCurrentTypeDoesMatch() {
Capabilities mockedCapabilities = mock(Capabilities.class);
when(mockedCapabilities.getBrowserName()).thenReturn(BrowserType.GOOGLECHROME);
when(mockedCapabilities.getPlatform()).thenReturn(Platform.YOSEMITE);
when(mockedCapabilities.getCapability(PLATFORM_NAME)).thenReturn(Platform.YOSEMITE);
when(mockedCapabilities.getCapability("automationName")).thenReturn("Generic");

RemoteWebDriver mockedWebDriver = mock(RemoteWebDriver.class);
when(mockedWebDriver.getCapabilities()).thenReturn(mockedCapabilities);

Query query = new Query().addSpecificLocator(BrowserType.GOOGLECHROME, CHROME_LOCATOR).usingDriver(mockedWebDriver);
query.locator();
query.by();
}
}

0 comments on commit ff58e4d

Please sign in to comment.