Skip to content

Commit e211217

Browse files
authored
Merge pull request #40 from Frameworkium/feature/angular2
Support for Angular 2 & JS Frameworks
2 parents c5b2daf + 6419682 commit e211217

File tree

8 files changed

+178
-27
lines changed

8 files changed

+178
-27
lines changed

src/main/java/com/frameworkium/core/ui/ExtraExpectedConditions.java

100644100755
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,17 @@ public static ExpectedCondition<List<? extends WebElement>> sizeLessThan(
102102
: null;
103103
}
104104

105+
/**
106+
* Wait for the document ready state to equal 'complete'.
107+
* Useful for javascript loading on page-load.
108+
*
109+
* @return a {@link ExpectedCondition} which returns <strong>false</strong> if the document
110+
* isn't ready, and <string>true</string> if the document is ready
111+
*/
112+
public static ExpectedCondition<Boolean> documentBodyReady() {
113+
114+
return driver ->
115+
(Boolean) ((JavascriptExecutor) driver)
116+
.executeScript("return document.readyState == 'complete';");
117+
}
105118
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.frameworkium.core.ui.js;
2+
3+
import org.openqa.selenium.JavascriptExecutor;
4+
5+
public interface AbstractFramework {
6+
7+
/** {@inheritDoc} **/
8+
boolean isPresent(JavascriptExecutor javascriptExecutor);
9+
10+
/** {@inheritDoc} **/
11+
void waitToBeReady(JavascriptExecutor javascriptExecutor);
12+
13+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.frameworkium.core.ui.js;
2+
3+
import com.frameworkium.core.ui.ExtraExpectedConditions;
4+
import com.frameworkium.core.ui.js.framework.Angular;
5+
import com.frameworkium.core.ui.js.framework.AngularTwo;
6+
import org.openqa.selenium.JavascriptExecutor;
7+
import org.openqa.selenium.WebDriver;
8+
import org.openqa.selenium.support.ui.Wait;
9+
10+
import java.util.Arrays;
11+
12+
/**
13+
* Frameworkium implementation of waiting for JS events on page-load
14+
*/
15+
public class JavascriptWait {
16+
17+
private final Wait<WebDriver> wait;
18+
private final JavascriptExecutor javascriptExecutor;
19+
20+
private SupportedFramework detectedFramework;
21+
22+
public JavascriptWait(WebDriver driver, Wait<WebDriver> wait) {
23+
this.wait = wait;
24+
this.javascriptExecutor = (JavascriptExecutor) driver;
25+
}
26+
27+
/**
28+
* Default entry to {@link JavascriptWait}
29+
*
30+
* Following actions are waited on:
31+
* <ul>
32+
* <li>Document state to be ready</li>
33+
* <li>If page is using a supported JS framework, it will detect & wait</li>
34+
* </ul>
35+
*/
36+
public void waitForJavascriptEventsOnLoad() {
37+
waitForDocumentReady();
38+
detectFramework();
39+
waitForJavascriptFramework();
40+
}
41+
42+
/**
43+
* If a page is using a supported JS framework, it will wait until it's ready
44+
*/
45+
public void waitForJavascriptFramework() {
46+
if (detectedFramework != null) getFrameworkClass(detectedFramework).waitToBeReady(javascriptExecutor);
47+
}
48+
49+
private void waitForDocumentReady() {
50+
wait.until(ExtraExpectedConditions.documentBodyReady());
51+
}
52+
53+
private void detectFramework() {
54+
detectedFramework = Arrays.stream(SupportedFramework.values())
55+
.filter(supportedFramework -> getFrameworkClass(supportedFramework).isPresent(javascriptExecutor))
56+
.findFirst()
57+
.orElse(null);
58+
}
59+
60+
private AbstractFramework getFrameworkClass(SupportedFramework supportedFramework) {
61+
try {
62+
return ((AbstractFramework) supportedFramework.getFrameworkClass().newInstance());
63+
} catch (InstantiationException | IllegalAccessException e) {
64+
throw new RuntimeException(e.toString());
65+
}
66+
}
67+
68+
/**
69+
* Supported JS Frameworks within Frameworkium and their class which implement {@link AbstractFramework}
70+
*/
71+
private enum SupportedFramework {
72+
ANGULAR(Angular.class),
73+
ANGULAR_TWO(AngularTwo.class);
74+
75+
private Class frameworkClass;
76+
77+
SupportedFramework(Class<? extends AbstractFramework> frameworkClass) {
78+
this.frameworkClass = frameworkClass;
79+
}
80+
81+
public Class getFrameworkClass() {
82+
return this.frameworkClass;
83+
}
84+
}
85+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.frameworkium.core.ui.js.framework;
2+
3+
import com.frameworkium.core.ui.js.AbstractFramework;
4+
import com.paulhammant.ngwebdriver.NgWebDriver;
5+
import org.openqa.selenium.JavascriptExecutor;
6+
7+
public class Angular implements AbstractFramework {
8+
9+
@Override
10+
public boolean isPresent(JavascriptExecutor javascriptExecutor) {
11+
return (Boolean) javascriptExecutor.executeScript("return typeof angular == 'object';");
12+
}
13+
14+
@Override
15+
public void waitToBeReady(JavascriptExecutor javascriptExecutor) {
16+
new NgWebDriver(javascriptExecutor).waitForAngularRequestsToFinish();
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.frameworkium.core.ui.js.framework;
2+
3+
import com.frameworkium.core.ui.js.AbstractFramework;
4+
import com.paulhammant.ngwebdriver.NgWebDriver;
5+
import org.openqa.selenium.JavascriptExecutor;
6+
7+
public class AngularTwo implements AbstractFramework {
8+
9+
@Override
10+
public boolean isPresent(JavascriptExecutor javascriptExecutor) {
11+
return (Boolean) javascriptExecutor.executeScript("return typeof ng == 'object';");
12+
}
13+
14+
@Override
15+
public void waitToBeReady(JavascriptExecutor javascriptExecutor) {
16+
new NgWebDriver(javascriptExecutor).waitForAngular2RequestsToFinish();
17+
}
18+
}

src/main/java/com/frameworkium/core/ui/pages/BasePage.java

100644100755
Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,30 @@
44
import com.frameworkium.core.common.reporting.allure.AllureLogger;
55
import com.frameworkium.core.ui.annotations.Visible;
66
import com.frameworkium.core.ui.capture.model.Command;
7+
import com.frameworkium.core.ui.js.JavascriptWait;
78
import com.frameworkium.core.ui.tests.BaseTest;
8-
import com.paulhammant.ngwebdriver.NgWebDriver;
99
import org.apache.logging.log4j.LogManager;
1010
import org.apache.logging.log4j.Logger;
1111
import org.openqa.selenium.JavascriptExecutor;
1212
import org.openqa.selenium.WebDriver;
1313
import org.openqa.selenium.support.ui.Wait;
1414
import ru.yandex.qatools.htmlelements.loader.HtmlElementLoader;
1515

16-
import java.util.Objects;
17-
1816
public abstract class BasePage<T extends BasePage<T>> {
1917

2018
protected final Logger logger = LogManager.getLogger(this);
2119
protected final WebDriver driver;
2220
protected Wait<WebDriver> wait;
2321
/** Visibility with current page wait and driver */
2422
protected Visibility visibility;
25-
26-
private NgWebDriver ngDriver;
23+
protected JavascriptWait javascriptWait;
2724

2825
/** Constructor, initialises all things useful. */
2926
public BasePage() {
3027
driver = BaseTest.getDriver();
3128
wait = BaseTest.getWait();
3229
visibility = new Visibility(wait, BaseTest.getDriver());
33-
ngDriver = new NgWebDriver(BaseTest.getDriver());
30+
javascriptWait = new JavascriptWait(driver, wait);
3431
}
3532

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

100+
//Populate Page Object
103101
HtmlElementLoader.populatePageObject(this, driver);
104102

105-
// wait for page to load
106-
if (isPageAngularJS()) {
107-
waitForAngularRequestsToFinish();
108-
}
103+
//Wait for Elements & JS
109104
visibility.waitForAnnotatedElementVisibility(this);
105+
javascriptWait.waitForJavascriptEventsOnLoad();
110106

111-
// log page load
107+
//Log
112108
takePageLoadedScreenshotAndSendToCapture();
113109
logPageLoadToAllure();
114110

@@ -135,8 +131,11 @@ private void takePageLoadedScreenshotAndSendToCapture() {
135131
}
136132
}
137133

138-
private boolean isPageAngularJS() {
139-
return Objects.equals(executeJS("return typeof angular;"), "object");
134+
/**
135+
* Waits for all JS framework requests to finish on page
136+
*/
137+
protected void waitForJavascriptFrameworkToFinish() {
138+
javascriptWait.waitForJavascriptFramework();
140139
}
141140

142141
/**
@@ -181,11 +180,6 @@ protected Object executeAsyncJS(String javascript) {
181180
return returnObj;
182181
}
183182

184-
/** Method to wait for AngularJS requests to finish on the page */
185-
protected void waitForAngularRequestsToFinish() {
186-
ngDriver.waitForAngularRequestsToFinish();
187-
}
188-
189183
/** @return Returns the title of the web page */
190184
public String getTitle() {
191185
return driver.getTitle();

src/main/java/com/frameworkium/core/ui/tests/BaseTest.java

100644100755
Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
11
package com.frameworkium.core.ui.tests;
22

3-
import com.frameworkium.core.common.listeners.*;
3+
import com.frameworkium.core.common.listeners.MethodInterceptor;
4+
import com.frameworkium.core.common.listeners.ResultLoggerListener;
5+
import com.frameworkium.core.common.listeners.TestListener;
46
import com.frameworkium.core.common.reporting.TestIdUtils;
57
import com.frameworkium.core.common.reporting.allure.AllureLogger;
68
import com.frameworkium.core.common.reporting.allure.AllureProperties;
79
import com.frameworkium.core.ui.capture.ScreenshotCapture;
8-
import com.frameworkium.core.ui.driver.*;
9-
import com.frameworkium.core.ui.listeners.*;
10+
import com.frameworkium.core.ui.driver.Driver;
11+
import com.frameworkium.core.ui.driver.DriverSetup;
12+
import com.frameworkium.core.ui.driver.WebDriverWrapper;
13+
import com.frameworkium.core.ui.listeners.CaptureListener;
14+
import com.frameworkium.core.ui.listeners.SauceLabsListener;
15+
import com.frameworkium.core.ui.listeners.ScreenshotListener;
1016
import com.saucelabs.common.SauceOnDemandAuthentication;
1117
import com.saucelabs.common.SauceOnDemandSessionIdProvider;
1218
import com.saucelabs.testng.SauceOnDemandAuthenticationProvider;
1319
import org.apache.commons.lang.StringUtils;
1420
import org.apache.logging.log4j.LogManager;
1521
import org.apache.logging.log4j.Logger;
1622
import org.openqa.selenium.NoSuchElementException;
17-
import org.openqa.selenium.*;
23+
import org.openqa.selenium.StaleElementReferenceException;
24+
import org.openqa.selenium.WebDriver;
1825
import org.openqa.selenium.remote.SessionId;
1926
import org.openqa.selenium.support.ui.FluentWait;
2027
import org.openqa.selenium.support.ui.Wait;
2128
import org.testng.annotations.*;
2229

2330
import java.lang.reflect.Method;
24-
import java.util.*;
31+
import java.util.ArrayList;
32+
import java.util.Collections;
33+
import java.util.List;
2534
import java.util.Optional;
26-
import java.util.concurrent.*;
35+
import java.util.concurrent.ExecutorService;
36+
import java.util.concurrent.Executors;
37+
import java.util.concurrent.TimeUnit;
2738

2839
import static java.util.Objects.isNull;
2940

@@ -166,7 +177,6 @@ public static WebDriverWrapper getDriver() {
166177
return driver.get().getDriver();
167178
}
168179

169-
170180
/** Loops through all active driver types and tears them down */
171181
@AfterSuite(alwaysRun = true)
172182
public static void tearDownRemainingDrivers() {

src/test/java/com/frameworkium/integration/angularjs/pages/web/DeveloperGuidePage.java

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public DeveloperGuidePage searchDeveloperGuide(String inputText) {
3636

3737
public DeveloperGuidePage clickBootstrapSearchItem() {
3838
bootstrapSearchItem.click();
39-
waitForAngularRequestsToFinish();
39+
waitForJavascriptFrameworkToFinish();
4040
return this;
4141
}
4242

0 commit comments

Comments
 (0)