Skip to content

Commit

Permalink
Completed & tested implementation of JS frameworks with support for A…
Browse files Browse the repository at this point in the history
…ngular & Angular 2
  • Loading branch information
Huxtable, Jonny (UK Leeds) committed Jul 27, 2016
1 parent d25195a commit 6419682
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 27 deletions.
13 changes: 13 additions & 0 deletions src/main/java/com/frameworkium/core/ui/ExtraExpectedConditions.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,17 @@ public static ExpectedCondition<List<? extends WebElement>> sizeLessThan(
: null;
}

/**
* Wait for the document ready state to equal 'complete'.
* Useful for javascript loading on page-load.
*
* @return a {@link ExpectedCondition} which returns <strong>false</strong> if the document
* isn't ready, and <string>true</string> if the document is ready
*/
public static ExpectedCondition<Boolean> documentBodyReady() {

return driver ->
(Boolean) ((JavascriptExecutor) driver)
.executeScript("return document.readyState == 'complete';");
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/frameworkium/core/ui/js/AbstractFramework.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.frameworkium.core.ui.js;

import org.openqa.selenium.JavascriptExecutor;

public interface AbstractFramework {

/** {@inheritDoc} **/
boolean isPresent(JavascriptExecutor javascriptExecutor);

/** {@inheritDoc} **/
void waitToBeReady(JavascriptExecutor javascriptExecutor);

}
85 changes: 85 additions & 0 deletions src/main/java/com/frameworkium/core/ui/js/JavascriptWait.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.frameworkium.core.ui.js;

import com.frameworkium.core.ui.ExtraExpectedConditions;
import com.frameworkium.core.ui.js.framework.Angular;
import com.frameworkium.core.ui.js.framework.AngularTwo;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.Wait;

import java.util.Arrays;

/**
* Frameworkium implementation of waiting for JS events on page-load
*/
public class JavascriptWait {

private final Wait<WebDriver> wait;
private final JavascriptExecutor javascriptExecutor;

private SupportedFramework detectedFramework;

public JavascriptWait(WebDriver driver, Wait<WebDriver> wait) {
this.wait = wait;
this.javascriptExecutor = (JavascriptExecutor) driver;
}

/**
* Default entry to {@link JavascriptWait}
*
* Following actions are waited on:
* <ul>
* <li>Document state to be ready</li>
* <li>If page is using a supported JS framework, it will detect & wait</li>
* </ul>
*/
public void waitForJavascriptEventsOnLoad() {
waitForDocumentReady();
detectFramework();
waitForJavascriptFramework();
}

/**
* If a page is using a supported JS framework, it will wait until it's ready
*/
public void waitForJavascriptFramework() {
if (detectedFramework != null) getFrameworkClass(detectedFramework).waitToBeReady(javascriptExecutor);
}

private void waitForDocumentReady() {
wait.until(ExtraExpectedConditions.documentBodyReady());
}

private void detectFramework() {
detectedFramework = Arrays.stream(SupportedFramework.values())
.filter(supportedFramework -> getFrameworkClass(supportedFramework).isPresent(javascriptExecutor))
.findFirst()
.orElse(null);
}

private AbstractFramework getFrameworkClass(SupportedFramework supportedFramework) {
try {
return ((AbstractFramework) supportedFramework.getFrameworkClass().newInstance());
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e.toString());
}
}

/**
* Supported JS Frameworks within Frameworkium and their class which implement {@link AbstractFramework}
*/
private enum SupportedFramework {
ANGULAR(Angular.class),
ANGULAR_TWO(AngularTwo.class);

private Class frameworkClass;

SupportedFramework(Class<? extends AbstractFramework> frameworkClass) {
this.frameworkClass = frameworkClass;
}

public Class getFrameworkClass() {
return this.frameworkClass;
}
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/frameworkium/core/ui/js/framework/Angular.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.frameworkium.core.ui.js.framework;

import com.frameworkium.core.ui.js.AbstractFramework;
import com.paulhammant.ngwebdriver.NgWebDriver;
import org.openqa.selenium.JavascriptExecutor;

public class Angular implements AbstractFramework {

@Override
public boolean isPresent(JavascriptExecutor javascriptExecutor) {
return (Boolean) javascriptExecutor.executeScript("return typeof angular == 'object';");
}

@Override
public void waitToBeReady(JavascriptExecutor javascriptExecutor) {
new NgWebDriver(javascriptExecutor).waitForAngularRequestsToFinish();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.frameworkium.core.ui.js.framework;

import com.frameworkium.core.ui.js.AbstractFramework;
import com.paulhammant.ngwebdriver.NgWebDriver;
import org.openqa.selenium.JavascriptExecutor;

public class AngularTwo implements AbstractFramework {

@Override
public boolean isPresent(JavascriptExecutor javascriptExecutor) {
return (Boolean) javascriptExecutor.executeScript("return typeof ng == 'object';");
}

@Override
public void waitToBeReady(JavascriptExecutor javascriptExecutor) {
new NgWebDriver(javascriptExecutor).waitForAngular2RequestsToFinish();
}
}
32 changes: 13 additions & 19 deletions src/main/java/com/frameworkium/core/ui/pages/BasePage.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,30 @@
import com.frameworkium.core.common.reporting.allure.AllureLogger;
import com.frameworkium.core.ui.annotations.Visible;
import com.frameworkium.core.ui.capture.model.Command;
import com.frameworkium.core.ui.js.JavascriptWait;
import com.frameworkium.core.ui.tests.BaseTest;
import com.paulhammant.ngwebdriver.NgWebDriver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.Wait;
import ru.yandex.qatools.htmlelements.loader.HtmlElementLoader;

import java.util.Objects;

public abstract class BasePage<T extends BasePage<T>> {

protected final Logger logger = LogManager.getLogger(this);
protected final WebDriver driver;
protected Wait<WebDriver> wait;
/** Visibility with current page wait and driver */
protected Visibility visibility;

private NgWebDriver ngDriver;
protected JavascriptWait javascriptWait;

/** Constructor, initialises all things useful. */
public BasePage() {
driver = BaseTest.getDriver();
wait = BaseTest.getWait();
visibility = new Visibility(wait, BaseTest.getDriver());
ngDriver = new NgWebDriver(BaseTest.getDriver());
javascriptWait = new JavascriptWait(driver, wait);
}

/**
Expand Down Expand Up @@ -89,7 +86,7 @@ public T get(long timeout) {
* <p>
* <ul>
* <li>Initialises fields with lazy proxies</li>
* <li>Waits for AngularJS requests to finish loading, if present</li>
* <li>Waits for Javascript events including document ready & JS frameworks (if applicable)</li>
* <li>Processes Frameworkium visibility annotations e.g. {@link Visible}</li>
* <li>Log page load to Allure and Capture</li>
* </ul>
Expand All @@ -100,15 +97,14 @@ public T get(long timeout) {
@SuppressWarnings("unchecked")
public T get() {

//Populate Page Object
HtmlElementLoader.populatePageObject(this, driver);

// wait for page to load
if (isPageAngularJS()) {
waitForAngularRequestsToFinish();
}
//Wait for Elements & JS
visibility.waitForAnnotatedElementVisibility(this);
javascriptWait.waitForJavascriptEventsOnLoad();

// log page load
//Log
takePageLoadedScreenshotAndSendToCapture();
logPageLoadToAllure();

Expand All @@ -135,8 +131,11 @@ private void takePageLoadedScreenshotAndSendToCapture() {
}
}

private boolean isPageAngularJS() {
return Objects.equals(executeJS("return typeof angular;"), "object");
/**
* Waits for all JS framework requests to finish on page
*/
protected void waitForJavascriptFrameworkToFinish() {
javascriptWait.waitForJavascriptFramework();
}

/**
Expand Down Expand Up @@ -181,11 +180,6 @@ protected Object executeAsyncJS(String javascript) {
return returnObj;
}

/** Method to wait for AngularJS requests to finish on the page */
protected void waitForAngularRequestsToFinish() {
ngDriver.waitForAngularRequestsToFinish();
}

/** @return Returns the title of the web page */
public String getTitle() {
return driver.getTitle();
Expand Down
24 changes: 17 additions & 7 deletions src/main/java/com/frameworkium/core/ui/tests/BaseTest.java
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
package com.frameworkium.core.ui.tests;

import com.frameworkium.core.common.listeners.*;
import com.frameworkium.core.common.listeners.MethodInterceptor;
import com.frameworkium.core.common.listeners.ResultLoggerListener;
import com.frameworkium.core.common.listeners.TestListener;
import com.frameworkium.core.common.reporting.TestIdUtils;
import com.frameworkium.core.common.reporting.allure.AllureLogger;
import com.frameworkium.core.common.reporting.allure.AllureProperties;
import com.frameworkium.core.ui.capture.ScreenshotCapture;
import com.frameworkium.core.ui.driver.*;
import com.frameworkium.core.ui.listeners.*;
import com.frameworkium.core.ui.driver.Driver;
import com.frameworkium.core.ui.driver.DriverSetup;
import com.frameworkium.core.ui.driver.WebDriverWrapper;
import com.frameworkium.core.ui.listeners.CaptureListener;
import com.frameworkium.core.ui.listeners.SauceLabsListener;
import com.frameworkium.core.ui.listeners.ScreenshotListener;
import com.saucelabs.common.SauceOnDemandAuthentication;
import com.saucelabs.common.SauceOnDemandSessionIdProvider;
import com.saucelabs.testng.SauceOnDemandAuthenticationProvider;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.*;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.testng.annotations.*;

import java.lang.reflect.Method;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static java.util.Objects.isNull;

Expand Down Expand Up @@ -166,7 +177,6 @@ public static WebDriverWrapper getDriver() {
return driver.get().getDriver();
}


/** Loops through all active driver types and tears them down */
@AfterSuite(alwaysRun = true)
public static void tearDownRemainingDrivers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public DeveloperGuidePage searchDeveloperGuide(String inputText) {

public DeveloperGuidePage clickBootstrapSearchItem() {
bootstrapSearchItem.click();
waitForAngularRequestsToFinish();
waitForJavascriptFrameworkToFinish();
return this;
}

Expand Down

0 comments on commit 6419682

Please sign in to comment.